cmux NEXT model menu: every row names its effort, each agent tab lists current versions with older ones under Legacy

Merged
AU
5d ago
+185-12

Fixes https://github.com/manaflow-ai/cmux/issues/29915

Summary

The issue reported three problems with the cmux NEXT agent chat quick model menu.

  1. Effort was easy to miss. Effort showed as "Medium >" only on the selected row. Now every model row with effort levels names its level at rest. The running row shows the chat's current effort and other rows show their default. On the chat's own tab, other rows used to hide this until hover. The running row's effort is in the stronger text color so it reads as the live choice (QuickModelMenu.tsx withEffort, modelPicker.css).
  2. Tabs listed models inconsistently. Codex reports its whole live list as its menu, so its tab listed every GPT generation flat. Claude Code reports a short menu, so its older versions sat under Legacy models. Now, when a harness menu lists an older version of one product line alongside a newer one, the older one moves to Legacy models (relevantModelSections). Each tab shows its lines' current versions and keeps the same Legacy fold. A product line is the declared catalog family plus the version-stripped id, so a gateway whose families are whole vendors ("OpenAI", "Google") never folds Astra under Sol.
    • Context variants of one version (Opus 5.5 and Opus 5.5 · 1M) both stay.
    • Versionless aliases, models without a declared family, and an alias beside its dated snapshot never fold.
    • The chat's running model always keeps its row. quickSections and retryModelSections pass it in.
  3. Harness icons looked identical. Duplicate marks such as claude vs claude-sr2 were already merged into one tab per family by https://github.com/manaflow-ai/cmux/pull/29770, which landed after the reported build. Each rail mark already carries its harness name as a title / aria-label tooltip. The rail stays marks-only, per the picker design rule, so I added no visible tab text.

Tests

The regression tests are committed before the fix.

  • Red, round 1 (fix files at base, tests from fa2da85095793): bun test test/relevant-models.test.ts src/agent-session/acpmux/QuickModelMenu.test.tsx gave 39 pass and 2 fail. The failures are exactly the new tests: "a harness menu that lists older versions of a catalog family folds them, keeping variants" and "every model row with levels names one at rest, on the chat's own tab too".
  • Red, round 2 (review findings, tests from 4840703f8d59d against the round-1 fix fef693fbb6e60): bun test test/relevant-models.test.ts gave 7 pass and 2 fail. The failures are "a vendor-wide family folds within one product line only" and "the running model keeps its row and a dated snapshot never folds its alias".
  • Green (head, rebased on f06d9bd0736cc): those files plus retry-model-sections, retry-model, model-menu-compact, model-menu-providers, model-menu-short-list, model-picker-effort-provenance, model-picker-inline-effort-focus, current-model-families and model-button-default-effort gave 167 pass and 0 fail.
  • The duplicate-key React warnings in model-menu-compact / model-menu-providers were already there: 8 on base and 8 on head.
  • bun run check: type check passed (3613 files). Lint and fmt are clean on every changed file. The remaining reds are on base files this PR does not touch:
    • check:popup-hover-reveals fails on conversation/conversation.css:2448.
    • vp fmt flags newtab/NewTabDots.gallery.ts, newtab/tabDots.ts, test/composer-plus-geometry.test.ts and test/model-menu-compact.test.tsx.
  • python3 scripts/cmux-next/prepush-gate.py: no new violations.
  • Pushed with CMUX_WEB_LINT_SKIP_REASON because the pre-push web lint refused only on those base reds. Every flagged file is byte-identical to base f06d9bd0736cc.

Review

A correctness-first review subagent found two blocking issues in the first fix:

  1. Vendor-wide gateway families folded unrelated product lines.
  2. The running model could be folded into Legacy, and it disappeared from the .shown-only list.

It also found a should-fix: a dated snapshot id folded its alias. All three are fixed in 4840703f8d59d (tests) and 7e2491ab4d2d0 (fix), along with two nits (a redundant data-held condition and a stale doc comment). The re-review found no blocking findings. One accepted nit remains: an id dated with dashes (-2025-11-01) and a name with no digits could still fold its alias, and no catalog row has that shape.

Observed / Not run

  • Observed: the focused bun tests above, run locally.
  • Not run: a tagged dev build, and the full webview suite (CI runs it).
  • Visual: the gallery compare (merge-base vs head) is posted as a PR comment.

Changelog

  • Fixed: the cmux NEXT model menu shows every model's effort level, and each agent tab lists only current model versions, with older ones under Legacy models.

🤖 Generated with Claude Code


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


Summary by cubic

Fixes https://github.com/manaflow-ai/cmux/issues/29915: the cmux NEXT quick model menu now names an effort level on every model row, and each agent tab shows current model versions with older ones folded under Legacy models.

  • Every row with effort levels names its level at rest (previously only the selected row showed it as "Medium >"); the running row's level is emphasized.
  • A harness menu that lists older versions of a declared catalog family folds them under Legacy models, so Codex and Claude tabs group the same way.
  • Context variants of one version stay together; the running model always keeps its row; vendor-wide families like a gateway's "OpenAI" fold within one product line only, and dated snapshot ids don't fold their aliases.