Files
Manage provider-hosted files through an AnyLLM instance
The Files API exposes upload, listing, metadata retrieval, streamed download, and deletion on an AnyLLM instance. Anthropic, OpenAI, Azure OpenAI, and Gemini (Developer API only) support Files. Vertex AI and custom OpenAI-compatible endpoints do not automatically inherit Files support.
Anthropic
Yes
Yes
Yes
Generated files
Yes
OpenAI
Yes, requires purpose
Yes
Yes
Depends on file purpose
Yes
Azure OpenAI (v1)
Yes, requires purpose
Yes
Yes
Depends on file purpose
Yes
Gemini (Developer API)
Yes
Yes
Yes
No
Yes
Vertex AI
No
No
No
No
No
Check get_provider_metadata().file_operations before using Files on a provider.
from any_llm import AnyLLM
provider = AnyLLM.create("anthropic") # ANTHROPIC_API_KEY
capabilities = provider.get_provider_metadata()
print(capabilities.files)
print(capabilities.file_operations)Upload and use a file
from pathlib import Path
from any_llm import AnyLLM
provider = AnyLLM.create("anthropic")
uploaded = provider.upload_file(
Path("report.pdf"),
mime_type="application/pdf",
expires_in=3600,
)
try:
response = provider.messages(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{
"role": "user",
"content": [
{"type": "document", "source": {"type": "file", "file_id": uploaded.id}},
{"type": "text", "text": "Summarize this report."},
],
}],
)
print(response.content)
finally:
provider.delete_file(uploaded.id)file accepts a path (str or PathLike), bytes, or a binary file handle. filename and mime_type override the multipart part's metadata. The default filename is the path's basename, or upload for bytes and handles; the default MIME type is application/octet-stream. Supply the actual MIME type for inputs whose interpretation depends on it.
Path uploads open a binary handle and close it after the request. Caller-owned handles remain open. The SDK multipart encoder reads handles in bounded chunks; any-llm does not read the entire path into bytes first. These file reads are synchronous SDK I/O even for an asynchronous upload. Bytes inputs are already resident in memory. Async iterators are not supported upload inputs.
OpenAI uploads
OpenAI requires an explicit, nonempty purpose for every upload. Choose the purpose for the API that will consume the file: user_data for general model inputs, batch for Batch API input JSONL, or fine-tune for training data. Other upload purposes include assistants, vision, and evals. OpenAI validates accepted purposes, file formats, and account-specific limits on the server.
expires_in maps to OpenAI's expires_after with anchor="created_at" and seconds=expires_in. Omit it to use the provider's retention policy. The server validates supported durations and purpose combinations. Native expires_after keyword arguments are not accepted; use the shared expires_in parameter.
OpenAI's bytes becomes size_bytes, and timestamps become datetime values. purpose and status are preserved when returned. Missing metadata, including mime_type and downloadable, remains None; do not interpret an unknown downloadable value as permission to download.
Azure OpenAI Files
Azure OpenAI uses the same public methods and metadata normalization as OpenAI, but routes requests to your Azure resource's /openai/v1/files endpoint. Configure AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY, or use the provider's existing Microsoft Entra authentication options (azure_ad_token or azure_ad_token_provider). Files requests use the v1 routes without adding a preview query parameter or a deployment name to the URL.
The Azure Files v1 reference lists upload purposes assistants, batch, fine-tune, and evals. Do not assume that OpenAI's user_data or vision upload purposes are available on Azure. Azure validates accepted purposes, file formats, expiry durations, and download permissions on the server. expires_in uses the same expires_after mapping as OpenAI; the adapter does not invent an expiry when it is omitted. For batch uploads, Microsoft documents 1,209,600 to 2,592,000 seconds (14 to 30 days). The Azure resource used by our integration tests also accepted 259,200 seconds (3 days), but this does not establish a universal minimum. Use 14 to 30 days unless you have confirmed a lower minimum on your resource. A one-hour expiry accepted by OpenAI was rejected by our Azure resource with HTTP 400. Verify the retention behavior for the purpose and Azure resource you use.
Azure shares the cursor/next_cursor pagination contract and supports the purpose filter and order option. File IDs remain scoped to their originating Azure resource and account; do not pass OpenAI file IDs to Azure or vice versa.
Gemini Files
Gemini Files is available on the Gemini Developer API (AnyLLM.create("gemini")), not Vertex AI. Uploads, listing, metadata, and deletion use google-genai's client.aio.files. Generated-file download is not a supported operation. File IDs are Gemini resource names such as files/abc-123; passing the bare suffix abc-123 is accepted and canonicalized.
filename maps to Gemini's display_name. An explicit mime_type is always forwarded. Without one, a path upload takes its MIME type from the file extension, and bytes, binary handles, and paths with an unrecognized extension default to application/octet-stream. any-llm opens a path upload itself and closes it after the request, so only a failure to open the path is reported as an unreadable path; caller-owned handles remain open. Gemini requires seekable binary streams. Because google-genai's async upload reads the stream on the event loop, any-llm runs the upload on the synchronous google-genai client in a worker thread. Uploads therefore use http_options.client_args, not async_client_args; configure a custom transport or proxy in both if uploads must go through it. The shared purpose and expires_in parameters are rejected: Gemini does not classify uploads by purpose, and uploaded files expire after 48 hours.
Upload may return status="PROCESSING". Wait until ACTIVE before referencing the file URI in a model request, and pause between polls. FAILED includes provider error details in error. Pass filename with the file URI. Gemini file URIs have no extension. Native fields such as uri, download_uri, source, sha256_hash, and error are preserved on FileMetadata extras.
Methods
upload_file(file, filename=None, mime_type=None, purpose=None, expires_in=None, **kwargs)
await aupload_file(...)
FileMetadata
list_files(limit=None, cursor=None, purpose=None, **kwargs)
await alist_files(...)
FilePage
retrieve_file(file_id, **kwargs)
await aretrieve_file(...)
FileMetadata
download_file(file_id, chunk_size=65536, **kwargs)
adownload_file(...)
Context manager yielding FileDownload / AsyncFileDownload
delete_file(file_id, **kwargs)
await adelete_file(...)
FileDeleted
These are instance methods. Reuse the instance configured for the originating provider account; file IDs are not portable to another provider or account. Use async methods inside an event loop. Sync methods honor the existing allow_running_loop option.
FileMetadata, FilePage, and FileDeleted are exported from any_llm and any_llm.types.files. Metadata uses size_bytes, mime_type, and parsed datetime timestamps, plus purpose, status, and downloadable. Fields a provider omits remain None. Each provider normalizes its own responses. Provider-specific fields survive in model_extra and model_dump(). A deletion acknowledgement preserves its native fields, without inventing a deleted flag if absent.
Pagination
Listing fetches exactly one page. Use the opaque next_cursor with the same provider, account, and filters to continue; None marks the final page.
Providers translate their native pagination into cursor and next_cursor. OpenAI and Azure OpenAI map cursor to after and derive next_cursor from the last file ID when has_more is true. Use purpose="batch" to filter a listing and order="asc" or order="desc" to select the order. Keep the same purpose and order on subsequent pages. Do not pass the native after keyword.
Anthropic maps cursor and next_cursor to page and next_page internally. Native cursor keyword arguments are not supported, and listing rejects the legacy files-api-2025-04-14 beta because it changes the page shape. Other Files operations forward that beta unchanged.
For a known set of IDs, Anthropic accepts the provider-specific ids=[...] option. The server validates its limits and combinations with other parameters. Missing or inaccessible IDs are omitted.
Gemini maps limit/cursor to page_size/page_token and reads next_cursor from the current pager page's next_page_token. Listing does not iterate the SDK pager, so subsequent pages are never fetched automatically. Native page_size and page_token keywords are not accepted.
Downloads and provider restrictions
OpenAI
Download eligibility depends on the file's purpose. Batch input files can be downloaded through the Files API without submitting a batch job. OpenAI rejects downloads of user_data files with HTTP 400, even when uploading and retrieving their metadata succeeds. Other purposes have their own restrictions; consult OpenAI's Files reference before assuming a file can be downloaded.
For a downloadable file ID, use openai_provider.download_file(file_id) or openai_provider.adownload_file(file_id) with the context-manager patterns below. OpenAI's deletion acknowledgement preserves its native deleted flag and provider-specific fields such as object.
Azure OpenAI
Azure downloads use /openai/v1/files/{file_id}/content with the same streaming context managers. Download eligibility is determined by Azure, not by the OpenAI purpose restrictions above. A failure on context entry is propagated through the normal error mapping; it is not treated as an empty download.
Gemini
User uploads are not downloadable (source="UPLOADED", no download_uri). download is omitted from Gemini file_operations until a live generated-file download has been checked. download_file on an upload raises InvalidRequestError before opening a content stream.
Anthropic
Anthropic marks user uploads as non-downloadable. Download files returned by native code execution or supported skills, using their structured file_id. MessagesParams.container accepts a string container ID or the documented Skills object (str | ContainerParams on Anthropic SDK 0.124+). Skills are GA on messages.create; any-llm does not infer a skills beta header. Tenant ownership, authorization, persistence, and cleanup remain application responsibilities.
Fresh skill-enabled container:
Reuse an existing container while keeping the same Skills:
For example, after a Messages request using the native code execution tool:
For an async caller with a generated file ID:
The request starts on entering with or async with. Connection failures and HTTP errors are raised before the context body runs, so a gateway can return the correct error status before committing its downstream response.
The public FileDownload and AsyncFileDownload types expose status_code and headers as soon as the context is entered. Response header lookup is case-insensitive for Anthropic, OpenAI, Azure OpenAI, and Gemini. Both objects remain directly iterable over bytes, so existing for chunk in download and async for chunk in download loops keep working. They are exported from any_llm and any_llm.types.files.
Body reads begin only on iteration. Always use the context manager, even if you only inspect headers: exiting closes the upstream response after full consumption, early exit, or cancellation. The sync bridge requests one chunk at a time without prefetching the body. Exceptions raised by consumer code are not converted into provider errors.
Headers describe the upstream response, while body chunks use the transport's content decoding. A proxy must choose an explicit response-header allowlist; it must not blindly forward Content-Encoding or a compressed Content-Length for decoded bytes. Header values can include sensitive metadata such as filenames and should not be logged indiscriminately.
Provider options and errors
All OpenAI and Azure OpenAI Files methods accept timeout, max_retries, and extra_headers. Upload requires the shared purpose parameter and accepts expires_in. Listing accepts purpose and the provider-specific order option. Anthropic's betas and ids options are not accepted by either provider.
All Anthropic Files methods accept timeout, max_retries, betas, and extra_headers (for example, {"anthropic-version": "2023-06-01"}). Upload also accepts the shared expires_in parameter, a positive integer duration in seconds, which maps to Anthropic's expires_in_seconds. Omission leaves retention to the provider. The shared purpose parameter is available for upload and listing; Anthropic rejects non-None values. Provider-specific options remain in **kwargs. Beta values from configured headers, request headers, and betas are merged. Anthropic SDK 0.124.0 or newer is required.
Gemini Files methods accept timeout, max_retries, and extra_headers. timeout must be a positive number of seconds; it is converted to google-genai's millisecond http_options.timeout, rounded up so that a sub-millisecond value never becomes zero. max_retries maps to HttpRetryOptions.attempts (attempts include the original request, so max_retries=0 is one attempt). It applies to metadata requests and to the request that creates an upload session. A download body is sent directly through the SDK HTTP client and is not retried. Uploads default to zero automatic retries of that creation request. The resumable byte transfer that follows runs its own retry loop inside google-genai, up to three attempts per chunk, which max_retries does not reach; those retries resume the same upload session and cannot create a second file. extra_headers is merged into retrieve, list, delete, and download requests. google-genai's resumable upload rebuilds session headers, so extra_headers is not applied to the upload transfer itself. The shared purpose and expires_in parameters are rejected. Deletion acknowledgements return the canonical file ID and do not invent a deleted flag; Gemini's delete response has no such field.
Unsupported options raise UnsupportedParameterError. Nonpositive limit, invalid expires_in, nonpositive chunk_size, invalid file IDs, and upload paths that cannot be opened raise InvalidRequestError. Local file-opening errors are preserved in original_exception, regardless of the unified-exceptions setting. Provider-specific numeric limits and option combinations are validated by the server, so SDK updates do not require copying server limits into any-llm.
Uploads default to zero automatic retries, even if the provider instance has retries enabled. A caller can explicitly override max_retries, but a lost response can follow successful creation: retrying can create another file. Other operations inherit the configured SDK retry policy unless overridden. Timeouts do not prove that an upload failed before creation.
Errors follow the provider's unified_exceptions option, falling back to the ANY_LLM_UNIFIED_EXCEPTIONS environment variable when it is not set. When enabled, a retrieve, download, or delete HTTP 404 becomes ProviderFileNotFoundError, authentication errors remain AuthenticationError, and RateLimitError retains retry_after. A missing Gemini file is HTTP 403 whose message says the file may not exist; that response is ProviderFileNotFoundError with status_code=403. A 403 without that phrase stays AuthenticationError. An invalid Gemini API key is HTTP 400 and is not treated as a missing file. Upload and list 404s retain the existing general error mapping. Streaming failures are converted during iteration. Without unified errors, SDK exceptions retain their existing behavior.
Applications remain responsible for authorization, ownership, cleanup jobs, credential rotation, and provider-account selection. This API neither stores application copies nor makes provider files shareable between tenants.
Last updated