Skip to content

fix(agent-chat): surface a rejected send on the transcript branch - #16216

Merged
teamleaderleo merged 2 commits into
mainfrom
fix/agent-chat-transcript-send-rejection
Sep 30, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
fix/agent-chat-transcript-send-rejection

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #16121. That PR made send reject where it previously did not: the Pi adapter now throws pi process changed during startup rather than writing a prompt to a process that never received its setup. One of the three sendPrompt call sites does not handle a rejection.

agent-chat/server.ts on the transcript branch was:

if (sess.transcript) {
  // Typed into the terminal's agent; the transcript records the prompt.
  void sess.adapter.send(sess, prompt);
  return;
}

A rejection there became an unhandled rejection with no feedback: the user's message vanished and the UI kept waiting. The other two call sites already catch, log and emit an error event.

The fix catches it and emits the same sanitized error event those two use. There is no turn generation on this path (the transcript records the prompt, so nothing was allocated), so there is nothing to unwind and no done to emit.

The test drives sendPromptForTest with a transcript session whose adapter rejects, and asserts both halves of the contract: an error event is emitted, and no unhandledRejection fires. It landed in its own commit first and fails on main:

error: a rejected transcript send must emit an error event: []

After the fix, transcript send rejection assertions passed.

One thing this deliberately does not change. safeReason is an allow-list, so pi process changed during startup maps to unexpected error and the user reads Failed to send message: unexpected error. The test asserts that exact string, because it is the shape the other two call sites already produce. Making the startup-race reason legible would mean widening safeReason, which is a policy call about what adapter text is allowed into the UI, and it belongs in its own change.

Validation, from agent-chat:

  • ./node_modules/.bin/tsc --noEmit, clean
  • bun run-tests.ts, 115 pass / 0 fail / 269 expect() calls, 39 scripts and 18 bun:test files, exit 0

Correction to something I wrote on #16121: I said the server half of server.ts had no test harness. It does. sendPromptForTest has been exported since before this work and test/server-utils.test.ts already uses it, which is what this test is built on.

🤖 Generated with Claude Code


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


Summary by cubic

Follows up on #16121, where the Pi adapter started rejecting send when its process changes during startup (pi process changed during startup). The transcript branch of sendPrompt dispatched with a bare void sess.adapter.send(...), so a rejection became an unhandled rejection and the user got no feedback — the message vanished and the UI kept waiting. The other two call sites already catch, log, and emit an error event.

The fix catches the rejection and emits the same sanitized error event those two call sites use. There is no turn generation on this path (the transcript records the prompt), so there is nothing to unwind and no done to emit.

Bug Fixes

  • A rejected transcript send now emits an error event and leaves no unhandledRejection.
  • Adds a test driving sendPromptForTest with a rejecting adapter that asserts both halves of that contract.
  • The message stays Failed to send message: unexpected error because safeReason is an allow-list; widening it is deliberately left out of this change.

Written for commit 47cfced. Summary will update on new commits.

Review in cubic

teamleaderleo and others added 2 commits September 30, 2026 13:33
sendPrompt dispatches transcript prompts with `void sess.adapter.send(...)`,
so an adapter rejection becomes an unhandled rejection and the user sees
nothing. The other two call sites already catch, log and emit an error event.
This fails on main.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A transcript chat view dispatched prompts with a bare `void`, so an adapter
rejection was an unhandled rejection and the user got no feedback. Catch it,
log it and emit the same sanitized error event the other two call sites use.
There is no turn generation on this path, so nothing to unwind and no "done"
to emit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@teamleaderleo
teamleaderleo enabled auto-merge (squash) September 30, 2026 20:36
@coderabbitai

coderabbitai Bot commented Sep 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 2 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 892d9361-84bc-4aee-a263-83b590ca927a

📥 Commits

Reviewing files that changed from the base of the PR and between b3ca418 and 47cfced.

📒 Files selected for processing (2)
  • agent-chat/server.ts
  • agent-chat/test/server-transcript-send.test.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@teamleaderleo
