Skip to main content
Version: 2.6

File Serving

Files stored in agent databases can be served directly via a built-in HTTP endpoint. This works for PDFs, images, documents, and any other binary file type.

Overview

The file serving system has three parts:

  1. Storage: Files are stored as BLOBs in the files table via aktorStoreFileWithContent
  2. URL: Files are accessible at /databases/:databaseId/files/:fileId
  3. Response: The endpoint sets the correct Content-Type and serves the file inline (browser displays it directly)

Storing Files

From Uint8Array (server-side)

import { aktorStoreFileWithContent } from '@operaide/vector';

const storedFile = await aktorStoreFileWithContent({
client: dbClient,
filename: 'photo.png',
content: fileBuffer, // Uint8Array
}).get();

// storedFile.file_id → use this to build the URL

MIME type and extension are detected automatically from the filename. Duplicate files (same SHA-256 hash) are deduplicated unless skipDeduplication: true is set.

From browser File objects

import { aktorProcessJSFile } from '@operaide/vector';

const storedFile = await aktorProcessJSFile({
client: dbClient,
file: browserFileObject, // File from <input type="file">
}).get();

Via the Embedding Pipeline

aktorVektorEmbeddingPipeline automatically stores the file as the first step. The resulting file_id is available in the pipeline result.

Generating File URLs

The URL pattern is:

/databases/{databaseId}/files/{fileId}

Build it in an aktor like this:

const fileUrl = `/databases/${databaseId}/files/${storedFile.file_id}`;

For absolute URLs (e.g. to return in API responses), prepend the platform root URL:

import { getPlatform } from '@operaide/aktor';

const absoluteUrl = `${getPlatform().config.getRootUrl()}/databases/${databaseId}/files/${fileId}`;

HTTP Endpoint

Request: GET /databases/:databaseId/files/:fileId

Response:

StatusMeaning
200File served with binary content
404Database or file not found
500Server error

Headers (on 200):

  • Content-Type: Determined from stored mime_type or filename extension
  • Content-Disposition: inline; filename="..." (browser displays the file)
  • Content-Length: File size in bytes

Supported MIME Types

ExtensionContent-Type
.pngimage/png
.jpg, .jpegimage/jpeg
.gifimage/gif
.svgimage/svg+xml
.webpimage/webp
.pdfapplication/pdf
.docapplication/msword
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.txttext/plain
.csvtext/csv
.htmltext/html
.mdtext/markdown
.jsonapplication/json
.xmlapplication/xml
.zipapplication/zip
.mp4video/mp4
.mp3audio/mpeg
.wavaudio/wav

Unknown extensions fall back to application/octet-stream.

Complete Example

Store a PDF, generate a URL, and return it to the user:

import { aktorStoreFileWithContent } from '@operaide/vector';
import { createAktorFunctionAsync } from '@operaide/aktor';
import * as fs from 'fs';

const aktorUploadAndServe = createAktorFunctionAsync(
'aktorUploadAndServe',
async (p: { client: Client; databaseId: string; filePath: string }) => {
// Read file
const buffer = fs.readFileSync(p.filePath);
const filename = p.filePath.split('/').pop()!;

// Store in database
const stored = await aktorStoreFileWithContent({
client: p.client,
filename,
content: new Uint8Array(buffer),
}).get();

// Return serving URL
return `/databases/${p.databaseId}/files/${stored.file_id}`;
}
);

For a working example, see the op-demo-database app which implements aktorGenerateFileUrl.

Next Steps