P0 cmux-next composer: reasoning is its own clickable control on New Tab and new chats

Merged
TE
23d ago
+190-5

On the New Tab composer and in a new chat, the Reasoning chip couldn't be clicked. Before a session reports its effort option, the chip was PendingChip: aria-hidden with pointer-events: none. A press on it landed on the chips row behind it, Tab skipped it, and the only way to the levels was the Reasoning row inside the model chip's menu, so reasoning read as part of the model chip. Live chats were unaffected; they already render the real EffortPicker.

Now that chip is the real EffortPicker (own button, accessible name "Effort", own reasoning menu) whenever there's a level to name. Its levels come from what this harness's last session offered (harnessProfiles), else the chip model's catalog levels under acpmux's generic effort id, which acpmux resolves to the harness's own option (model_options.rs resolve_config_id). A pick goes through onEffort like a reported option's does: on New Tab that starts the deferred chat and harnessSwitch.pickConfig holds the value for the session. With no remembered or start level, nothing is drawn, as before (acpmux names a start level for its harnesses; widening that is a follow-up so new-tab-composer-first-frame's no-placeholder contract is decided on its own). The test proves the menu opens on its own; that a held pick reaches the chat's session (pick, then send) is covered end to end by item 9's model+effort carry-over work, not here. There's no CSS or row-fit change here, so it doesn't overlap #20802's step-down work.

Evidence

  • webviews/test/reasoning-own-control.test.ts (browser lane, real Chromium) presses each chip's centre at 760, 400 and 300 px on New Tab (agent-pane.new-tab / reasoning-chip, a new gallery variant), a new chat (agent-pane.composer / new-chat-reasoning) and a live chat (agent-pane.composer-row / claude-auto). The reasoning chip opens the reasoning menu and not the model picker, and the model chip opens the model picker. It also tabs from the model chip ("Model") to the reasoning chip ("Effort"). On the test-only commit 03fad9c0294: 12 fail (New Tab and new chat), 6 pass (live chat). On db726bb07de and the current head: 18 pass.
  • These also pass locally with CMUX_BROWSER_TESTS=1: new-chat-effort-chip, new-tab-composer-first-frame, access-chip-pending-warning, ultracode-rides-effort, composer-row-layout/fit/rhythm, new-tab-composer-layout, new-tab-picker-fold/clip, composer-location-strip, model-picker-picks and composer-turn-cycle. bun run check (vp check: fmt, lint, types) passes.

Known, not changed here: at 300 px in a chat the row is genuinely too narrow, so the reasoning label still shortens with an ellipsis ("M…"). Whole-unit step-down belongs to #20802.

In the app

I built the tagged app with CMUX_SKIP_ZIG_BUILD=1 ./scripts/reload.sh --tag cg-composer at 6686f2defc, under the lane lock, and opened it directly. I drove it with debug.agent_pane click, which is a native click at the element's centre.

  • New Tab: before any chat exists, the Reasoning chip shows the full "Medium". Clicking it opens the reasoning menu (Reasoning levels only, so this is the held path). On a fresh New Tab, clicking the model chip opens the model picker.
  • New chat: clicking the reasoning chip opens its own menu, with the reasoning levels plus the Ultracode and Fast Mode sections.
New Tab: reasoning chip clickedNew Tab: model chip clickedNew chat: reasoning chip clicked

Stills (gallery, reasoning chip clicked, its menu open)

Catppuccin LatteCatppuccin Mocha
New Tab 760
New Tab 400
New Tab 300
Chat 760
Chat 400
Chat 300

🤖 Generated with Claude Code