Agent pane: a sent prompt or steer never comes back to the composer once acpmux took it

Merged
AU
12d ago
+51-5

Summary

After you send a prompt or a steer to a running chat, the text you sent sometimes reappears in the composer. Pressing Enter then sends it a second time.

Cause: a running chat's send (App.tsx onSend) clears the composer at once. If chat.send later rejects, it calls composerHandle.restore(text), unless the rejection carries a failed row. But that session/prompt request only settles when the turn ends, or for a steer, when the agent reads it. Once acpmux has taken the prompt, its echo settles the pending local-<promptId> row, which deletes it. Any later end of that request then finds no row to mark failed (direct.ts send), so it throws a plain error and the pane restores a prompt that was already delivered and running. Requests that can end this way: the agent's error, a steer's error, or a dropped connection (rejectPending).

Fix:

  • direct.ts tags that error taken.
  • App.tsx keptInChat keeps a failed-row or taken prompt in the chat and never restores it. Its failure belongs to the transcript.
  • A queued prompt that acpmux refuses when its turn comes never ran, so it is not tagged, and its existing give-back is unchanged.

Testing

Regression test: two cases in webviews/test/agent-pane-steer.test.ts (browser lane). The stand-in acpmux echoes a steer and then either answers it with an error or drops the connection. The test asserts the composer stays empty, exactly one steer went out, and no failed row shows.

Focused command: CMUX_BROWSER_TESTS=1 bun test ./test/agent-pane-steer.test.ts from webviews/. On the test-only commit 278206455a6f it should fail (the composer gets the steer back); on the fix head 1b3f33a9dd1e it should pass.

Observed / Not run

  • Observed: hosted CI at head 1b3f33a9dd1e, web / react-apps-check, run https://github.com/manaflow-ai/cmux/actions/runs/40058912383. PASS test/agent-pane-steer.test.ts (browser lane), in attempt 1 shard 4 and again in attempt 2.
    • Attempt 1 flagged two reds not on the base, both timing-shaped and in tests that never send a prompt: agent-pane-older-rows-fade (Reduce Motion) and gallery-agent-pane-entries artifact-panel#versions (waitFor did not hold within 5000 ms).
    • A rerun of the failed jobs on the same SHA (attempt 2) made all four shards and web / react-apps-check green.
  • Observed: the remaining reds also fail on merged peer PRs https://github.com/manaflow-ai/cmux/pull/24715 and https://github.com/manaflow-ai/cmux/pull/24692, so they are base reds: health (0-3), cmux-next checks, defaults-snapshot, release-notary, Guard status.
  • Observed: scripts/web-lint.sh type check is clean on the head. Its remaining reds are base debt in untouched files: check:design-tokens, check:text-focus, and warning-only vp lint.
  • Observed: independent correctness-first review subagent: SHIP. Its one real finding is fixed in this head.
  • Not observed: the red run. The focused test on the test-only commit 278206455a6f was submitted as fleet step 527b208641cdd81a4a9252d2 (green as 0c41657f06287c602229826e). The authoring host is outside the tailnet and could not read either result, and Freestyle had no key there. The red is argued from the code path (review comment above), not observed.
  • Not run: a tagged dev build. The change is webview-only and the test drives the real agent pane.

Changelog

Fixed: A prompt or steer sent to a running chat no longer reappears in the composer when its turn ends in an error or the connection drops

Proof

No capture: behavior fix with no visual change; the browser-lane test is the proof.

šŸ¤– Generated with Claude Code