cmux NEXT composer: arbitrarily large attachments never freeze it; cancel stops the upload

Merged
TE
11d ago
+693-52

Leo, 2026-10-25: "are the fixes for all the composer attachment/image big size things fixed? like arbitarrily large file sizes the composer should never ever freeze and prevent new things from happening/from cancelling the thing". And: "oh attaching a video froze the composer".

Follows #24975 (image work in a worker), #24976 (per-file tiles with spinner, cancel and retry) and #24993 (strip reorder). A fleet browser test of Leo's whole sentence (stacked PR, agent-pane-attach-huge-files.test.ts) failed 13 of 15 cases on #24976 as landed. These fixes make it pass 15 of 15.

What changes

  • Cancel stops the upload. A tile's x stops its file's upload at the next 512 KiB chunk and sends chat.upload.cancel, so the host drops what it staged. The rest of the batch goes on. Before: about 190 chunks kept going after x, and no cancel was sent.
  • An upload never holds a send. A file streaming to the session's machine no longer counts as loading for the send hold. The prompt goes with what is ready, and the file stays for the next one. Before: a send waited for the whole 2 GB upload.
  • Huge pictures go as files. A picture whose header says it is over 100 megapixels (PNG, GIF, JPEG and WebP headers read from the first 64 KiB) is never decoded. It goes as a file, linked or uploaded. Before: a 200 MP PNG was decoded and peaked the renderer at about 1.1 GB.
  • Huge text goes as a file.
    • A paste or a text drop over 1 MiB never reaches ProseMirror or a chip that holds it. The field hands it to the composer, which attaches it as Pasted text.txt through the file intake.
    • Its tile shows at once, and its bytes are made 4 MiB per task, never splitting a surrogate pair.
    • Before: a 100 MB paste took 2.4 s and sent a 100 MB text block, more than acpmux's 15 MiB per message. A 100 MB text drop froze the page.

Numbers (fleet run https://github.com/manaflow-ai/cmux/actions/runs/40246109860, Chromium, a stand-in host at 25 ms per chunk). Columns: tile | key p95 | longest stall | + menu | chunks after x / cancel sent | JS heap base/peak/after | another message sent while loading.

casetilekey p95stall+ menuafter xheap MBsend
nothing attached-172232-68/121/70129 ms
300 MB screen recording, drop/paste/+ (local and remote)6-9 ms15-1720-10632-450 / yes63-68/115-121/70126-151 ms
2 GB file, paste/drop7-8.5 ms16-1721-2241-440 / yes68/121/70141-156 ms
500 MB video, paste/drop7-9 ms14-1722-11743-440 / yes63-68/116-121/70136-150 ms
200 MP PNG, paste/drop6-9 ms1619-2034-48not decoded, a file68/121/7097-144 ms
100 MB text, paste/drop24-34 ms15-1737-4133-460 / yes68-168/221/70258-260 ms

The JS heap never holds a big file: it peaks at 121 MB, or 221 MB with the 100 MB text string, and returns to 70 MB. The two 106 and 117 ms stalls coincide with a GC in the window: key p95 stayed at 14-15 ms there. On #24976 as landed the same run measured a 2413 ms tile and 87 ms keys for the text paste, a frozen text drop, a 1.1 GB renderer for the PNG, and sends held until x.

Tests: composer-huge-attachments.test.ts (new, red without the fixes):

  • the header sizes, including JPEG;
  • a 200 MP PNG is never decoded;
  • a cancelled 64 MB upload stops after 3 chunks while the next file goes whole;
  • a paste over 1 MiB becomes a file of its exact text, split across slices around an emoji.

composer-intake-events, agent-pane-paste-large-screenshots, agent-pane-attach-reorder and composer-kept-attachments pass. The three composer-paste-text failures fail the same way on base.

Not here, by design

  • Native upload path: the app decodes and writes each upload chunk on its main thread, and has a 1 GiB cap (helper composer-bigupload).
  • Video previews and frames to the agent: helper composer-video. The video reaches the agent as a resource_link today, its Desktop path in a local chat.
  • + > Attach files: in a chat on this Mac it still copies the file through the page's input. It streams without blocking now.

Risk: medium-low. Intake semantics change in two ways: an upload no longer holds a send, and a text paste over 1 MiB becomes a file. Both are what Leo asked for.

Agent session: huge-blue

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.