You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The composer only accepts images (image/* gate in ChatComposer.tsx / Normalizer.ts). Dropping a PDF, log file, or CSV shows "Please attach image files only." When driving an agent remotely (desktop app or web paired to t3 serve on another machine), there is no way to hand the agent a file — you have to scp it to the server and type the path by hand.
Related: #2803 (mobile web attach) is adjacent but different surface.
Proposed design (implemented, PR ready)
Images keep their exact current flow (native image content blocks per provider). Non-image files reuse the existing upload path — base64 data URL → server writes to <stateDir>/attachments/ — and are delivered by reference: at the single sendTurn choke point in ProviderCommandReactor, a line like
[Attached file: /abs/state/attachments/<id>.pdf (report.pdf, application/pdf, 2.1 MB). Read it from disk when needed.]
is appended to the turn input, and the attachment list passed to the provider is filtered to images only. The agent reads the file with its own tools, so this works identically for Claude/Codex/Grok with zero adapter changes, and works for remote environments by construction (the file lands on the machine the agent runs on).
Details handled:
New ChatFileAttachment contract variant (additive union member — old persisted rows decode unchanged; old clients hit the usual version-skew surface on threads containing file attachments, same class as fix(mobile): Send composer images in upload wire format #4035).
Disk extensions are allowlist-gated (SAFE_FILE_EXTENSIONS), .bin fallback — keeps .html-class extensions off the same-origin asset route.
Attachment GC keep-set in ProjectionPipeline updated (it currently skips non-image attachments, which would prune the files).
Non-image asset requests get Content-Disposition: attachment (no inline render).
Composer: same drag/drop + paste, non-images render as a name+size chip; timeline renders a download chip. Limits unchanged (10 MB, 8/message).
Known follow-up: shipped mobile renders file attachments as image tiles by id; a small mobile render fix can follow.
Happy to open the PR if this direction works for you — it's ~16 files, images' behavior untouched, with tests across contracts/server/web.
Problem
The composer only accepts images (
image/*gate inChatComposer.tsx/Normalizer.ts). Dropping a PDF, log file, or CSV shows "Please attach image files only." When driving an agent remotely (desktop app or web paired tot3 serveon another machine), there is no way to hand the agent a file — you have to scp it to the server and type the path by hand.Related: #2803 (mobile web attach) is adjacent but different surface.
Proposed design (implemented, PR ready)
Images keep their exact current flow (native image content blocks per provider). Non-image files reuse the existing upload path — base64 data URL → server writes to
<stateDir>/attachments/— and are delivered by reference: at the singlesendTurnchoke point inProviderCommandReactor, a line likeis appended to the turn input, and the attachment list passed to the provider is filtered to images only. The agent reads the file with its own tools, so this works identically for Claude/Codex/Grok with zero adapter changes, and works for remote environments by construction (the file lands on the machine the agent runs on).
Details handled:
ChatFileAttachmentcontract variant (additive union member — old persisted rows decode unchanged; old clients hit the usual version-skew surface on threads containing file attachments, same class as fix(mobile): Send composer images in upload wire format #4035).SAFE_FILE_EXTENSIONS),.binfallback — keeps.html-class extensions off the same-origin asset route.ProjectionPipelineupdated (it currently skips non-image attachments, which would prune the files).Content-Disposition: attachment(no inline render).Happy to open the PR if this direction works for you — it's ~16 files, images' behavior untouched, with tests across contracts/server/web.