Repository navigation
Agent chat: a failed tool call says what happened in a word and why in one line - #24339
Conversation
…n one line Leo: "we need to have prettier errors". A failed call's row now says blocked, denied, timed out, Exit N or failed in the error tone, and one quiet line under it says why in the tool's own words (a hook's reason, a shell's error line, an MCP server's message) without the JSON or tag envelope. Claude Code's "Exit code N" line becomes the row's Exit N and the Shell block's exit line, so it is said once. Three looks are the tool-error-look experiment (quiet line, on the row, compact card); the quiet line ships. Leo-ask: ask-427cc7d8f5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
|
Owned by cosmic-gray/transcript-parity on cosmic-gray · session |
|
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)
Unclear: CI failed on
Failures:
Matched log linesNot re-run automatically: Written by red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: Tour of Gallery before/after for |
|
Found 41 test failures on Blacksmith runners: Failures
...and 31 more test failures. View all on Blacksmith: run 39897564646, run 39897564708, run 39897564683
|
|
Bead |
|
Review (codex gpt-6.1-sol xhigh): BLOCK at 4e7ac1b
Verification: inspected the supplied diff and surrounding pinned source, including existing output/context/Find tests. Focused parser and React static-render probes reproduced the examples above, with host integrations stubbed; these ran on cmux16 before the huge-blue-only instruction arrived. No further reproductions ran after that instruction. The repository test suite and browser/layout tests were not run. The PR snapshot matched the requested head. |
- A denial is read only from a result with no exit code, anchored at its start; a timeout only from the first or last line; errno codes only in capitals. - The cause skips host-injected context (cleanText), unwraps fences and ANSI before the exit line, reads small JSON whole, and keeps non-Latin words. - Find counts a shell's output as drawn (shellOutput); the red word and the Shell block's exit line are data-find-skip. - A single-call group and a folded run say the failure; the card uses CopyButton. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
|
Review (claude subagent, correctness first): SHIP at 4e7ac1b This is an earlier verdict at the first head, posted for the record. All its findings are fixed in 5351190, and that head gets a fresh review.
|
|
Review (codex gpt-6.1-sol xhigh): BLOCK at 5351190 The five original examples are addressed, including the Unicode and fenced-output fixes. Three correctness gaps remain in the denial, context-cleaning and Find fixes:
Verification: source inspection of the pinned head, fix.diff, pr2.diff, and surrounding tests. No reproductions, Bun commands or tests ran on cmux16 during this re-review. The available workspace |
- claude-agent-acp's "User refused permission" reads as denied. - A lone call is failed by its status or a nonzero exit, as a command row reads it, so its Find index and its drawing agree. - Copy error copies the result as drawn (no colour codes, fence or injected context). - A long cause never splits an emoji; a zero-count summary is never the cause. - The gallery stage is tall enough to show every call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
…; nested MCP JSON errors lose injected context Codex re-review of #24339: a structured refusal or a hook's block is read only from a result with no exit code, and an MCP text block that is itself a JSON error is unwrapped (bounded) and cleaned before it becomes the cause. Find tests cover a completed call with a nonzero exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
From the third review at ca49990 (all low): - a hook's bracketed command stays out of its reason; - Copy error keeps Claude Code's "Exit code N" line; - a call with its own exit code keeps an output line that names another; - lone carriage returns stay, as in a call that worked; - the tail window starts on a whole line; - context before an MCP text block's JSON is cleaned before parsing; - a failed background call shows no cause line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
From the Claude re-review at 99b4875 (both low): - a tail slice with no newline is kept, so an over-long last line is still read; - a line a carriage return redrew reads as its last drawn part. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
|
Review (claude opus-5.5 subagent, correctness first): SHIP at e21c63a This is an independent read-only review of the whole PR, done in three rounds (at ca49990, 99b4875 and e21c63a). Every finding from the earlier rounds is fixed with a test:
Also checked: React hook order, rows that did not fail (unchanged, and no experiment read), regex cost (anchored or bounded to the 4K+4K window, JSON at most 64K), and ToolRow's switch to One nit, not blocking: a tail slice with no newline can start with a lone low surrogate, which would show as one replacement character in an extreme case. |
|
Review (codex gpt-6.1-sol xhigh): BLOCK at e21c63a
|
|
Orphaned: no activity for 12 h, and no lane holds a lease on it. The orphan sweep could not merge |
…view) - Merge base: base already counts a folded run's failures, so ToolRun is base's. - ToolRow: a shell that went on in the background fails only by its status, so it keeps its background mark rather than reading its exit code as a failure (as CommandRow does). - shellOutput: Find counts a shell's output without colour codes, as ShellBlock draws it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
|
Review (claude opus-5.5 subagent, correctness first): SHIP at a6a1d0e This is a read-only review of the base update and the two Codex P2 fixes. The update changes none of the PR's own code:
Both fixes are correct:
One nit, not blocking: for a background Codex shell whose output starts with exactly "Exit code N" matching its own exit code, Find would skip that line while the row draws it. |
- Merge base (#24305's running label on a command row; ours already says Exit N). - rowFailed: ToolRow, CommandRow and Find's shellOutput share one rule, so a shell that ended in the background is drawn and counted alike (Claude review nit at a6a1d0e). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16030-bf28-7072-b1f6-b83bbd0beacc&host=cosmic-gray
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (claude opus-5.5 subagent, correctness first): SHIP at 86a6ab7 This is a read-only review of the base update (c3bdbb8) and the shared
Two consistency nits, not blocking:
|
|
Review (fable-5.1 xhigh, correctness first): SHIP at 86a6ab7 Read-only review of the whole files at the head (ToolRow, CommandRow, ToolGroupRow, ToolRun, McpCallRows, ShellBlock, BackgroundMark, chatFind, toolFailure, ToolFailureCause, toolGroups, toolOutput, mcpCalls, model, TurnRows, conversation.css, both tests) against Both P2s from the e21c63a verdict are fixed, and the base merges changed nothing beyond the PR's own lines. P2 1, background shells. P2 2, colour codes. Merges. Head ToolRow vs base: the only differences are the PR's (rowFailed/failure at 86-89, the failed word at 112-118, the cause at 155, the Shell block's output and exit code at 160-166). Base's "Running {command}" label (82) is kept and BackgroundHint is absent on both sides. Head CommandRow vs base: base's Also checked: Findings, none blocking:
|
|
Shipped in:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo-ask: ask-427cc7d8f5
Leo: "we need to have prettier errors"
This is the first part of that ask: failed tool calls. Turn-level and connection errors come in a follow-up that builds on #24312's turn error card.
What changes
A failed tool call used to show its label, then a dim "failed" (or a red "Exit 1" on a command row). Why it failed was only in the raw result, and you had to open the call to see it: Claude Code's
Exit code 1line over a traceback, a hook'sPreToolUse:Bash hook error: Blocked: …, a long "The user doesn't want to proceed with this tool use…" paragraph, a<tool_use_error>tag, Codex's{"status":"declined"}, or an MCP server's JSON error.Now a failed call has two parts:
The row says what happened in one word, in the theme's error tone:
blocked(a hook refused it),denied(you declined it),timed out,Exit N, orfailed. This applies to lone calls, command rows and MCP rows.One quiet line under the row says why, in the tool's own words without the envelope:
TypeError: …,error: could not compile …);error.message (code)or itsisErrortext;<tool_use_error>;The line is cut to one line. The opened call still has the raw result, and Find in Chat still counts the result rather than this line.
Claude Code's
Exit code Nline is said once. It becomes the row'sExit Nand the Shell block's exit line, so the output in the opened block starts at the real output.The error tone stays on the one word. There is no red block, and the cause uses the transcript's dim text.
toolFailure.tsreads only failed calls, and only the first and last 4,000 characters of a long result. Nothing changes for calls that succeeded.Versions
There are three looks as the
tool-error-lookexperiment, side by side in the gallery entryagent-pane.tool-errors→ Compare arms:line, shipped): the cause on a dim line under the row.inline): no new line; the cause follows the call's words and is cut with them.card): a small glass card with a thin error-tone rail, up to three lines, and Copy error.I picked Quiet line. It keeps a run of calls scannable, it reads like Claude Code's own
⎿result line, and it adds no surface. The card is heavier than a single failed call warrants in a list of calls. The inline look loses the cause on narrow panes, where the label already fills the row. To dogfood another arm, setlocalStorage["cmux.experiments"] = {"tool-error-look":"card"}.Gallery variants:
claude-code(hook refusal, Exit 1 with a traceback, a declined edit, a tool_use_error, a timeout),codex(a declined command, a build that exited 101),mcp(an MCP JSON error, anisErrorresult, a 404 fetch), andexit-opened.Gallery: agent-pane.tool-errors
Before / after
The gallery entry
agent-pane.tool-errorsuses synthetic fixtures only, rendered by the gallery matrix runner (Chromium, 460 px). Before is basefeat-cmux-nextrows; after is this PR's shippedlinelook.line, shipped)The three versions side by side (dark):
line(shipped)inlinecardRelation to sibling PRs
cv-tool__failedclass. Whichever lands second has a one-line conflict.Tests
test/tool-failure.test.tsxcovers:test/tool-failure-find.test.tsxrenders lone and grouped rows in JSDOM and checks that Find in Chat counts exactly what is painted outsidedata-find-skip. It covers anExit code 1result, a failed call that exited 0, and a completed call with a nonzero exit. A mutation check showed it fails without the fix.feat-cmux-next(see below).vp check(format, lint, tsc) is clean.check-type-scaleis ok.Base reds (not this PR)
gallery coverage(2 tests) fails on basefeat-cmux-next:chatFolders.ts,ChatUnavailableStateandDropOverlayhave no entry. None are files in this PR.tooltip-rules.test.tsfails on base: 10 violations, all in files this PR does not touch.Review
Three Codex xhigh rounds and three Claude rounds. Every finding is fixed with a test, and the receipts are in the comments.
Changelog
Size
About 1,070 changed lines: about 650 of code and 420 of tests, plus 396 generated catalog lines: three strings × 21 locales, with non-English entries marked
needs_review. The tests are most of the overage past the 800-line guide. Splitting the classifier from its rows would leave either half without a visible change, so this is kept as one PR.No capture: webview-only. The gallery shots above are the visual.
Agent session: cosmic-gray
🤖 Generated with Claude Code