Repository navigation
acpmux: the app's WebSocket takes binary upload frames, with no size cap - #25803
Conversation
|
Owned by an agent session · session |
eedba3d to
b35e059
Compare
aa23033 to
b942f7e
Compare
15a44a8 to
e966c95
Compare
768cb76 to
7d01fa3
Compare
e966c95 to
f5c570c
Compare
f5c570c to
f45cb86
Compare
f45cb86 to
39a825b
Compare
… GB file reaches a busy chat that way Binary data frames on the app's own WebSocket (4 in flight), resumed from file_put_status after a disconnect, finish checked by sha256; any other connection gets a refusal as its answer; a peer's chat is written on the peer. A 2 GB file of no known type streams in 1 MiB frames to a busy chat, is accepted in under a second, and reaches the agent by path with its SHA-256 intact, with a small peak RSS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…der with no size cap
One binary frame is one _acpmux/file_put_data request: "AMUP", a u32
big-endian header length, the JSON-RPC header {sessionId, uploadId, offset},
then the raw bytes. A per-connection worker writes frames in order from a
queue of 4 and answers each once its bytes are on disk, so memory stays at a
few frames whatever the file's size. Any connection but the local app's gets
filePut.remote as its answer, never silence. A peer's chat gets the bytes as
file_put_chunk requests over the peer link. Feature uploadFrames.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…the frame it edits next Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…e, and a peer without chunked uploads is refused up front Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…upload to a peer without filePutChunks is refused before anything is sent Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…before the finish's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
67d5359 to
65f722d
Compare
|
Found 7 test failures on Blacksmith runners: Failures
|
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on e6adb7f to compare; do not merge until green; see lane-rules |
|
Bead |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40458763715 at 9a52a3c failed: cmux-next generated files. |
|
Shipped in:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
The app's native side streams a file's raw bytes to the daemon as WebSocket binary frames: no base64, no size cap, a few frames of memory whatever the file's size. Stacked on #25793 (base is its branch). Contract: #25774, sections 1 and 1b.
Leo: "why the FUCK SHOULD THERE BE A FUCKING SIZE CAP ANYWAYS JUST FUCKING / I ALREADY SAID WE NEED ARBITARRILY LARGE FILES OF ANY TYPE". The spec: files of any type and size stream to disk in chunks, resumable, with progress; bytes never cross the page binding as base64; the peer hop is uncapped and resumable.
Change
src/server/upload_frames.rs, wired into the WebSocket reader inserver/mod.rs:_acpmux/file_put_datarequest:"AMUP", a u32 big-endian header length, the JSON-RPC header{"id", "method": "_acpmux/file_put_data", "params": {sessionId, uploadId, offset}}, then the raw bytes. The answer is an ordinary text response with the same id:{offset}once the bytes are on disk (file_uploads::append, shared withfile_put_chunk), or theupload.*reasons from acpmux: resumable uploads report where they stand, check their bytes, and fail on size only when the disk is full #25793.WINDOW). A sender may keep 4 in flight; past that the socket slows it. Stop condition: the worker ends when the connection's reader ends (its sender drops) or the writer closes.Origin::LocalApp) may send frames. Any other getsfilePut.remoteas its answer, never silence (the original bug was an app bridge that dropped oversize calls unanswered).InFlight: a count and aNotify; the worker releases what it holds when it ends). So a finish, status or prompt sent right behind the last frames sees all their bytes. A connection that sends no frames never waits.file_put_chunkrequests of at most 512 KiB over the peer link, so the peer hop has no cap and resumes the same way (status and finish are forwarded). A peer that does not listfilePutChunksis refused at begin and at every frame, before anything is sent.uploadFrames;_acpmux/file_put_datais in the protocol registry.Risk: contained to WebSocket binary frames, which the daemon dropped before. Text frames take the same path as before, except that on a connection with frames in flight they wait for those frames.
Tests
tests/upload_frames.rs: a 6 MiB file in 1 MiB frames, 2 then 4 in flight, answered in order; the connection drops and a new one resumes fromfile_put_status; a stale frame isupload.offsetwith the resume offset; finish withsha256. A Web connection's frame is answeredfilePut.remote. A peer's chat gets the frames written on the peer, SHA-256 intact.a_finish_right_behind_its_frames_sees_every_byte: a finish sent right behind 5 unanswered frames (3 rounds) gets its answer after every frame's. Before the fix, the finish was answered ahead of 3 frames ([3, 4, 8]against[3, 4, 5, 6, 7, 8]).a_peer_without_chunked_uploads_is_refused_before_anything_is_sent: a peer listingfilePutbut notfilePutChunksis refusedfilePut.unsupportedat begin and at a frame, and gets nothing.tests/prompt_uploads_large.rs(Linux): a 2,000,000,000-byte file of no known type streamed the app's way (1 MiB frames, 4 in flight) to a busy chat, finished with itssha256, named in a prompt, then checked at the path the agent got.Results (
cmux-ci test, 32-vCPU Linux):no answer to request 3 in 20 s; nouploadFramesfeature).c4d9358b27b(run 40440049200): both fail, as above.67d53596666(rebased onto acpmux: resumable uploads report where they stand, check their bytes, and fail on size only when the disk is full #25793's85a0b100709; run 40445691817):upload_frames5 passed,send_attach12,peer_integration47,prompt_uploads_large1,upload_resume3,prompt_uploads8,file_put7,conn_auth3, libfile_uploads/upload_frames/protocol14,hub_integrationprotocol 1,cargo clippy -p acpmux --all-targets -D warningsclean.Not in this PR: the native sender (its owner builds against this), and model-sized copies of large images per harness (next PR).
Agent session: agent session
🤖 Generated with Claude Code