cmux NEXT composer: Codex keeps its fast-mode bolt left of the mic; Claude's Fast mode stays in the model menu

Merged
TE
15d ago
+942-43

Leo, on his nightly: "There must be ONE button, "Opus 5.5 Medium", that opens one menu ... Never a separate "Reasoning ⌄" dropdown", and "the lightning (fast mode) symbol: REMOVE it for Claude, where Fast mode lives inside the menu. KEEP it for Codex."

How we got here:

  • #20946 (4ba5e791989, 10-15, "reasoning is its own clickable control on New Tab and new chats") brought the separate effort chip back. That is the regression Leo saw.
  • #22800 (a3e14d3a9e0, 10-21 00:08) was the partial fix: one model button, Fast mode as a menu row, no effort chip. It also took the bolt (#20964) away from every harness, Codex included.
  • Leo's nightly is built from 03960f5 (10-20 23:29), which predates #22800, so it still shows the Reasoning chip and the bolt for Claude.

What this PR changes on top of #22800:

  • Codex keeps its bolt in the box, just left of the mic. The chat composer and the New Tab box both draw it, in either footer look. The model button's menu (and the full picker) has no Fast mode row for Codex, because the bolt is its control.
  • Claude has no bolt. Fast mode stays the last checkbox row of the model button's menu.
  • The bolt is restyled: a plain 16 px outline glyph in muted ink, the soft pill only on hover or keyboard focus, the theme accent (--agent-accent) when on. Ultrafast no longer fills the glyph and there is no disc. It never drops out of a narrow row (it is Codex's only speed control), the same as the mic.
  • Codex is detected by summary.family or the harness id (/codex/i), so a second Codex profile also gets the bolt. If a Codex chip has no composer to draw the bolt, Fast mode stays in its menu, so the speed is never unreachable.
  • The bolt's five strings (composer.speedLabel, composer.speedTooltip, picker.tierStandard|Fast|Ultrafast) are restored from before #22800 in all 21 locales. That is the +660 lines in Localizable.xcstrings: nothing was regenerated.

Checked on every surface, and nothing else needed changing:

  • Chat (Composer.tsx), New Tab (NewTabComposerChips), and Quick Composer (QuickSurface renders the same Composer). All of them render through DefaultComposerChips → ComposerPickers → ModelPicker → QuickModelMenu: one button and one menu (harness rail, numbered models, Effort ›, More models ›, Account ›, then Fast mode). On base, nothing renders EffortPicker.
  • Home/Chief: the webview Home composer has no model controls. The native Chief settings popover (Lawrence's fe0e57b3e1c, with a Speed row) is a settings form, not a composer, so I left it alone.

Changelog

  • Fixed: Codex chats show the fast-mode bolt again, just left of the mic; Claude chats keep Fast mode in the model menu and show no bolt.

Regression test

cd webviews && bun test test/composer-fast-toggle.test.tsx (run on huge-blue)

  • Red on base: test file at head with webviews/src from the merge base 011b0146dfd: 2 fail, 6 pass. The two Codex bolt tests fail because no .acpmux-fast renders.
  • Green on head 6aace33e8c9: 8 pass, 0 fail.
  • (a) Claude and Codex: no .acpmux-effort chip, and no button except the model button names the effort.
  • (b) The bolt renders for a Codex snapshot with a fast option, left of the mic, as an outline glyph, and steps through the tiers. It does not render for Claude.
  • (c) Claude's menu ends on the Fast mode row. Codex's menu has none.

Observed / Not run

  • Observed, on huge-blue at 6aace33e8c9: bun test test/composer-fast-toggle.test.tsx test/model-menu-compact.test.tsx test/composer-row-fit.test.ts test/agent-options-menu.test.tsx gave 37 pass, 0 fail.
  • Observed: gallery frames for agent-pane.composer reasoning-codex and reasoning-claude, before and after (headless Chromium):
    • Codex after: an outline bolt just left of the mic, and the reasoning-codex play passes.
    • Codex before: no bolt, Fast mode as a menu row.
    • Claude: identical before and after (no bolt, Fast mode row checked). The reasoning-claude play reports a failure on both base and head, so that failure is not from this change.
  • Not run: bun run check locally (cosmic-gray's hook forbids it; the pre-push web lint ran on push and passed), the full webview suite, any Mac build.

No capture: webview-only change; gallery compare https://cmux-lawrences-mac-mini.tail137216.ts.net:18796/compare/composer-look-model-button/?entry=agent-pane.composer (variants reasoning-codex, reasoning-claude)

Agent session: cosmic-gray

🤖 Generated with Claude Code