Skip to content

Agent pane: an unreachable server's error card leads with Retry, never Switch model - #34588

Merged
teamleaderleo merged 3 commits into
feat-cmux-nextfrom
lane/error-card-retry-first
Nov 4, 2026
Merged

teamleaderleo merged 3 commits into
feat-cmux-nextfrom
lane/error-card-retry-first

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Leo, 2026-11-03, on a cmux NEXT agent pane: "this ui is pretty awkward looking".

One item from that screenshot: a turn whose model server could not be reached (a transport, network or API connection failure) showed an error card that led with a filled Switch model. That happened whenever the card had no Retry of its own: an earlier turn, or a turn that a retry had already gone on from. Switching model is not the fix for a server that can't be reached.

  • TurnRows.tsx TurnFailure: an unreachable failure never makes Switch model the filled lead. If the chat has a Retry, Retry leads (filled). It runs acpmux's turn retry, the same path whose attempts Agent pane: a turn whose model can't be reached says so, not Thinking (acpmux turn_retrying) #34306's live line counts ("Can't reach the model · retrying (N of M)"). Retry stays disabled while the request is in flight, and Switch model follows it, outlined. If there is no Retry, Switch model stays on the card, outlined.
  • Failures about the model or its route (a refused key, a proxy) keep Switch model as the filled lead with Retry after it. Capacity, sign-in, compact, access and CodeRouter cards are unchanged. No action is removed anywhere.
  • No new strings. The button classes are unchanged, so each button's hover highlight still covers only that button.
  • I left the open Agent pane: a failed turn's Retry says Retrying… and never settles as sent when nothing was sent #34443 (the "Retrying…" note under the card's actions) alone. This diff doesn't touch that state or its strings.

Gallery: agent-pane.turn-error-card, new variants

  • server-unreachable: Retry first (filled), Switch model after it
  • server-unreachable-retrying: the retried attempt's live line says "Can't reach the model · retrying (2 of 10) · 503 server error", and the earlier card keeps Switch model outlined
  • model-error: a refused API key, with Switch model leading and Retry after it

Testing

webviews/test/turn-error-card.test.tsx gets four new tests that check which action leads for each error kind:

  • unreachable with Retry: ["Retry", "Switch model"], Retry filled
  • unreachable with no Retry: ["Switch model"], outlined. This one fails on base, where Switch model is filled.
  • unreachable through acpmux's turn retry: Retry calls retryFailed with the row and prompt, and stays disabled until it settles
  • invalid key: ["Switch model", "Retry"], Switch model filled

Ran on the fleet (cmux-ci test, Linux):

  • vp fmt on the changed files, with its change applied
  • bun test on turn-error-card, turn-error-continue, failureCopy, access-offer, signed-out-harness and cloud-signin-card: 87 pass, 0 fail
  • bun run typecheck and bun run lint: the one error in each is Cannot find name 'after' in test/transcript-spacing-kinds.test.ts:247. That is a base red from Agent pane: the live Thinking line starts on the icon column and stays the last row #34370, not a file this PR touches. These files report no errors.

Observed / Not run

  • Observed: the fleet results above.
  • Not run: a DEV build against a real failing gateway, and gallery captures.

Risk: low. One condition in one component, and it only changes which button gets the filled style and the lead slot for unreachable cards that have no Retry.

Changelog

Fixed: An agent chat whose model server can't be reached no longer leads its error card with Switch model; Retry leads, and Switch model follows it.

Proof

No capture: webview UI. See gallery agent-pane.turn-error-card (server-unreachable, server-unreachable-retrying, model-error).

Agent session: agent session

🤖 Generated with Claude Code


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


Summary by cubic

Fixes the agent pane error card so an unreachable model server leads with Retry instead of Switch model. Previously, a connection failure without its own Retry showed a filled Switch model, which doesn't fix a server that can't be reached.

Bug Fixes

  • Unreachable failures now lead with filled Retry when the chat has one; Switch model follows outlined, and stays outlined when there's no Retry.
  • Failures about the model or its route (refused key, proxy) keep Switch model as the filled lead with Retry after it.
  • Adds four tests per error kind and gallery variants, with no actions removed and no new strings.

Written for commit 9f3e8fa. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 3 commits November 3, 2026 17:43
…h model