teamleaderleo merged commit 90d2fb9 into main Sep 30, 2026
55 of 60 checks passed
@teamleaderleo
teamleaderleo deleted the fix/agent-chat-transcript-send-rejection branch September 30, 2026 20:48
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 47cfced855: every check was green at merge (10 verified; 14 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 30, 2026
5e83d80 Keep agent mode controls reachable and respect disabled choices (manaflow-ai#15971)
24f1ee0 fix(codex): arm the transcript monitor's watch before it reads (manaflow-ai#15913)
17f370e fix: pass the action reference for untrusted setting tab-bar buttons (manaflow-ai#16223)
5e33b84 Agent messages that never land in a human's draft: cmux agent message (manaflow-ai#15279)
522ba05 fix(sidebar): replay agent runtime changes for late observers (manaflow-ai#15829)
3016cf3 Fix browser state helper package convention (manaflow-ai#16205)
b1fd787 Preserve agent Stop completion before session teardown (manaflow-ai#16122)
7ba9740 Prevent duplicate pool VMs after lost create responses (manaflow-ai#15946)
e6e6982 Keep Cloud agent chat recoverable when browser storage fails (manaflow-ai#15968)
d8f62dc fix(ci): production-secret jobs run only from protected refs (manaflow-ai#16171)
8aa9b5c fix(agents): isolate OpenCode workspace auto-naming (manaflow-ai#16210)
7bce471 Add cmux agent hibernate and wake (manaflow-ai#15308)
90d2fb9 fix(agent-chat): surface a rejected send on the transcript branch (manaflow-ai#16216)
d01e8ce fix: list setting actions in Actions discovery so main compiles (manaflow-ai#16222)
b3ca418 Serialize Pi Agent Chat startup before prompts (manaflow-ai#16121)
75650a8 fix: end CodeRouter sessions on team removal; fresh auth for presence mutations (manaflow-ai#16169)
1831681 fix(web): refuse to publish the Cloud VM daemon port (manaflow-ai#16144)
258c2ee Let remote workspaces use cmux agent message through the SSH relay (manaflow-ai#15863)
3b196d0 Merge pull request manaflow-ai#16160 from manaflow-ai/ci/failfast
f02bdec Fix browser state restoration ordering (manaflow-ai#16204)
2fdf7d0 fix(coderouter): pin the OpenCode provider address per request (manaflow-ai#16165)
aaebb18 Fix Cmd+I notifications popover anchor (manaflow-ai#14582)
ef3e658 Preserve valid Claude hook sessions after decode drift (manaflow-ai#16196)
a0660ce test: avoid fixed cancellation delay
6e997e2 Fix narrow pane tab close UX (manaflow-ai#15957)
a018381 ci: run process tree regression in guard preflight
723bbe6 fix(ci): bound artifact fallback at workflow call sites
7cbc73e test: require caller bounded artifact downloads
6120003 fix(ci): retain artifact download action
c801205 test: keep artifact fallback action wired
c1f0509 docs: record overstay evidence and bounded transfers
e91d51b fix(ci): bound artifact download fallback
a2679ce test(ci): require bounded artifact fallback transfer
ef447e2 ci: bound process tree reaping after kill
8f342fc test: bound process tree reaping
5d7af99 test: update cancellation guard expectations
984bf0c Merge remote-tracking branch 'mf/main' into ci/failfast
2c47268 Merge commit '57fd5ac4df7641c05eb73df76fe3554a2a604264' into ci/failfast
83998ac ci: skip cancelled iOS status rollup
bd5692e ci: stop leaking cancelled test processes
55a1003 ci: reap detached processes on cancellation
0351680 test: bound cancellation cleanup for stubborn CI children
bfe79f1 test: cover CI cancellation process cleanup
f20c7d3 ci: cancel useless downstream work
fd0a123 test: require job-scoped CI fail-fast cancellation

# Conflicts:
#	.github/workflows/ci-guards.yml
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci-web.yml
#	.github/workflows/ci.yml
#	.github/workflows/cmux-tui-artifacts.yml
#	.github/workflows/ios-app-store.yml
#	.github/workflows/ios-appstore-upload.yml
#	.github/workflows/ios-testflight.yml
#	.github/workflows/iroh-release-gate.yml
#	.github/workflows/nightly.yml
#	.github/workflows/release.yml
#	.github/workflows/repair-nightly-appcast-content-types.yml
#	.github/workflows/repair-v0-64-25-helper-rpaths.yml
#	.github/workflows/test-e2e.yml
#	.github/workflows/test-ios.yml
#	.github/workflows/update-homebrew.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant