agent pane: a failed turn shows an error card with its cause and way out
Leo-ask: ask-427cc7d8f5 (error card, relayed by claude-sr2)
Leo: "we need to have prettier errors" and "we also wanna make sure we have good recoverable/informative disk errors tailscale erros for acpmux".
What changes
A failed turn showed acpmux's bare agent process closed above an outlined Copy error button. Now a failed turn draws one card:
- Cause: one human line (failureCopy.ts). The new kinds are:
- Disk full:
ENOSPC,no space left,disk quota exceeded. - Tailscale:
tailscale,tailnet,*.ts.net. - Agent quit mid-turn: acpmux's
agent process closed, an exit code or signal, a broken pipe. - Agent couldn't start: a spawn
ENOENT,command not found. - Anything unnamed: reads " ran into a problem and stopped." The agent's raw words are never the sentence any more.
- Precedence: stderr that names a cause (529,
ECONNREFUSED) still wins over "it quit".
- Disk full:
- The way out first: a filled Retry for whatever may pass, or Switch model for capacity, key and proxy failures. Sign in again stays in the footer, as before.
- Details opens the agent's own words, with Copy error.
- Typed errors: acpmux's typed reason, the turn result's
errorCodewhen it is a string, now reaches the row and wins over the text. The mapping matches words (disk/no_space,tailscale,peer/unreachable,spawn,exit/closed), so the codes acpmux-unify is adding (disk, tailscale, peer, spawn) map without a second change here.
Versions
There are three versions as the turn-error-card experiment: Glass card (ui-glass), Accent rail and Quiet note. They sit side by side in the gallery entry agent-pane.turn-error-card → Compare arms. The variants cover Leo's "agent process closed", disk full, Tailscale, a typed disk.full, spawn failure, rate limit, unknown, and Details open. I picked Glass card as the shipped default: it reads as the turn's answer, the way out is the one filled button, and it uses our glass. To dogfood the other arms, set localStorage["cmux.experiments"] = {"turn-error-card":"rail"}.
Follow-ups (not in this PR)
- "Open Tailscale" and "Free space…" buttons. The pane has no native call to open an app or a Settings pane yet (
app.actiononly runs New Tab omnibar actions), so those need a small native handler; that is its own PR. Until then the cause line says what to do and Retry is the way out. - The Continue button (Leo: "and we should add a continue button if things were stopped, just like codex") is the next PR, folded into this card.
Size
About 570 lines of code and tests. The 660 catalog lines (five strings × 21 locales, non-English marked needs_review) are split into #24529, which lands first. This PR's catalog lines are the same as #24529's, so once #24529 is in the base they drop out of this diff.
Tests
- New
test/turn-error-card.test.tsxcovers classification, the typed code, the human sentence, recovery order, and the card's DOM. - These tests still pass unchanged against the card:
turn-error-details,turn-error-layoutandsigned-out-harness(.cv-turn-note, the Details chevron, Sign in again, Switch model, Copy error). - Tests run in PR CI (webview tests are not run on Leo's Macs).
- Adopted from a session that died; ownership was claimed with
pr-owner(comment 6363193552). Changes since the earlier review:- the current base brought in (no conflicts);
- two fixes from Codex review (gpt-6.1-sol xhigh), each with a test:
- Retry shows only when the turn has a prompt row to send again;
- an agent that ran and quit, with a tool's "command not found" or "failed to start" in its stderr, reads as quit, not as "couldn't start".
- On huge-blue,
vp checkandvp fmt --checkadd no errors. The only errors are three base type errors intest/thread-minimap-stream.test.tsx, red on base 42134449 too. - The turn-error-card, turn-error-details, turn-error-layout and signed-out-harness tests pass.
No capture: webview-only; the gallery entry above is the visual.
Original session: cosmic-gray
Agent session: cosmic-gray
🤖 Generated with Claude Code