Skip to content

cmux NEXT agent pane: a prompt a dropped connection lost goes again, no "Not sent" (lost-prompt replay on) - #32389

Merged
teamleaderleo merged 2 commits into
feat-cmux-nextfrom
lane/lost-prompt-resend
Nov 2, 2026
Merged

teamleaderleo merged 2 commits into
feat-cmux-nextfrom
lane/lost-prompt-resend

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Leo, about a chat that said "Not sent: The agent connection was interrupted. Read its saved state before retrying." while the agent was alive:

why does it say it's not responding? also you previously weren't running???

Leo-ask: ask-7877c9aa95

What was wrong

When acpmux's connection drops while a prompt is still on its way (an acpmux restart or a daemon update mid-send, a reset socket), the pane's pending session/prompt is rejected with "The agent connection was interrupted". The agent itself was fine. Then:

  • A prompt its composer still held (a new chat, the Quick Composer, a View Only chat) showed "Not sent: The agent connection was interrupted. Read its saved state before retrying." at once and stayed in the composer.
  • A started chat's prompt left the transcript and silently came back to the composer, so it had to be sent again by hand.

#23027 built the fix's parts: the host's prompt journal sends such a prompt again on the next connection, under its promptId and marked resend so acpmux runs it at most once, and the page has hooks to wait for it. But the replay stayed behind a Debug toggle that was off, and the page never waited. The other line in Leo's screenshot, "Permission groups are disconnected. Refresh before answering.", is already gone on base. #23027 made the permission panel wait quietly for the reconnect attach, and that string has no callers left.

What changes

  • AgentPaneTunables.lostPromptReplay is on by default (schemas/defaults/cmux-next.json follows). The host journal sends a prompt the daemon dropped with its connection again on the next one. The Debug toggle stays, so it can be turned off.
  • direct.ts: a prompt lost with its connection before acpmux took it, on a connection to this Mac's acpmux and small enough for the journal (8 MiB), carries lostPrompt {sessionId, promptId}. A held sender's immediate "Not sent" notice is skipped for it.
  • lostPrompt.ts: resentAfterLoss waits on the pane's next connected client for the prompt to show there. It reuses the existing waitForResend and awaitResent, waiting 30 s for a connection and 10 s for the prompt to show.
  • App.tsx: the established-chat send and the held send both wait for that before giving the prompt back. If it shows, the send counts as delivered (promptLanded), and the held composer lets go of it. Only a prompt that never shows comes back to the composer, with the "Not sent" line, the same way as before.

No new Swift logic: the Swift change is a default flip and two comments.

Risk

This changes how an agent-pane send recovers from a lost connection. When the wait gives up (no reconnect within 30 s) and the journal later sends the prompt after all, a person who edits the returned prompt and sends it gets a new promptId. That is the same edge #23027's reviews found. It is an edge of the new behaviour, filed as a follow-up. A remote-origin connection, which has no journal, and a prompt over 8 MiB keep today's behaviour.

Tests

  • lostPrompt.test.ts adds a prompt the connection lost before acpmux took it waits for the host's resend, never 'Not sent' at once. It uses a mock acpmux whose socket drops as the prompt reaches it. With base direct.ts swapped in, it fails (lostPrompt undefined; the notice is drawn). With this change, it passes.
  • resentAfterLoss is covered for each outcome: the prompt shows, a connection comes back but the prompt never shows, no connection comes back, and a refusal that is not a lost prompt.
  • Fleet fast checks at 71a596db: webview lint 0/0, typecheck clean, fmt clean. lostPrompt.test.ts, agent-pane-connect-disconnect.test.ts and src/agent-session/acpmux/conversation give 761 pass and 1 fail. The failure is BackgroundMark.test.tsx "only Open in terminal…", which this PR does not touch.
  • cmux-ci compile-check --app at 1d5a4d1c passed. The Swift diff is the same at the head. The existing AgentPaneUnsentPromptTests replay test runs both arms of the toggle.

Agent session: agent session

🤖 Generated with Claude Code


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


Summary by cubic

Fixes a lost agent-pane prompt showing "Not sent: The agent connection was interrupted" while the agent was fine. When acpmux's connection drops mid-send (a restart, an update, a reset socket), the host's prompt journal now sends the prompt again on the next connection and the pane waits for it to show there instead of saying "Not sent" at once. The lostPromptReplay debug toggle is now on by default.

  • A held send (a new chat, the Quick Composer, a View Only chat) waits 30 s for a reconnect and 10 s for the prompt to show; only one that never shows says "Not sent" and comes back to the composer.
  • A started chat's lost prompt is treated the same and no longer silently returns to the composer.
  • Remote-origin connections and prompts over 8 MiB are not journaled and keep today's "Not sent" behavior.
  • Known edge: if the wait gives up but the journal sends the prompt later, editing the returned prompt and re-sending it creates a new promptId (filed as a follow-up).

