Agent pane: a guest's held prompt in the pane's model (approvable only from its record)
HOLD: stacked on #26855 (_acpmux/queue_get, lane/mp-queue-get at 68ac4b4f6296), which sits on #26747 (acpmux held prompts). It lands after both; rebase onto feat-cmux-next once they merge, then drop this line. The card UI that uses it is #26742, stacked on this PR.
What
This is the pane model for a guest's held prompt. Leo (2026-10-28), on Theo's T3 Code "Share with guest": "we want to be having, be able to do this kind of flow for CMux multiplayer ... we can work on the agent chat multiplayer." In Theo's flow "each message they send waits for you"; the owner approves each message. Spec: leo-workspace design/chat-multiplayer.md §2 and §4.1; plan manaflow-ai/cmuxterm-hq#4766. It is split out of #26742 (which is now the card UI) to keep each PR reviewable.
THE RULE (direct.ts, Hold): a held prompt is approvable only when the pane holds that prompt's authoritative record for its current revision. That record is a queued / queue_updated record or _acpmux/queue_get. A listing (acpmux's queue list, a 200-character preview) never makes it approvable, whatever its preview looks like. The prompt's text, images, parts and revision always come from that one record. listedRevision is the newest revision acpmux has named anywhere. updating holds until the pane has the record at that revision.
- Queue entries:
awaitingOwner,revision,updatingandlistedRevisiononQueuedPrompt, fromqueued,queue_updated,queue_approvedandqueue_declined, and from acpmux's list (which only names the revision). - Approve and Decline:
answerHeld(promptId, approve, revision)sends_acpmux/queue_approve {sessionId, promptId, revision}, using the revision the card drew, or_acpmux/queue_decline {sessionId, promptId}. - Backfill: when the pane lacks a held prompt's record (an attach page that starts after it), it makes one
_acpmux/queue_getfor that prompt. Reads are keyed by selection generation and prompt id and cleared when the session resets; a read for a selection the pane has left is dropped. This happens only where acpmux's initialize namesqueueGet; without it the prompt staysupdatingand is never approvable. - Features:
queueApprovalandqueueGetcome from initialize's features.queueApprovalis passed on to the snapshot. - Owner's own queued prompt: it still settles its sending bubble on its
queuedrecord. Only held prompts wait forqueue_approved. - Needs you: each held prompt is a "needs you" item, only where
queueApprovalis served. Its one action is Review, which scrolls to the held card (#26742) and focuses it. Needs you never approves from a preview. New stringqueue.held.review, in all 21 locales. - Mock daemon: it answers
queue_approve,queue_declineandqueue_get, and names both features.
Tests
webviews/src/agent-session/acpmux/heldPrompts.test.tsx (model only, no card):
- The client sends
queue_approve {sessionId, promptId, revision}andqueue_declinewith the right ids. - Needs you shows only Review, gated on
queueApproval. Review scrolls to the held card and focuses it. - The owner's queued prompt leaves no sending bubble.
- A listed newer revision never joins held text; an edit past the 200-character preview waits for its own record.
- A stale listing is ignored.
- A cold attach reads the record with
queue_get, with no history paging, and becomes approvable. - Leaving and reopening a chat in the middle of a read (A→B→A).
- Images come from the record.
- A listing never makes a prompt approvable.
- Without
queueGetthe prompt staysupdatingand noqueue_getis sent.
Every one of these was red before the fix it covers, in the review rounds on #26742.
Risk
risk:normal. The change is pane state plus requests that are refused unless acpmux serves them. Nothing changes for chats without guests. On its own (without #26742), a guest's prompt shows as an authored composer-queue row with no actions, and Review has no card to go to.
Changelog
none (the user-visible part is #26742)
Agent session: agent session
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds owner approval for guest prompts in chat multiplayer: a link guest's prompt now waits for the chat's owner to approve or decline it, on both the acpmux daemon and the agent pane.
- New acpmux methods
_acpmux/queue_approve,_acpmux/queue_decline, and_acpmux/queue_get: approve runs the prompt in its queue place at the revision the owner saw (a stale revision is refused), decline drops it, and queue_get reads a held prompt whole for the owner. - A prompt whose author carries
approval: "owner"is queued, never steered in or stopping the running turn, and the queue runs past it until the owner answers. Queue records gainawaitingOwnerandrevision. - Held prompts are never forwarded to or moved onto a peer that does not list the queue approval feature; a held prompt and the owner's answer go only on the link that listed it.
The pane tracks each held prompt by its authoritative record: approvable only when the pane holds that record (queued/queue_updated or a queue_get read) at its current revision, never from a listing. A cold attach lacking the record reads it with one queue_get, gated on acpmux serving queueGet and never paging history via _acpmux/events.
- Needs you lists each held prompt with a single Review action that scrolls to and focuses its card; it never approves from a preview.
- The owner answers with Approve or Decline from the held prompt's card, naming the revision it drew.