Files
New in 2.0
Upload provider-managed files for APIs that require file IDs
Provider-managed files are different from inline chat attachments. Use with: for normal prompt files. RubyLLM automatically promotes large eligible local attachments to provider-managed files when the selected provider can reference stored files in chat. Use RubyLLM.upload when you want to upload once and reuse the same provider file ID or URI yourself.
Uploading
file = RubyLLM.upload("batch.jsonl", purpose: "batch")
file.id # => "file_..."
file.filename # => "batch.jsonl"
file.byte_size # => 1234
file.mime_type # => "application/jsonl"
When provider: is omitted, RubyLLM uses the provider of config.default_model, the same model resolution path as RubyLLM.chat. Pass provider: when the file belongs to a different provider:
file = RubyLLM.upload("document.pdf", provider: :anthropic)
You can pass a path, an IO object, or a RubyLLM::Attachment. For IO objects, pass filename: so the provider receives a useful name:
io = StringIO.new(jsonl)
file = RubyLLM.upload(io, provider: :openai, purpose: "batch", filename: "batch.jsonl")
OpenAI and Azure require purpose: because their Files API requires it: assistants, batch, fine-tune, vision, user_data, or evals. Mistral accepts purpose: for batch, fine-tuning, and OCR workflows. Other providers infer the file use from the API call that later references the file.
Expiration
Pass expires_in: with a number of seconds to have the provider delete the file automatically:
file = RubyLLM.upload("batch.jsonl", purpose: "batch", expires_in: 24 * 60 * 60)
file.expires_at # => 2026-07-05 12:00:00 +0000
RubyLLM translates the duration into each provider’s wire format. OpenAI anchors the expiration to the upload time and accepts between 1 hour and 30 days. xAI takes the value as seconds from upload, in the same range. Mistral counts expiration in whole hours, so RubyLLM rounds expires_in up to the next hour. Providers without upload expiration ignore the option; Gemini files always expire after 48 hours.
Using Files in Chat
Pass an uploaded file through with: to reuse it by provider-managed ID or URI:
file = RubyLLM.upload("large-report.pdf", provider: :openai, purpose: "user_data")
chat = RubyLLM.chat(model: "gpt-5-nano", provider: :openai)
chat.ask("Summarize the financial risks.", with: file)
For Gemini and Vertex AI, uploaded files are referenced by URI:
file = RubyLLM.upload("demo.mp4", provider: :gemini)
chat = RubyLLM.chat(model: "gemini-2.5-flash", provider: :gemini)
chat.ask("What happens in this video?", with: file)
Large Chat Attachments
When config.auto_upload_large_files is true, RubyLLM uploads oversized local attachments before storing the message and replaces them with a provider-managed file reference. The original chat message then contains the provider file ID or URI instead of inline bytes.
RubyLLM.configure do |config|
config.auto_upload_large_files = true
end
Automatic uploads are enabled only for providers and protocols that can reference stored files in chat. Other providers keep their existing inline behavior and still raise provider errors when a request exceeds that provider’s limits.
Finding and Downloading
file = RubyLLM::UploadedFile.find("file_123")
content = RubyLLM.download(file.id)
File IDs are provider-owned, so persist the provider alongside any file id you store and pass it back explicitly when reading later.
Provider Notes
| Provider | Files API limit | Chat file references | Automatic large attachments |
|---|---|---|---|
| OpenAI | 512 MB per file; purpose: required | PDF files by file_id in Responses and Chat Completions | PDFs above 50 MB, uploaded with purpose: "user_data" |
| Azure OpenAI / Foundry | 512 MB per API upload for assistants and fine-tuning; purpose: required | Upload/find/download only; Azure chat file references are not enabled | No |
| Anthropic | 500 MB per file; beta Files API | Images, PDFs, and text files by file_id | Images, PDFs, and text files above 24 MB |
| Gemini | 2 GB per file, 20 GB per project, 48-hour retention | Media, PDFs, and text files by Files API URI | Supported attachments above 20 MB |
| Mistral | 512 MB per file | Upload/find/download for batch, fine-tuning, OCR, and retrieval workflows | No |
| xAI | 48 MB per file | Upload/find/download only in RubyLLM’s current xAI Chat Completions protocol | No |
| OpenRouter | 100 MB per file | PDF files by file_id in Chat Completions file parts | PDFs above 50 MB |
| Vertex AI | Google Cloud Storage backed; Gemini fileData supports large gs:// inputs | Gemini models by gs:// URI; batch workflows also use GCS | Supported Gemini attachments above 7 MB |
| Bedrock | S3 backed | Supported Converse document formats by S3 URI | Supported documents above 4.5 MB |
| DeepSeek, GPUStack, Ollama, Perplexity | No provider-managed Files API in RubyLLM | Inline/provider-specific attachment behavior only | No |
Downloads depend on the provider. Anthropic and OpenRouter only allow downloading files created server-side; uploaded files are not downloadable through their Files APIs.