Appearance
S3 Storage
Overview
S3-compatible object storage handles two categories of files in the Lota SDK: user-uploaded attachments (files attached to conversation messages) and generated documents (artifacts produced by the runtime, such as exported reports or pipeline outputs). The storage layer is owned by @lota-sdk/core and accessed exclusively through runtime service accessors.
Public Runtime Boundary
ts
const runtime = await createLotaRuntime(config)
await runtime.connect()
const { attachmentService, generatedDocumentStorageService } = runtime.servicesHost code should use runtime.services.attachmentService and runtime.services.generatedDocumentStorageService.
Ownership
core/src/storage/attachment-storage.service.tscore/src/storage/generated-document-storage.service.tscore/src/storage/attachment-parser.tscore/src/storage/attachments.utils.ts
Attachment Upload Flow
When a user attaches a file to a conversation message, the following sequence occurs:
Upload. The file is uploaded to S3 via the attachment service. The storage key is structured by organization, user, and workstream to ensure tenant isolation:
{orgId}/{userId}/{workstreamId}/{filename}.Metadata persistence. A
workstreamAttachmentrecord is created in SurrealDB containing the storage key, original filename, MIME type, file size, and a reference to the associated message.Presigned URL generation. A presigned download URL is generated with a configurable TTL (default: 30 minutes). This URL grants temporary read access to the object without exposing S3 credentials.
URL re-signing on load. Every time messages are loaded for a workstream, attachment URLs are re-signed with fresh expiry times. This ensures users never encounter expired download links, regardless of how long the conversation has been idle.
Content parsing. The
attachment-parsermodule extracts text content from supported file types (PDF, plain text, code files, etc.) so that the content can be included in the agent's context window.
Generated Documents
Runtime-generated artifacts are stored via generatedDocumentStorageService. These are separate from user attachments and include:
- Exported documents produced by agent tools
- Pipeline outputs from execution plans
- Any file artifacts created during agent execution
Generated documents follow the same presigned URL pattern for retrieval but use a distinct storage key namespace to keep them separate from user uploads.
S3-Compatible Services
The SDK uses the standard AWS S3 API (@aws-sdk/client-s3 and @aws-sdk/s3-request-presigner), which means it works with any S3-compatible object storage service:
| Service | Notes |
|---|---|
| AWS S3 | Native support |
| MinIO | Common for local development and self-hosted deployments |
| Garage | Lightweight, used in the default docker-compose stack |
| DigitalOcean Spaces | Drop-in S3-compatible |
| Cloudflare R2 | S3-compatible with no egress fees |
| Backblaze B2 | S3-compatible API available |
The only requirement is that the bucket specified in the configuration must already exist. The SDK does not create buckets automatically.
Configuration Details
ts
s3: {
endpoint: 'http://localhost:3910', // S3-compatible endpoint URL
bucket: 'lota-attachments', // Bucket name (must already exist)
region: 'garage', // Region identifier (default: 'garage')
accessKeyId: 'your-access-key', // S3 access key
secretAccessKey: 'your-secret-key', // S3 secret key
attachmentUrlExpiresIn: 1800, // Presigned URL expiry in seconds (default: 30 min)
}| Option | Required | Default | Description |
|---|---|---|---|
endpoint | Yes | — | The S3-compatible service endpoint URL |
bucket | Yes | — | Target bucket for all stored objects |
region | No | 'garage' | AWS region or equivalent identifier |
accessKeyId | Yes | — | Access key for authentication |
secretAccessKey | Yes | — | Secret key for authentication |
attachmentUrlExpiresIn | No | 1800 | Presigned URL TTL in seconds |
The lower-level storage modules remain implementation detail surfaces for the runtime. The supported host boundary is the runtime service accessor.