Written for commit 71a596d. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits November 2, 2026 14:10
…no "Not sent"

The host's prompt journal sends a prompt the daemon dropped with its connection (an acpmux
restart or update mid-send) again on the next connection, under its promptId, now on by default.
The page waits for it to show there instead of saying "Not sent: The agent connection was
interrupted" at once and handing it back; only one that never shows says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-140531107322b17b78f0
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 71a596d: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr32389 -f ref=lane/lost-prompt-resend -f platform=macos -f backend_mode=local

Gallery before/after for 71a596d: 16 states rendered, 0 images differ, 2992 more touched states not rendered. Images are in the run's artifact, not on this public PR; the independent review of this head reads them on its own, so the PR needs no hand-made screenshots of these states.

gh run download 41464870638 -R manaflow-ai/cmux -n gallery-advisory-32389-71a596db3fad2532c3961d656ed994362f615de8 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.chat-width/standard Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/standard Apple System Colors unchanged 0% own App.tsx
agent-pane.chat-width/wide Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/wide Apple System Colors unchanged 0% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-edge/short-edge Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-edge/short-edge Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-edge/wide-edge Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-edge/wide-edge Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-edge/no-edge Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-edge/no-edge Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-floats/scrolled-to-end Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-floats/scrolled-to-end Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-floats/composer-grown Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-floats/composer-grown Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-40 Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-40 Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-56 Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-56 Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-72 Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-72 Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/shipped Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/shipped Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/two-thirds Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/two-thirds Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/half-tucked Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/half-tucked Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/before Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/before Apple System Colors unchanged 0% own App.tsx
agent-pane.copy-controls/output Apple System Colors Light unchanged 0% own App.tsx
agent-pane.copy-controls/output Apple System Colors unchanged 0% own App.tsx

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

Default changes

This pull request changes 2 defaults at 71a596db3fad (what everyone gets without configuring anything):

  • tunable-source.CmuxNextAgentPane/AgentPaneTunables.swift:lostPromptReplay: "6a00138d5bed6d62100d6392e672bdba9ed1d2ad0a5f049eaeeda421d2cd2d97" -> "2c31be0b94d7b46601841d2c4a2c2003756e25be45010520737622cca68c9e74"
  • tunable.agentPane.debug.lostPromptReplay: false -> true

Signed off on this commit by review (codex, router-review).

Merge receipt: merged as d33fc9e423ec with these defaults changed, signed off by review (codex, router-review).

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

Shipped in:

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at 71a596d

Reviewer: codex gpt-6-astra high, fast tier.

Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward.

SHIP at 71a596d

Visual verdict: no images; Leo tries the build

  1. [P1] [follow-up] webviews/src/agent-session/acpmux/App.tsx:13501 — A successful journal replay never resolves the Quick Composer’s taken promise. The original turn rejection also calls cancelOpenInWindow(), so startInBackground() remains pending and the replayed prompt never opens the background chat. Replay success must trigger the same accepted/landed path as a normal send.

  2. [P1] [follow-up] webviews/src/agent-session/acpmux/App.tsx:13440 — If no replacement connection appears, directClient.current is cleared by the disconnect handler. After the replay wait expires, giveBack() restores the prompt but the optional notice() call is skipped, leaving the user without the promised “Not sent” explanation. Retain a notifier or render the notice independently of the active client.

Follow-ups:

  • [P1] [follow-up] Resolve Quick Composer handoff state when a replayed prompt lands.
  • [P1] [follow-up] Preserve the “Not sent” notice when reconnect never succeeds.

@cmux-bot cmux-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmux-bot approves 71a596d: an independent review passed this exact head (router-review receipt by teamleaderleo). A push needs a new review; a later BLOCK at this head dismisses this approval.

@teamleaderleo
teamleaderleo merged commit d33fc9e into feat-cmux-next Nov 2, 2026
210 of 223 checks passed
@teamleaderleo
teamleaderleo deleted the lane/lost-prompt-resend branch November 2, 2026 15:53
teamleaderleo added a commit that referenced this pull request Nov 5, 2026
The base removed the journal's size and entry caps (#33145) and the
byDaemon close (#32389, #36333): record drops its too-large branch and
trim, and the two write-race tests use a forget on another thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-a57dc6a4e0ad73610b3a

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 71a596db Deployed Nov 2, 2026 by teamleaderleo via namespace autofix #12504
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant