Skip to content

Retrieving Output Files

Source: src/llm/files/retrieve.ts (+ LLMClient.retrieveFile/streamFile, AgentLoop.retrieveFile/streamFile, CompleteResult.retrieveFile/streamFile).

Hosted tools (code execution) produce files that surface on response.files as FileOutput descriptors, not bytes. This subsystem resolves a FileOutput into actual bytes plus display metadata (name / mimeType / size), buffered (retrieveFileBlob) or streamed (streamFileReadableStream, for large files piped to a sink without buffering).

It is deliberately not a FileProviderAdapter concern: that adapter covers upload / delete / getInfo / list of input files. Retrieving output file bytes is a distinct, read-only path that must be bound to the completion’s own model + key, so it lives next to the client.

A FileOutput carries exactly one of three retrieval shapes, and the resolver branches on which field is set — the caller never does:

FieldProviderResolution
data (base64)Googledecoded in-process, no HTTP
urlOpenAI code-interpreter imagesGET that URL
id (+ ref.containerId)Anthropic, OpenAI container filesGET the provider’s files / container-files endpoint

The public surfaces (CompleteResult, LLMClient, AgentLoop) all delegate to retrieveFile(file, ctx) / streamFile(file, ctx) with a RetrieveContext built from the client that made the call: { provider, apiKey, fetch, baseURL? }. This is why the user never re-passes model or key — the retrieval reuses the exact provider + credentials + engine (engine.fetch, so the queue / retry / cost / trace plumbing still applies).

contentRequest(ctx, file) builds the authenticated download request:

  • AnthropicGET /v1/files/{id}/content?beta=true with x-api-key, anthropic-version, anthropic-beta: files-api-2025-04-14, accept: application/binary.
  • OpenAI / xAI / OpenRouter — container path /v1/containers/{containerId}/files/{id}/content when file.ref.containerId is set, else /v1/files/{id}/content; Authorization: Bearer.
  • GoogleGET /v1beta/files/{id}:download?alt=media with x-goog-api-key (rare; Google usually returns inline data).

providerAuth(ctx, url) attaches the provider’s credentials only when the request URL starts with the provider’s base URL. A url-form FileOutput pointing at a third-party host (e.g. a CDN) is fetched with no auth header — so keys never leak off the provider’s own domain.

Name / type / size come from the download’s response headers, not guessed:

  • mimeTypeContent-Type (split off params), falling back to a filename-extension map (EXT_MIME), then application/octet-stream.
  • nameContent-Disposition (RFC 5987 filename*=utf-8''… preferred over filename="…"), else FileOutput.name.
  • sizeblob.size (buffered) or Content-Length (streamed).

streamFile uses the network layer’s responseType: 'stream', which returns the raw response.body (ReadableStream<Uint8Array>) and releases the queue slot immediately — the transfer isn’t held in memory, and the queue isn’t blocked for the whole download. Inline data is wrapped in a single-chunk stream so the streamed path has the same shape for all three sources.

  • All HTTP flows through the injected EngineFetch — never a bare fetch.
  • Provider credentials are sent only to the provider’s own host.
  • Buffered and streamed paths return the same metadata for the same file.