Skip to content

Group model picker by provider for ACP route models - #2465

Open
bradhallett wants to merge 1 commit into
get-bb:mainfrom
bradhallett:fix/2062-model-picker-provider-groups
Open

Group model picker by provider for ACP route models#2465
bradhallett wants to merge 1 commit into
get-bb:mainfrom
bradhallett:fix/2062-model-picker-provider-groups

Conversation

@bradhallett

Copy link
Copy Markdown
Contributor

Human comments

What was wrong

buildModelCatalogFromConfigOptions hard-coded description: "" for every ACP model select option, and acpConfigOptionSelectOptionSchema did not type description (it only survived via .passthrough()). Agents such as omp send description: "provider/modelId" and advertise the same display name under several routes (on this machine: 279 models across 9 providers, 37 duplicate display names). The desktop picker rendered only the display name, so those rows were identical in text, tooltip, and accessible name. Issue: #2062. Closed PR #2226 had the bridge fix plus inline qualifiers; this redo keeps the bridge hunks and replaces the desktop UX with provider-grouped headers.

What changed

Bridge (packages/provider-bridge-acp; the former plugins/provider-acp/src/bridge path is now a thin declaration layer):

  • src/wire.ts: description: acpOptionalString on the select-option schema.
  • src/bridge/model-catalog.ts: description: option.description ?? "", mirroring buildModelCatalogFromSessionModels.
  • No HOST_DAEMON_PROTOCOL_VERSION bump: AvailableModel.description is already a required string.

Desktop (apps/app):

  • Two-level grouped list by route key (routeProviderId, else the first segment of a slashed id). Sticky MenuSectionLabel headers only when ≥2 routes are visible. Search that narrows to one route hides the headers (same rule).
  • Within-group label collisions get an inline qualifier (id remainder after provider/). The trigger shows a distinguishing token only when the committed label is ambiguous across modelOptions + moreModelOptions.
  • Tooltips stay on the inner span[title] with the full raw id; keyboard order matches DOM order (contiguous route runs, not merged).
  • Curated short display names (zai → Z.ai, xai-oauth → xAI, …) with a hyphen→title-case fallback. omp 18.0.5 does not expose provider display names on omp models --json; group keys and tooltips stay on raw ids.
  • Single-provider lists (Claude Code, Codex) render with no headers and no qualifiers.

Mobile: no source change. execution-options.test.ts asserts the ACP description survives resolveModelSelectionmodelToOption so the existing subtitle path lights up from the bridge fix.

Deviation from closed #2226: grouping + headers instead of always-on inline qualifiers. F6 (Home/End) and F10 (header weight) from the design critique were skipped; no sibling picker supports Home/End.

How you verified

Tests (fail before, pass after):

  • packages/provider-bridge-acp/src/bridge/model-catalog.test.ts — catalog keeps the per-option description.
  • packages/provider-bridge-acp/src/wire.test.ts — schema returns description and normalizes nullundefined.
  • apps/app/src/components/pickers/model-picker-option.test.ts — 25 helper tests: grouping, ≥2-route header gate, within-group qualifiers, trigger token, display-name map.
  • apps/app/src/components/pickers/ModelReasoningPicker.test.tsx — grouped headers, role="group" / aria-labelledby, raw-id tooltips, single-route lists stay flat, sticky offsets, unique-trigger shape.
  • apps/mobile/src/data/compose/execution-options.test.ts — ACP description survives into the mobile option subtitle.

Mutation-kills (reverted after): hasMultipleRouteGroupsreturn false fails the grouped-catalog test; title always undefined fails getByTitle("zai/glm-5.3"); qualifyCollidingLabels early return new Map() fails the within-provider qualifier test.

Commands (after rebase onto 31d66d9, then pnpm install --frozen-lockfile): pnpm exec turbo run typecheck lint test --filter=@bb/provider-bridge-acp --filter=@bb/app --filter=@bb/mobile — 11/11. @bb/app 3445 passed (4 skipped), @bb/provider-bridge-acp 289 passed.

Manual: Ladle pickers--model-reasoning-picker--overview, "open: acp grouped" — pretty headers (Cursor / Z.ai / CommandCode / Mistral), collision tails, full-id tooltips, role=group.

Fixes #2062

AGENT GENERATED: by grok-4.6

ACP agents such as omp advertise the same display name under multiple
providers. Type description on the select-option schema, keep it through
the catalog, and group the desktop picker by route — headers only when
two or more providers are present.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ACP bridge drops model descriptions, so the model picker shows indistinguishable duplicate rows

1 participant