Repository navigation
cmux NEXT model menu: one row per model, its provider at the row's end - #24530
Conversation
…me their state; submenus grow up from the composer (failing) Leo 2026-10-21 on the nightly: his claude-sr2 chat's model menu listed nine numbered models, Opus 5.5 twice, and its Effort submenu opened downward toward the window's edge. These tests hold the menu to at most four models (the running one among them, each once, numbered 1 to 4), the Effort row naming its level with the submenu checking it, the Fast mode row naming On or Off, and the Effort submenu growing up from its row when the composer sits at the window's foot. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…els; Effort and Fast name their state; submenus grow up from the composer Leo 2026-10-21: "why are there so many models!? it should be truncating and then showing more models.. this effort should open up top instead of bottom" and "this should just show the effort too right?". - Opus 5.5 twice: foldAliases (modelCatalogData.ts) left the catalog release a session pins (claude-opus-5-5) beside Claude Code's `opus` alias, which Claude Code names "Opus 5.5" (0fe538a), and a Claude profile the catalog does not map (claude-sr2) skipped the alias fold and the curated top list entirely. The fold now keeps the running release's row and folds the alias into it, and a profile of a catalogued agent folds against that agent's releases (`kin`) and lists its curated top models. - The compact menu lists at most four models (QUICK_ROWS): the top picks, plain models before variants, and the running model always among them. Number keys name only those rows. Everything else is under More models. - Submenus (ui/Menu.tsx Submenu) grow toward the room their row has: up from the row's bottom when the row sits in the lower half of the menu's box, down from its top otherwise; Base UI's collision avoidance still flips them. - The Fast mode row names Off or On (On in the accent) where Effort and Account name their values. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rted pinned release keeps its row (failing at 7ab8d7b) Codex review of #24224 at 7ab8d7b (BLOCK, two findings): folding a profile's `opus` alias into the release claude-opus-5-5 dropped the user's overrides of `claude-sr2/opus` (fast off, one effort), and a session that reports running the pinned release with no model option lost that release's row. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…idden for it; the reported running model keeps its row - aliasRow layers the release's catalog row (and its own declared and user layers), then what the harness declares for the alias and the user's overrides of the alias, so `<harness>/opus` overrides still apply after the alias takes the release's row. - The fold's running model is the session's model option, else the model the session reports (summary.model, which direct.ts sends without a model option). The picker catalog's session now carries `model`. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…errides Codex review of #24224 at 850d374: a started profile on claude-opus-5-5 that also lists Claude Code's `opus` alias ("Opus 5.5") kept the release row unchanged, so what the harness declares for `opus` and the user's overrides of `<harness>/opus` (no Fast, one effort) were dropped. The running row now takes the alias's layers and keeps its own id, so it stays the checked row. The short-list test and the gallery's Claude stage pass the running model to the picker session too. Test: test/model-catalog-alias-fold.test.ts "the running release keeps the folded alias's overrides" fails at 850d374 and passes here. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e the session options withLiveOptions read any row with no efforts as one the catalog does not describe, so a session offering fast mode marked it Fast-capable and gave it every effort the adapter lists. That undid an alias declaration or agentPane.models.overrides entry that set fast: false and efforts: []. layeredModel now records which of efforts and fast the profile or the user set (PickerModel.own); withLiveOptions only narrows those efforts and leaves that fast alone. Codex review at a3f9e52. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sts as an alias shows it checked A direct session (direct.ts) has no model option and reports the release it runs in summary.model, while the live Claude probe lists only the bare opus alias. foldAliases found no row for the release, gave the alias the release's catalog row, and kept the alias id, so the running model was missing, no row was checked, and picking the apparent current row chose the alias. The alias now takes the release's id when the session runs that release, and a running release nothing lists still gets its row. Codex review at 6638fbc. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… row reasoningChoices read an empty efforts list as "no restriction", so a folded alias its profile declares (or the user overrides) with efforts: [] still showed every level the session lists, and a pick sent a level the profile says the model does not take. A row whose levels its profile or user set (PickerModel.own.efforts) is now held to them: none means no Effort row. Codex review at 87da5d1. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on the fold and the running release Codex review at a14ff11, and a sweep of every path this PR adds against every override field: - hidden: a profile the catalog does not map (claude-sr2) rebuilt its kin's releases without the user's hides, so with claude-sr2/opus hidden the running claude-opus-5-5 came back, checked. A release hidden here by its id, a catalog alias, or an alias the harness reports as it is no longer one of the profile's releases, as applyUserLayer drops it from its own harness. - fast and efforts: an override keyed by a catalog alias (claude/opus, */opus) reached the release through applyUserLayer but was not recorded as the user's, so the session's options undid it. layeredModel now layers a release's catalog-alias overrides, then its own. - name: the fold matched the user's display names, so renaming the alias or the release listed Opus 5.5 twice. It matches the harness's reported name against the catalog's own names. Leo-ask: ask-98ecbe7758 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lawrence on an OpenCode chat's model menu, which listed DeepSeek V4 Pro once per provider: "spacing + needs search", "we should just have a standard model picker". The menu should list each model once, name the provider its row lands, and offer a Provider row for the running model. Red on base: 6 fail, 0 pass (bun test test/model-menu-providers.test.tsx). Leo-ask: ask-a8b97f1201 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
Lawrence on an OpenCode chat's model menu, which listed DeepSeek V4 Pro once
per provider ("DeepSeek V4 Pro [New]", "OpenRouter/DeepSeek V4 Pro",
"DeepSeek/DeepSeek V4 Pro"): "spacing + needs search", "we should just have a
standard model picker".
modelVariants.ts groups a harness's "provider/model" rows by model: the menu
lists each model once, by its name, with the provider its row lands in
secondary ink at the trailing edge (one column, where a filtered row names its
harness) and a bracketed note as a quiet word. A Provider row (after Effort)
names the running model's provider and switches among the ones that serve
it. The four rows are four models, not four providers of one.
The gallery (agent-pane.model-menu-providers) shows three versions: the
Provider row (ships), each grouped model as a submenu of providers, and
providers listed under their model.
Leo-ask: ask-a8b97f1201
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Probably yours: CI failed on
Failures:
Matched log linesNot re-run automatically: Written by red: web / Web status; NEW: green on the base b247631; do not merge until green; see lane-rules Gallery before/after for
States
Pick other states with a |
|
Owned by an agent session · session |
|
Found 8 test failures on Blacksmith runners: Failures
|
|
|
#24224 landed squashed, so its pre-squash commits on this branch conflicted with base. This merge resolves to base plus only this PR's own two commits (d3eea1c, 5160f68) re-applied onto base's current model menu: base's search, New Tab and fork rows and its grid trailing column stay; the provider grouping, Provider row, tag and detail-at-end are added on top. The PR's own check/shortcut width rules are dropped because base's grid column already lines them up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (codex): FIX FIRST at a40f4e8
|
…ls and vendors (red) Codex review of #24530: rows of two vendors sharing an id tail merged, an unavailable first provider disabled the whole model on New Tab, search and Starred listed every provider's row, and More models dropped the provider and tag. Red on a40f4e8: 6 fail, 5 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
…keep vendors apart - modelVariants: rows whose ids name different vendors (openrouter/qwen/x, together/mistral/x) stay two models. - A grouped model lands its running provider, else its first available one, so an unavailable first provider no longer disables it. - Search and Starred group a model's providers into one row; a search row names its provider in its detail. - More models rows show the tag and provider. - The held height and width probes count the Provider row and each row's provider and tag. bun test test/model-menu-providers.test.tsx: 11 pass (6 fail before). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
…ning one is unavailable (red) Codex review of 924b529. Red on 924b529: 1 fail, 11 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
…ailable A search has no Provider row, so a running provider that is unavailable left the model's other providers out of reach. bun test test/model-menu-providers.test.tsx: 12 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
|
Review (codex): FIX FIRST at 924b529
[exited with code 0] |
…odel in any order (red) Codex review of 34bace1. Red on 34bace1: 1 fail, 12 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
…do not A two-segment id (qwen/coder-3) names no vendor, so it joined whichever group with its last segment came first: after together/mistral/coder-3 it merged direct Qwen into Mistral. Rows that name a vendor group first; a row that does not joins the model of the vendor its provider is, else the only model with its last segment, else stands alone. bun test test/model-menu-providers.test.tsx: 13 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
|
Review (codex): FIX FIRST at 34bace1
[exited with code 0] |
…ing one is unavailable (red) Codex review of 3992645. Red on 3992645: 1 fail, 13 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
… it is available Lists with no Provider row (search, Starred) left an unavailable running provider as the model's only row. groupChoices now lands the first available provider whenever the running one is unavailable, so search no longer needs its own special case. bun test test/model-menu-providers.test.tsx: 14 pass; model-menu*, model-picker*, quick* and composer pickers: 116 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
|
Review (codex): FIX FIRST at 3992645
|
|
|
|
|
|
Review (codex): FIX FIRST at 2c2cd8c
|
…ne is unavailable Red at 2c2cd8c: bun test test/model-menu-providers.test.tsx (Provider row missing). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
…available The fixed-harness list dropped the unavailable running offer before grouping, and the running row, its Provider row, tabExtent and the width probe matched only the row's own id. They now match any of the row's offers, and the list filters after grouping. Green: bun test test/model-menu-providers.test.tsx (15 pass); model menu, picker, quick and composer-picker suites 108 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-6516c08f19030a26c4eb
|
Review (codex): SHIP at 74f3c8f
|
|
Shipped in:
|
…picker-height Every commit of this branch, through 724ea2d, already landed on feat-cmux-next as #24676 (f1f6ba2, "follow-up: carry #24194 stable model menu fix"), and later base PRs (#24224, #24530, #25182, #25183, #25167) built on that code. The conflicts in QuickModelMenu.tsx and model-menu-compact.test.tsx are base's later edits to the same lines, so they resolve to base's side; the height spacer, width probe and check-in-probe behaviour are all in base's version. The branch now matches feat-cmux-next. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-f68ebdd9a3c1704ffb42
#24530 landed this feature's first version, and base since replaced the compact menu's held width/height probes (#26615) and its provider search grouping (#27303). The conflicting menu files (QuickModelMenu, ModelPicker, gallery, CSS, the providers and compact tests) take base. What this PR still adds on top: modelVariants.ts's grouping (the route prefix names the provider, rows join by owner, one offer per provider preferring the available and running row, ids/count per group) with its tests, and the reasoning slider focusing on mount (EffortTrack/EffortPicker). The modelSections dedupe flag and the groupVariants `preferred` set had no caller left, so they are dropped. Verified: bun test model-variants (13/13), model-menu-providers (15/15), model-menu-compact (42/42), effort-picker-slider (18/18); bun run check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d7590af53de4742a1808
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo-ask: ask-a8b97f1201
#24224 has landed. The branch's base merge (
a40f4e8) resolves to feat-cmux-next plus only this PR's own two commits (d3eea1ctest,5160f68fix), re-applied onto base's current model menu (its search field, New Tab inline More models, fork rows and grid trailing column stay). Adopted from the original lane after it closed.Leo, exact words: "the thing i had in the henlo chat was just pasting some images lawrence said and this: ... and also the tab unread + simultaneous ongoing thing feels I weird idk if there's a way to combine + the spacing is off ..."
Lawrence posted a thumbnail of the model menu showing many near-duplicate DeepSeek rows, such as "DeepSeek V4 Pro [New] OpenCode", "DeepSeek V4.1 Flash OpenCode" and "OpenRouter/DeepSeek Chat OpenCode". His caption: "spacing + needs search". He also wrote "we should just have a standard model picker".
This PR covers provider variants and spacing. Search landed separately in base. Focus after a pick comes in its own PR.
What changes
A harness that routes to several providers (OpenCode, Pi) reports a model once per provider:
openrouter/deepseek/deepseek-v4-pro,deepseek/deepseek-v4-pro, and so on. The menu drew each of these as its own row, with the provider pasted into the name.modelVariants.ts(new, pure functions) reads the provider from the id path or from a "Provider/" prefix in the name. It groups rows that share the last id segment into one model. Only rows that name a provider join a group; two bare ids stay two models. The row's name drops the provider prefix. A bracketed note such as "[New]" becomes a quiet tag after the name.picker.providerstring, which already has all 21 languages.quickSections(from cmux NEXT model menu: four models, each once, the rest under More models; Effort and Fast name their state; submenus open up from the composer #24224) counts a model as a top one if any of its offers is among the latest, so one model with three providers no longer takes three of the four top slots.Look: the menu's glass is unchanged (
rgba(30,30,46,0.6),blur(20px) saturate(1.4)). Theme tokens only, with no orange, no system blue and no dots.Versions (gallery
agent-pane.model-menu-providers, an OpenCode chat on DeepSeek V4 Pro)provider-row,provider-row-open).provider-submenu,provider-submenu-open).provider-expanded).I picked A. It is the "standard model picker" Lawrence asked for: a short list of models, one row each, with the provider as a detail rather than part of the name. Picking a model is still one click, and changing provider is the second choice, next to Effort. B hides which provider a row lands behind a hover, and its rows stop being one-click picks. C brings back the long list Lawrence flagged, just reorganised. The version is one prop (
quick.providers), so B or C is a one-line switch.Tests
bun test test/model-menu-providers.test.tsx(new) on huge-blue:2c761a8(feat-cmux-nexte1f78c7with cmux NEXT model menu: four models, each once, the rest under More models; Effort and Fast name their state; submenus open up from the composer #24224's head merged): 6 fail, 0 pass.5160f68: 6 pass.What the six tests cover:
groupVariantskeeps bare ids apart.deepseek/deepseek-v4-prochecks the single row and names DeepSeek.Neighbours on the head:
model-menu*,model-picker*andcomposer-fast-toggle, 9 files, 76 pass, 1 fail. The one failure,model-menu-short-list"a model its profile declares with no effort levels shows no Effort row…", fails the same way without this PR.vp lintandvp checktypes pass.Observed / Not run
No capture: webview-only change; gallery compare https://cmux-lawrences-mac-mini.tail137216.ts.net:18796/compare/composer-look-picker-spacing/ (entry
agent-pane.model-menu-providers;agent-pane.model-pickerfor the Claude and Codex menus, which don't change).Size
613 added lines: about 290 source, 223 test and 105 gallery. That's over the brief's ~300 because the tests and gallery are in their own new files, which keeps them clear of the sibling PRs that edit
model-menu-compact.test.tsx.Overlap
The sibling PRs this used to overlap (#24224, #24355 merged; #24521, #24487 closed) are all settled; the base merge resolved their hunks.
Re-run on the merged head (huge-blue)
bun run check: format, types and protocol pass;vp lintexits non-zero only on warnings inDynamicWorkflow.gallery.tsx, which this PR doesn't touch (same on base).model-menu-providers,model-menu-compact,model-menu-short-list,model-menu-submenu-up,composer-fast-toggle,model-catalog-alias-fold: 87 pass, 0 fail.model-menu*,model-picker*,quick*,new-tab*tests: 466 pass, 3 fail. The 3 (new-tab-widget-edit,new-tab-minimal-default,new-tab-no-entry-motion) fail the same way with base's sources.Changelog
Agent session: agent session
🤖 Generated with Claude Code