P0 cmux-next composer: reasoning is its own clickable control on New Tab and new chats
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 clicked | New Tab: model chip clicked | New chat: reasoning chip clicked |
|---|---|---|
![]() | ![]() | ![]() |
Stills (gallery, reasoning chip clicked, its menu open)
| Catppuccin Latte | Catppuccin Mocha | |
|---|---|---|
| New Tab 760 | ![]() | ![]() |
| New Tab 400 | ![]() | ![]() |
| New Tab 300 | ![]() | ![]() |
| Chat 760 | ![]() | ![]() |
| Chat 400 | ![]() | ![]() |
| Chat 300 | ![]() | ![]() |
🤖 Generated with Claude Code














