Multimodal & Media
Foil supports multimodal traces — mix text, documents, spreadsheets, code files, and images in your span inputs and outputs. Upload files via the SDK, and Foil automatically extracts text content for evaluations and analysis.How It Works
- You upload a file via the SDK — it’s stored in S3 and categorized automatically
- The ingestion service extracts text content (for documents, spreadsheets, code)
- You reference the uploaded media in span inputs/outputs using content blocks
- Evaluations automatically include extracted text when analyzing spans
Supported Media Categories
| Category | File Types | Max Size | Processing |
|---|---|---|---|
| Document | PDF, DOCX, DOC, RTF | 50 MB | Text extraction, metadata |
| Spreadsheet | CSV, TSV, XLSX, XLS, ODS | 25 MB | Text + structured JSON extraction |
| Code | Any text/code file | 10 MB | Direct text passthrough |
| Image | PNG, JPEG, GIF, WebP, SVG | 20 MB | Dimensions & metadata |
| Audio | MP3, WAV, OGG, FLAC | 100 MB | Coming soon |
| Video | MP4, WebM, MOV | 500 MB | Coming soon |
| Archive | ZIP, TAR, GZ | 100 MB | Coming soon |
| Notebook | .ipynb | 10 MB | Coming soon |
| Other | Any other file | 25 MB | Stored as-is |
Media category is auto-detected from the file’s MIME type. You can associate up to 20 files per span.
Content Blocks
Content blocks let you mix text and media references in span inputs and outputs:- Text blocks — plain text content (
{ type: 'text', text: '...' }) - Media blocks — references to uploaded media (
{ type: 'media', mediaId: '...' })
- JavaScript
- Python
Auto-Upload with ContentBlock.file() (JavaScript)
The JavaScript SDK supports ContentBlock.file() which automatically uploads files before the span is sent — no manual uploadMedia() call needed:
ContentBlock.file() accepts a file path, Buffer, or ReadStream:
Uploading Media
Upload files directly withuploadMedia() for more control over the upload lifecycle.
- JavaScript
- Python
Upload Options
| Option | Type | Description |
|---|---|---|
filename | string | Override filename (required for Buffer/bytes) |
mimeType / mime_type | string | Override MIME type (auto-detected if omitted) |
spanId / span_id | string | Associate media with a span |
traceId / trace_id | string | Associate media with a trace |
direction | string | 'input' or 'output' |
Using Media in Spans
After uploading, reference media in span inputs and outputs using content blocks.- JavaScript
- Python
ContentBlock.file() to skip manual upload:Retrieving Media
Limitations
Best Practices
Upload media before creating spans
Upload media before creating spans
Upload files first and use the returned
mediaId in your content blocks. This ensures media is available when the span is processed. Alternatively, use ContentBlock.file() (JavaScript) to handle this automatically.Use content blocks for structured input/output
Use content blocks for structured input/output
Instead of embedding file contents as plain text, use content blocks. This enables Foil to track media associations, provide download links, and include extracted content in evaluations.
Check processing status for time-sensitive workflows
Check processing status for time-sensitive workflows
Text extraction is asynchronous. If you need extracted content immediately, poll
getMedia() until processing.status is 'completed'.Prefer file paths over Buffers
Prefer file paths over Buffers
When possible, pass file paths to
uploadMedia() or ContentBlock.file(). This lets the SDK auto-detect the filename and MIME type. When using Buffer/bytes, always provide a filename.