Custom Media Storage
Custom Media Storage
By default, multimedia tools (image generation, video generation, TTS, STT) save outputs to the local filesystem via FileMediaStorage. You can plug in custom storage backends (S3, GCS, Azure Blob, etc.) by implementing the IMediaStorage interface.
The IMediaStorage Interface
import type { MediaStorageMetadata, MediaStorageResult, MediaStorageListOptions, MediaStorageEntry } from 'oneringai';
// Interface sketch; import IMediaStorage when implementing a backend.
interface IMediaStorage {
save(data: Buffer, metadata: MediaStorageMetadata): Promise<MediaStorageResult>;
read(location: string): Promise<Buffer | null>;
delete(location: string): Promise<void>;
exists(location: string): Promise<boolean>;
list?(options?: MediaStorageListOptions): Promise<MediaStorageEntry[]>; // optional
getPath(): string;
}
MediaStorageMetadata describes the media being saved:
type:'image' | 'video' | 'audio'format: file extension (e.g.,'png','mp4','mp3')model: model name used for generationvendor: vendor that produced the outputindex?: index for multi-image resultssuggestedFilename?: optional filename hint
MediaStorageResult returned by save():
location: where the file was stored (path, URL, S3 key, etc.)mimeType: MIME type of the saved filesize: file size in bytes
Custom S3 Backend Example
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand } from '@aws-sdk/client-s3';
import type { IMediaStorage, MediaStorageMetadata, MediaStorageResult } from 'oneringai';
class S3MediaStorage implements IMediaStorage {
private s3: S3Client;
private bucket: string;
constructor(bucket: string, region: string) {
this.s3 = new S3Client({ region });
this.bucket = bucket;
}
async save(data: Buffer, metadata: MediaStorageMetadata): Promise<MediaStorageResult> {
const key = `media/${metadata.type}/${Date.now()}_${Math.random().toString(36).slice(2)}.${metadata.format}`;
await this.s3.send(new PutObjectCommand({
Bucket: this.bucket,
Key: key,
Body: data,
ContentType: this.getMimeType(metadata.format),
}));
return { location: key, mimeType: this.getMimeType(metadata.format), size: data.length };
}
async read(location: string): Promise<Buffer | null> {
try {
const response = await this.s3.send(new GetObjectCommand({ Bucket: this.bucket, Key: location }));
return Buffer.from(await response.Body!.transformToByteArray());
} catch (err: any) {
if (err.name === 'NoSuchKey') return null;
throw err;
}
}
async delete(location: string): Promise<void> {
await this.s3.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: location }));
}
async exists(location: string): Promise<boolean> {
try {
await this.s3.send(new HeadObjectCommand({ Bucket: this.bucket, Key: location }));
return true;
} catch { return false; }
}
getPath(): string { return `s3://${this.bucket}/media/`; }
private getMimeType(format: string): string {
const map: Record<string, string> = { png: 'image/png', jpg: 'image/jpeg', mp4: 'video/mp4', mp3: 'audio/mpeg' };
return map[format] ?? 'application/octet-stream';
}
}
Setting the Global Storage
import { setMediaStorage } from 'oneringai';
// Set globally before creating agents - all multimedia tools will use this
setMediaStorage(new S3MediaStorage('my-bucket', 'us-east-1'));
All multimedia tools (generate_image, generate_video, text_to_speech, speech_to_text) automatically use the global storage handler.
FileMediaStorage Default
The built-in FileMediaStorage saves files to os.tmpdir()/oneringai-media/ by default:
import { FileMediaStorage, createFileMediaStorage } from 'oneringai';
// Use defaults (saves to /tmp/oneringai-media/)
const storage = createFileMediaStorage();
// Custom output directory
const storageVariant2 = createFileMediaStorage({ outputDir: '/data/media-outputs' });
Per-Tool-Factory Storage
For advanced use cases, you can pass a storage instance directly to individual tool factories:
import { createImageGenerationTool } from 'oneringai';
const connector = Connector.get('openai');
const tool = createImageGenerationTool(connector, myCustomStorage);