Repository navigation
acpmux: send --attach and send_message take files of any size and number, by reference - #25840
Conversation
|
Owned by an agent session · session |
|
Bead |
This comment has been minimized.
This comment has been minimized.
…ned references (#25840) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
b2a3d10 to
77fdf1a
Compare
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 0f8696c to compare; do not merge until green; see lane-rules |
|
|
…ompt links to by path Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
|
Found 8 test failures on Blacksmith runners: Failures
|
… peer's linked upload is kept too Test: prompt_uploads a_link_names_its_upload_on_any_platform (fails on f6a414c). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
#25840 made a forPrompt upload removable only by a cancel carrying its ownerToken, and made upload.owned carry that token instead of true. The contract doc still described the earlier shape. It now says what begin returns, what cancel removes, what owned's value is, and the app's path: begin forPrompt, keep the token natively, leave owned out of prompt refs. Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Shipped in:
|
…ase red) Same change as #26087, combined here because each is red on the other's red: check-state-roots counts the inline test module's /home/me/.acpmux/... fixture (since #25840). upload_ids reads only the parent folder, so the test is the same. Test: bash scripts/cmux-next/check-state-roots.sh .: exit 1 on the base, ok here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
check-state-roots (baseline 0) flags the fixture path /home/me/.acpmux/uploads/... added by #25840. The test checks that a link names its upload by the parent folder on any platform; the root's name plays no part (upload_ids reads the second-to-last path segment), so a neutral root keeps the test's intent. Agent-Session: https://cmux.com/deeplink/agent?id=aid-6ccd4e4ea4a1d1f1ddd4 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* docs(next): the Cloud start-session highlight links its docs (release-notary red on base) test_the_repository_highlights_validate fails on every feat-cmux-next PR: the highlight from #25625 has no tryIt action or docs link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(nightly): read the legacy publish job with its moved step scripts inline #25879 moved "Generate the old feed's appcast" into scripts/ci/nightly-steps/legacy-identity-appcast.sh, so test_the_appcast_comes_from_the_tested_plist no longer found its commands in nightly.yml (ValueError: substring not found) and release-notary went red on feat-cmux-next. Read the workflow through nightly_workflow_text.nightly_text(), as the other nightly workflow tests do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(nightly): leave test-execution.toml as on the base The pre-commit hook registered two base tests that this PR does not touch; keep this PR to the two red fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release notes: two new fixed highlights get their Try it action (base red) home-composer-border (#26119) and selected-harness-start (#26106) landed with neither an action nor a docs link, which scripts/whats-new/validate.py requires, so release-notary's test_the_repository_highlights_validate is red on feat-cmux-next. The Chief field one opens Home; the harness one starts a new agent chat. Test: python3 scripts/whats-new/test_digest.py: 1 failure before, OK after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * nightly: the Sparkle key test reads nightly.yml with its moved steps inline (base red) #26196 and #26210 moved two of the four SPARKLE_PRIVATE_KEY="$(./scripts/ci/nightly-sparkle-key.sh)" call sites into scripts/ci/nightly-steps/, so the raw workflow has two and tests/test_nightly_sparkle_key.sh (release-notary) fails its at-least-three check. It now greps nightly_workflow_text.nightly_text(), the expansion the other workflow tests read. Test: bash tests/test_nightly_sparkle_key.sh: FAIL on the base, PASS here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next routing: a test's home-folder Claude settings path is not a repository read (base red) CloudCredentialTransferTests named ".claude/settings.json" under a temp home in one literal; ci-target-graph.py found the repository's own file at that path and listed it as a CmuxNextAppTests read (base autofix c14a002), which cmux-next.yml's pull_request paths do not cover, so Tier routing's test_every_routed_input_triggers_the_workflow is red on feat-cmux-next. The test builds the path from folder and file, and the graph loses the read (literal_reads recomputed: the target's other 14 reads are unchanged). Test: python3 tests/test_cmux_next_route.py: 1 failure on the base, OK here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: the upload-link test names no literal ~/.acpmux state root (base red) Same change as #26087, combined here because each is red on the other's red: check-state-roots counts the inline test module's /home/me/.acpmux/... fixture (since #25840). upload_ids reads only the parent folder, so the test is the same. Test: bash scripts/cmux-next/check-state-roots.sh .: exit 1 on the base, ok here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: collapse the Codex broker's account checks into let chains (clippy base red) #26191 nested two if-lets in codex_auth_broker.rs; clippy -D warnings (collapsible_if) fails on it for every PR that touches acpmux. Same checks, one let chain each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release notes: the compact thought-row highlight gets its Try it action (base red) #26270 added it with neither an action nor a docs link, so release-notary's test_the_repository_highlights_validate is red again. Test: python3 scripts/whats-new/test_digest.py: 1 failure before, OK after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tests: leave test-execution.toml as the base has it The pre-commit hook registered unrelated tests while committing the base merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next tests: drop the settings-path split; the graph skips .claude paths itself #26248 made ci-target-graph.py ignore .git, .claude and .codex paths a test names, so the one-literal form no longer routes CmuxNextAppTests on the repository's settings file. Back to the base's line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(next): the Cloud start-session highlight links its docs (release-notary red on base) test_the_repository_highlights_validate fails on every feat-cmux-next PR: the highlight from #25625 has no tryIt action or docs link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(next): give the two base highlights release-notary rejects a live action feat-cmux-next's inline-pr-pills and inspector-error-colours highlights have no action or docs line, so scripts/whats-new/test_digest.py (release-notary) fails on the base. Use existing palette actions rather than https://cmux.com/docs/agents, which returns 404. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(next): give the new Find in Chat highlight a live action (release-notary red on base since 93ff53c) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Leo <cheerleaderleo@outlook.com>
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo, 2026-10-26: "why the FUCK SHOULD THERE BE A FUCKING SIZE CAP ANYWAYS JUST FUCKING / I ALREADY SAID WE NEED ARBITARRILY LARGE FILES OF ANY TYPE"
Base
feat-cmux-next. It builds on #25793 (resumable uploads,upload.diskFullwith host and path, merged as e6adb7f).After #25730 the prompt path had no cap, but
acpmux send --attachand cmux-subsessionssend_messageattachmentsstill refused a message: 8 MiB a file, 10 MiB and 16 files a message, and "one message is at most 15 MiB" (attach.rs).Change
The senders (
attach::blocks_for) never refuse a file for its size or their number:fits_inline: at most 16 files, each at most the inline image size of 3.75 MiB, 10 MiB together, and the whole message as base64 within one JSON-RPC message). Old receivers keep working for these._acpmux/file_put_begin/_chunk/_finish(512 KiB chunks read from disk as they go, so memory stays flat), and the prompt names it by reference (acpmux: a prompt names its files as uploads, of any size, by reference #25730). The daemon that runs the chat puts an image the agent can take inline and gives every other file, and an image too large to show, by its path. A failed upload is cancelled.promptUploads; if it does not, the error names its build and says to restart it. The begin carriesforPrompt: true, which a peer withoutpromptUploadsrefuses (upload.unsupported). So no upload is left behind for a prompt that would be refused,--no-waitincluded.file_put_cancelwithownerTokendeletes an upload begun for a prompt whole, finished or not, and only with the matching token, here or through a peer. Any other upload is cancelled only while unfinished, as before.file_put_beginwithforPromptwrites a random token to the upload's.ownerfile and answers it asownerToken. The sender's references carry it in_meta.acpmux.upload.owned, and only an upload whose.ownermatches counts as the prompt's own (file_uploads::owned_dir). So a reference can't mark someone else's upload as its own, andowned: truedeletes nothing. The tokens are read off the runtime. The daemon deletes owned uploads when the prompt is refused before the chat takes it:OwnedUploadscovers the checks, andSavedcovers the chat's own refusal or an unanswered drop. A prompt the chat takes, a duplicate, and a held prompt keep them./and\alike, so a Windows peer's path counts too), whatever the spelling of its id, and each cancel carries the owner token.held_dirs). They are deleted when the held message is dropped, or when its release never ran.file_uploads::remove_uploads).send_messageasks the daemon first (_acpmux/subsession/sendwithattachCheck: true), so it reads no path for a send that would be refused.subsession_sendrefuses any attachments from such a caller withattach.remotebefore it reads or resolves them, andreceive/resolveget the caller's Web state. This closes a hole that is already on base:send_messageread a path as the agent's own user and sent it inline, withweb=false.acpmux sendand the MCP server send from an agent's environment (server/requests.rscaller_sends_no_files). It refusesattach.remoteforsession/promptand_acpmux/send_queue(the--no-waitoutbox) with file or upload-ref blocks, and for the upload calls (file_put,_begin,_chunk,_finish,_cancel).send_messagewith an emptyattachmentslist is a text message and skips the check. Soacpmux send --attachfrom such an agent's shell uploads and sends nothing. The CLI's attach errors now carry their reason.peer/id).send_messagesends the reference blocks too:_acpmux/subsession/sendaccepts them and resolves them before the receiver's turn (hub/subsession_send.rs), assession/promptdoes.On the receiving side the
MAX_FILE_BYTES,MAX_MESSAGE_BYTESandMAX_FILESrefusals are gone (check_sizesdeleted).check_wirenow checks only that a raw protocol request with inline files fits one JSON-RPC message on the next hop, so it gets an answer instead of being dropped by a hop. Neither sender can reach that check, since both switch to references first. Its message now says to send the files as uploads.The
send_messageschema losesmaxItemsand the cap sentence.--attachhelp, the README and the skill say "any size and number".Not in this PR: the app composer's own attachment limit (
home.composer.attach.tooMany, Swift), which belongs to the composer owner.Risk: contained to sends with attachments. Small attachments take the same inline path as before. Larger ones need the receiving daemon to resolve references (#25730,
promptUploads). An older peer is refused withupload.unsupported, naming the peer andacpmux host update, where before it was refused for size.Tests
send_attach_cli.rssend_attach_sends_files_of_any_size_and_number_by_reference, against a real daemon:acpmux send --attachwith a 24 MiB binary, a 6 MiB PNG and 20 screenshots (22 files). The screenshots reach the agent as images; the binary and the large PNG arrive asresource_linkwith their paths. SHA-256 is intact and the files are owner-only.send_attach.rsa_peer_that_does_not_save_attachments_is_refused_before_anything_is_sent: a begin withforPromptto a peer withoutpromptUploadsis refusedupload.unsupportedand reaches nothing; a plain begin still goes. It fails on the previous head281386808ce(run 40439544930).send_attach.rsa_refused_prompt_leaves_none_of_its_own_uploads_behind: covers a prompt refused by its checks, one the chat refuses (steer.unavailable), one that runs (which keeps its upload), and a cancel of a finished upload. It fails on its parent7393c04a7ad(run 40445698527).send_attach.rs: inline files past the old caps (8 MiB + 1, two halves of 10 MiB, 20 files) are saved, including through--no-wait(outbox) and to a peer's chat. A web client still cannot attach.send_attach_family.rs: a 6 MiB PNG uploaded to a child and sent by reference throughsubsession/sendreaches its agent by path, bytes intact.send_attach.rsa_withdrawn_queued_prompt_leaves_none_of_its_own_uploads_behind. Units:a_taken_prompt_that_never_ran_leaves_none_of_its_own_uploads, anda_held_message_keeps_its_files_until_it_is_dropped_or_its_release_never_ran, which now carries an owned upload. All three fail on 77fdf1a (run 40452127624).subsessions_safety.rsan_agent_a_web_turn_drove_cannot_send_files_with_a_message: an inline file, an upload reference and theattachCheckare all refusedattach.remote, and nothing reaches the child. Before the fix the inline send was accepted and started a turn in the child (run 40459662099).subsessions_safety.rsan_agent_a_web_turn_drove_sends_no_files_from_its_shell_or_its_toolsruns theacpmuxbinary as that agent, with its caller token:acpmux send --attachwith a small file (inline), a 5 MiB file (by upload) and--no-waiteach fail with the remote-device reason;acpmux subsession-mcpsend_messagewith a path that does not exist answers theattach.remoterefusal, not file-not-found, so the path is never read;On the previous head
e19104ef2cbthe inlineacpmux send --attachsucceeded (run 40465938084).send_attach.rsa_refused_prompt_leaves_none_of_its_own_uploads_behindalso sendsowned: trueand a wrong token for an existing upload: the upload stays. A cancel with no token or a wrong one leaves a finished upload, and one with its token deletes it.a_cancel_through_a_peer_deletes_only_with_the_owner_tokenchecks the same through a peer link.send_attach.rsa_repeated_queued_send_deletes_only_its_own_new_uploads: a repeat of a deliveredsend_queueprompt id deletes the upload it began. It keeps the delivered prompt's upload, even named in upper case, an upload it names with a forged token, and an upload the delivered prompt links to by path. With the link not counted, it fails (run 40470385633).subsessions_safety.rs:send_messagewithattachments: []from the Web-driven agent is sent as a text message.e5eeb6e9401(tests only, run 40469083026) all four new checks fail: the cancel without a token deleted the upload (here and through the peer), the repeat deleted the delivered prompt's upload, and the empty list was refused.small_files_go_inline_and_the_rest_by_reference(each threshold; every inline message the senders make passescheck_wire).Results (
cmux-ci test, 32-vCPU Linux):edc86435fa5, test commit only; run 40433931184): 5 failed.send_attach_cli:22 attachments: a message takes at most 16.send_attach: 3 (past the old caps, queued, peer).send_attach_family: the by-reference block is refused as not an attachment.a_link_names_its_upload_on_any_platform: a POSIX path and a Windows path each name their upload. Onf6a414c2f74the Windows one is missed (run 40472624765).a0de7dc2085: fmt, clippy, the prompt_uploads units and send_attach pass (run 40472623355).f6a414c2f74, which differs only in that function, passes the full acpmux suite except the six base failures (run 40471492169), and the attach, upload, outbox and Web-turn tests (run 40470388422).474370107ab(run 40469087813, full acpmux suite, fmt and clippy): fmt and clippy are clean, and every attach, upload, prompt-upload and Web-turn test passes. The only failures are the six that fail the same way on base9c6435d(run 40453283684):own_servers_run_under_the_daemon_prefix,hermetic_daemon_guard×2,daemon_chat_open,ephemeral_run,pooled_sessions_end_with_the_daemon_and_after_a_crash.Size: 654+/144− in source and 485+/55− in tests. That is over the usual 800 lines, because the review rounds added the owned-upload lifecycle, its owner token and the Web-control fix. The fix changes the same
subsession_sendlines, so it could not land on its own.Agent session: agent session
🤖 Generated with Claude Code