Skip to main content

Files

A file is a file. Where it came from — the user attached it, the model generated it, the agent screenshotted a page or exported it from a sandbox — is provenance, not type, and it does not decide what can be done with it. What a file is decides how it is read; where it came from decides nothing.

This is separate from Documents, which is about a curated corpus the agent searches. This page is about the files in one conversation.

Read anything in the conversation

// The agent calls these; nothing to implement on your side.
list_files() // everything here: attached, generated, screenshotted, exported
read_file(name?) // read one — blank takes the most recent

read_file picks the best available route for that file and that model:

FileHow it is read
Text, CSV, JSON, code, logsDecoded directly — no processor, no model support needed
PDF, Word, spreadsheetsConverted to text with the project's document processor
Images, audio, videoPut in front of the model to perceive, if it can and input:<kind> allows
Anything elseReported as what it is, with the sandbox suggested

No sandbox is required for any of it. Reading a file in your own conversation is not a privilege, so these are bound for every chat.

That last row matters: a tool that implied a read it never performed is how an agent ends up handing over a screenshot it never checked. It says so instead.

Producing a file, and sending one

These are two separate acts, and deliberately so. Every producer puts a file into the conversation and hands back an id; nothing reaches the user until the agent says so:

write_file(name, content) // something the agent writes → id
screenshot_url(url) // a captured page → id
computer_export_file(path) // out of a sandbox → id
send_file(id) // give ANY of them to the user

A producer that also delivered would force the decision at the wrong moment: the agent would have to know at capture time whether a screenshot is worth showing — before it has looked at it — and could not change its mind after cropping. send_file works on any file in the conversation whatever produced it and however long ago, so "screenshot → check → crop → send the crop" is just four calls with the user seeing only the last.

write_file needs no sandbox — a text-only model can write a CSV and hand it over.

Every file classifies as one of four kinds — image, audio, video, or file for everything else — and delivery is allowed when either of these is true:

  • the token holds output:file, which permits sending any kind; or
  • the token holds output:<that kind> — so output:image alone is enough to send a picture.

So a screenshot goes out under output:file or output:image, and needs neither the other one nor both.

Why output:file is the broad one

output:file means "the agent may hand the user a file", full stop — a screenshot it took, a chart it rendered in a sandbox, a CSV it wrote. Those are files it produced, and a project that granted "you may send files" did not mean "except pictures".

output:image|audio|video answer a different question — whether the model may generate that medium — and they additionally permit delivering their own kind, since generated media the user can never be shown is generated for nobody.

Delivery is deliberately not gated on the turn's requested output_modalities: a screenshot the agent took is a file it produced, not a modality the model emitted.

Files the user never sees

Anything produced but not sent stays in the conversation for the agent's own use — an intermediate screenshot, a scratch CSV — and list_files still shows it. That is what keeps working notes out of the chat without throwing them away.

Moving between layers

computer_fetch_attachment(name?) // conversation → sandbox
computer_fetch_document("prices.csv") // knowledge base → sandbox (name or id)
computer_export_file(path) // sandbox → the conversation (then send_file)

All of these refer to the same descriptors, so a file crosses a boundary without changing identity: screenshot a page, pull it into a sandbox, annotate it with ImageMagick, send the result — and read any of them back at any point.

Note the third one: exporting brings a file into the conversation, it does not hand it over. That is send_file, for the reason the producers section gives — and it is the step easiest to forget, because the failure looks like success from every angle: the tool succeeded, the file exists, nothing errored, and attachments is empty.