Leo, 2026-11-03: "this ui is pretty awkward looking". A connection failure's card led with a filled
Switch model where it had no Retry (an earlier turn, or one a retry went on from). Retry leads it
where the chat has one; Switch model only follows, outlined. Gallery variants and tests per kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
@teamleaderleo teamleaderleo added risk:low Risk tier (docs/ci/risk-tiers.md) leo-named-fix An obvious fix to something Leo named: lands on push, review runs in parallel labels Nov 4, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (subagent claude-opus-5-5 medium, correctness): SHIP at 9f3e8fa

Checked the switchFirst change against every card kind. Only unreachable changes; capacity, sign-in, needs-credits, compact, CodeRouter, invalid-key and proxy-auth cards are unchanged. Each unreachable card has at most one filled button. The new tests and gallery fixtures check out, and a duplicate test helper flagged at 815469a was fixed in 6855c94. 9f3e8fa only adds the formatter's keyword wrap.
Visual verdict: no images; webview gallery variants server-unreachable, server-unreachable-retrying and model-error.
Follow-ups: an unreachable card on an earlier turn, with no Retry, now has no filled button; look at it in the gallery.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 9f3e8fa: 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=pr34588 -f ref=lane/error-card-retry-first -f platform=macos -f backend_mode=local

Gallery before/after for 9f3e8fa: 16 states rendered, 6 images differ, 3 more touched states not rendered (picked by the Gallery: line in the PR body). 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 41757422286 -R manaflow-ai/cmux -n gallery-advisory-34588-9f3e8fa6d445fc9308e1b2027b24ca3a201af8fa (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.turn-error-card/server-unreachable Apple System Colors Light new 0% pr-body
agent-pane.turn-error-card/server-unreachable Apple System Colors new 0% pr-body
agent-pane.turn-error-card/server-unreachable-retrying Apple System Colors Light new 0% pr-body
agent-pane.turn-error-card/server-unreachable-retrying Apple System Colors new 0% pr-body
agent-pane.turn-error-card/model-error Apple System Colors Light new 0% pr-body
agent-pane.turn-error-card/model-error Apple System Colors new 0% pr-body
agent-pane.turn-error-card/cloud-missing Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/cloud-missing Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/cloud-expired Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/cloud-expired Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/cloud-rejected Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/cloud-rejected Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/agent-closed Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/agent-closed Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/disk-full Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/disk-full Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/tailscale Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/tailscale Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/typed Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/typed Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/spawn-failed Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/spawn-failed Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/rate-limited Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/rate-limited Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/rate-limited-before-work Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/rate-limited-before-work Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/context-full Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/context-full Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/context-full-no-compact Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/context-full-no-compact Apple System Colors unchanged 0% pr-body
agent-pane.turn-error-card/sign-in Apple System Colors Light unchanged 0% pr-body
agent-pane.turn-error-card/sign-in Apple System Colors unchanged 0% pr-body

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

Unclear: web / react-apps-check failed: no known signature; failed step: Check webview test shards. This PR merged before its CI finished: fix forward on main.

CI failed on 9f3e8fa6d4 (run 41757396734 attempt 1): 1 code, 1 unknown.

Job Verdict Why
web / react-apps-base-check (2) code a web test failed
web / react-apps-check unknown no known signature; failed step: Check webview test shards

Failures:

  • seen on other PRs agent-pane-changes-placement.test.tsx the in-page changes view sits right of the transcript at every pane width: failed (job)
  • seen on other PRs agent-pane-changes-tab.test.ts the chat opens Changes as a tab for remote chats and non-repository turns, in the page only with no ...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts chromium: agent-pane.composer new-chat-reasoning at 760 px: with a menu open, one press on another c...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts chromium: agent-pane.new-tab reasoning-chip at 760 px: with a menu open, one press on another chip o...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts webkit: agent-pane.composer new-chat-reasoning at 760 px: with a menu open, one press on another chi...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts webkit: agent-pane.new-tab reasoning-chip at 760 px: with a menu open, one press on another chip ope...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts webkit: agent-pane.new-tab reasoning-chip at 300 px: Escape closes a menu and puts the keyboard back...: failed (job)
  • seen on other PRs transcript-spacing-kinds.test.ts work-to-subagent finds both its marks (light): failed (job)
Matched log lines
web / react-apps-base-check (2): (fail) the in-page changes view sits right of the transcript at every pane width [0.49ms]

Not re-run automatically: web / react-apps-base-check (2), web / react-apps-check are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

red: web / Web status; a job it gathers is red on this change (its line here); do not merge until green; see lane-rules
red: web / react-apps-base-check (2); it named no new red test (setup or base replay failed; see its log); do not merge until green; see lane-rules
red: web / react-apps-check; a job it gathers is red on this change (its line here); do not merge until green; see lane-rules

Shipped in:

@github-actions github-actions Bot added risk:normal Risk tier (docs/ci/risk-tiers.md) and removed risk:low Risk tier (docs/ci/risk-tiers.md) labels Nov 4, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol xhigh, via router-review): SHIP at 9f3e8fa

