@emberark/agent-tool-storage
v1.0.2
Published
A unified file uploader with support for: - AWS S3 - MinIO (via S3-compatible API) - Local storage (PVC or direct filesystem)
Readme
Upload Tool
A unified file uploader with support for:
- AWS S3
- MinIO (via S3-compatible API)
- Local storage (PVC or direct filesystem)
Features
- Upload a file to the configured backend
- Get back a presigned URL (or equivalent for local)
- Enforce file size limits
- Customize file path prefix
- Compatible with agentic workflows
🧱 Installation
npm install @emberark/agent-tool-storage🚀 Usage
S3
import { createUploader } from '@emberark/agent-tool-storage';
createUploader({
backend: 's3',
s3: {
region: 'us-west-2',
bucket: 'my-prod-bucket',
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
endpoint: 'https://s3.amazonaws.com' // Optional for AWS
},
prefix: 'users/alex/',
defaultExpirationSeconds: 600,
maxFileSizeMB: 100
});MinIO (S3-compatible)
import { createUploader } from '@emberark/agent-tool-storage';
createUploader({
backend: 's3',
s3: {
region: 'us-east-1',
bucket: 'dev',
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
endpoint: 'http://localhost:9000' // MinIO endpoint
},
prefix: 'agent/uploads/',
defaultExpirationSeconds: 300,
maxFileSizeMB: 20
});Local Filesystem (PVC or disk)
import { createUploader } from '@emberark/agent-tool-storage';
createUploader({
backend: 'local',
local: {
directory: '/mnt/pvc/storage',
publicUrlPrefix: 'http://localhost:8080/files'
},
prefix: 'uploads/session-xyz/',
maxFileSizeMB: 10
});This creates files in /mnt/pvc/storage/uploads/session-xyz/, which are served under http://localhost:8080/files/uploads/session-xyz/
API Reference
createUploader(config: UploadClientConfig)
| Option | Type | Description |
| -------------------------- | ------------------- | ------------------------------------------------------------- |
| backend | 's3' | 'local' | Required. Determines which storage to use. |
| prefix | string | Optional. Adds a path prefix to every file (e.g. user123/). |
| maxFileSizeMB | number | Optional. Max file size allowed. Default: 50 MB |
| defaultExpirationSeconds | number | Optional. For presigned URLs. Default: 900 seconds |
| s3 | S3Config | Required if backend is 's3' |
| local | LocalConfig | Required if backend is 'local' |
uploadFile({ filename, content, contentType })
| Field | Type | Description |
| ------------- | -------- | ------------------------------------------------------------------------ |
| filename | string | Name of the file (e.g. output.pdf) |
| content | Buffer | File contents |
| contentType | string | MIME type (image/png, application/pdf, etc.) |
| prefix | string | Optional. Dynamic prefix for this upload. Overrides default if provided. |
Returns:
{
fileUrl: string;
expiresAt?: Date;
}Security Notes
- Always validate content type and size before upload
- Use scoped, time-limited credentials for cloud uploads
- Use HTTPS endpoints in production
Agent Tool Integration
You can wrap createUploader() into a Mastra-compatible Tool (https://mastra.ai/en/docs/tools-mcp/overview) object to expose it in your Agent. Example included in examples/upload-file/tool.ts.
import { z } from 'zod';
import { createUploader } from '@emberark/agent-tool-storage';
import { Tool } from '@mastra/core/schema';
const uploader = createUploader({
backend: 's3',
prefix: 'uploads/session-001/', // default fallback
maxFileSizeMB: 100,
defaultExpirationSeconds: 900,
s3: {
region: process.env.S3_REGION!,
bucket: process.env.S3_BUCKET!,
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
endpoint: process.env.S3_ENDPOINT || undefined
}
});
const uploadFileTool: Tool = {
name: 'upload-file',
description: 'Uploads a file to the configured storage backend (S3, MinIO, or local) and returns a presigned URL.',
inputSchema: z.object({
prefix: z.string().optional().describe('Optional custom prefix (e.g., "agent-1234/session-5678/")'),
filename: z.string().describe('The desired name for the uploaded file, including extension (e.g., "image.png")'),
content: z.string().describe('The file content encoded as a base64 string'),
contentType: z.string().describe('The MIME type of the file (e.g., "image/png", "application/pdf")')
}),
outputSchema: z.object({
fileUrl: z.string().url().describe('Presigned URL to access the uploaded file'),
expiresAt: z.string().optional().describe('Optional expiration timestamp for the URL (ISO 8601)')
}),
run: async (input) => {
const buffer = Buffer.from(input.content, 'base64');
const result = await uploader.uploadFile({
prefix: input.prefix,
filename: input.filename,
content: buffer,
contentType: input.contentType
});
return {
fileUrl: result.fileUrl,
expiresAt: result.expiresAt?.toISOString()
};
}
};
export default uploadFileTool;