Visual verdict: no images; Leo tries the build.
Checked the changed action ordering and the retry wiring; found no correctness regression.
Follow-ups: [P2] [follow-up] add gallery after screenshots for the new variants.

@teamleaderleo
teamleaderleo merged commit 49d2b6e into feat-cmux-next Nov 4, 2026
155 of 178 checks passed
@teamleaderleo
teamleaderleo deleted the lane/error-card-retry-first branch November 4, 2026 02:08
teamleaderleo added a commit that referenced this pull request Nov 5, 2026
#34779)

* Agent pane: Retry and its model switch on the last turn's reply footer

Leo: "Today Retry is on your prompt bubble, and appears on the reply only after
a failure. Put it, with the model switch, in the last turn's footer."

The last turn's footer offers Retry right after Copy, failed or not, with its
model chevron as one split control (shared hover pill, lit while the menu is
open). Sent prompts and other agents' messages no longer draw Retry; a queued
row keeps its own. The failure card (#34588) is unchanged.

Agent-Ask: ask-78e15cc85d

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

* Agent pane: the Messages view keeps a sent prompt's Retry

The Messages view draws no reply footer for a turn that ended well
(messagesRows.ts), so moving Retry to the footer left it with none there.
Its prompts keep their Retry, as on base.

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

* Agent pane: a waiting steer's row draws no Retry either, so delivery moves nothing

The queue row of a waiting steer still drew Retry while the sent row no longer
did, so Send now changed the row's buttons (gallery health: composer
steer-send-now-leaves past its layout-shift baseline). Retry is the reply
footer's in the transcript; the Messages view's prompts keep it, sent or queued.

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

* test: Retry's model menu keeps the footer and its split pill lit while open

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

* Agent pane: the waiting steer's comments name the buttons it draws

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

* Agent pane: a waiting steer's row draws no Retry after the base merge; its test, gallery and capture notes say so

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

* test: format the waiting steer's Retry check

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

* Agent pane: a tool-only last turn's footer shows, so its Retry is not lost (review F1)

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

* Agent pane: format the footer mark's Retry check

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

* test: a folded stopped last turn with a prompt keeps the row its Retry sits on

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

* Agent pane: a read-only transcript keeps a tool-only last turn's empty footer, with no Retry to carry (review F1 at 9fceb0c)

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

* Agent pane: Retry stays on the person's last prompt's footer when only notices and reminders follow it (review F2 at effbc47)

turns.ts retryTargetAt picks the footer: the last turn whose prompt can be sent again. The
reply footer keeps the one visible Retry the prompt bubble had in those chats.

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

* Agent pane: type and format the retry target fixtures

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

* Agent pane: a task result's turn never offers Retry; the person's last prompt keeps it (review F1 at 83a3ecb)

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

* Agent pane: one Retry placement for the transcript, turns.ts retryPlacement, read by the footer and the prompt

The reply footer draws the chat's one Retry only when it shows and offers it; else the person's
last prompt keeps it, as before. Footer layout is base's again. A table-driven test covers each
turn shape the reviews named.

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

* Agent pane: a steer with its queue controls is never the Retry target; format the placement table

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

* Agent pane: Retry eligibility is base's prompt predicate, isRetryablePrompt, extracted unchanged

Only where Retry is drawn moved; which prompts can be retried is base's: the person's own
prompt UserBubble drew Retry for. Another agent's message and a task result draw none, a
waiting steer keeps its held Retry as on base, and the table test covers both as none.

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

* test: another agent's message fixture names its sender

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

* test(gallery): the reply footer's Retry split control shares one hover pill

The gallery control-surface audit flagged span.cv-turn-retry lighting when either half is hovered. Retry and its model switch are one split control by design (conversation.css .cv-turn-retry), so the pill is the control's own, not a row highlight.

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

* test(acpmux): a waiting steer that is the latest prompt keeps its held Retry

Pins that the bubbles' retry target (retryTargetIn) scans every row, so a waiting steer, which continues its turn rather than opening one, is still the prompt PendingSteer's held Retry belongs to.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 9f3e8fa6 Deployed Nov 4, 2026 by teamleaderleo via cmux-tui tree preflight #108712
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

leo-named-fix An obvious fix to something Leo named: lands on push, review runs in parallel risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant