Skip to content

Keep ACP model descriptions and disambiguate same-name picker rows - #2226

Open
SawyerHood wants to merge 1 commit into
mainfrom
fix/2062-acp-model-description
Open

Keep ACP model descriptions and disambiguate same-name picker rows#2226
SawyerHood wants to merge 1 commit into
mainfrom
fix/2062-acp-model-description

Conversation

@SawyerHood

Copy link
Copy Markdown
Collaborator

What was wrong

buildModelCatalogFromConfigOptions in the ACP bridge hard-coded description: "" for every model select option, and acpConfigOptionSelectOptionSchema did not type the option's description at all (it only survived via .passthrough()). Agents such as omp (oh-my-pi) send description: "provider/modelId" on every option, and advertise the same display name under several route prefixes (on this machine: 15 collisions across 72 models, e.g. github-copilot/gpt-5.1 vs openai-codex/gpt-5.1). Because the desktop model picker renders only the display name, those rows were identical in text, tooltip and accessible name. Issue: #2062. Report: https://get-bb.github.io/reports/issues/2062.html

What changed

Bridge (plugins/provider-acp):

  • src/wire.ts: description: acpOptionalString on the select-option schema (string or null, normalized to undefined like name).
  • src/bridge/model-catalog.ts: description: option.description ?? "", mirroring the sibling buildModelCatalogFromSessionModels path.
  • No HOST_DAEMON_PROTOCOL_VERSION bump: AvailableModel.description is already a required string on the wire; only its value changes.

Desktop (apps/app):

  • ModelPickerOption.routeProviderId becomes a general qualifier, and a new toModelPickerOptions(models, formatLabel) in model-picker-option.ts builds rows for useThreadCreationOptions (modelOptions / moreModelOptions) and both preview mappings in ModelReasoningPicker.
  • Only rows whose formatted label collides with another row in the same list get a qualifier: the agent's description when it is non-empty and at most 40 characters, otherwise the raw model id. A Pi model's routeProviderId is kept as the qualifier exactly as before.
  • The qualifier renders in the existing inline slot (MenuRowButton's qualifier, already used for Pi) and in the row's title tooltip, so row height does not change and providers with unique names (Claude Code, Codex) render exactly as before. The qualifier also feeds the model search text, so typing openai-codex finds the right row.

Relation to #2063 (external, reviewed REQUEST CHANGES): its bridge hunks are the same fix and are credited here. This PR differs on the desktop side: #2063 forwarded description for every provider into a new two-line MenuRowButton layout, which centered every picker row (the wrapper lost the button's default alignment) and turned every Claude Code / Codex row into a second line of truncated marketing copy. This PR instead fills the existing qualifier slot, and only for colliding rows.

How you verified

Tests (fail before, pass after):

  • plugins/provider-acp/src/bridge/model-catalog.test.ts: "keeps the per-option description the agent sends (ACP bridge drops model descriptions, so the model picker shows indistinguishable duplicate rows #2062)" (fails on main with description: "").
  • plugins/provider-acp/src/wire.test.ts: the schema now returns the parsed description and normalizes null to undefined (fails on main because the untyped field is not present in the inferred type).
  • apps/app/src/components/pickers/ModelReasoningPicker.test.tsx: "tells apart previewed models that share a display name (ACP bridge drops model descriptions, so the model picker shows indistinguishable duplicate rows #2062)": two equal-label options render distinct row text (GPT-5.1github-copilot/gpt-5.1 vs GPT-5.1openai-codex/gpt-5.1), a unique-label sibling stays a plain single-segment row, and clicking the second row emits openai-codex/gpt-5.1.
  • apps/app/src/components/pickers/model-picker-option.test.ts: unique labels keep no qualifier regardless of description; only colliding rows are qualified; long/missing descriptions fall back to the raw model id; collisions are detected on the formatted label and routeProviderId wins.

Commands: pnpm exec turbo run typecheck lint --filter=@bb/app --filter=bb-plugin-provider-acp and pnpm exec turbo run test --filter=@bb/app --filter=bb-plugin-provider-acp all green.

Manual, own dev instance with the real omp 16.3.10 on PATH (auto-registered as acp-omp): GET /api/v1/system/execution-options?providerId=acp-omp now returns 72 models with 72 non-empty descriptions (15 duplicate display names). In the picker, the oh-my-pi tab searched for GPT-5.1 shows GPT-5.1 github-copilot/gpt-5.1 and GPT-5.1 openai-codex/gpt-5.1 (and the Codex / Codex Max / Codex mini pairs) as distinct rows with distinct tooltips; every row, including Codex and Claude Code rows, measured 26px tall, and the Codex and Claude pickers are byte-for-byte the same row text as before.

Fixes #2062

AGENT GENERATED: by Claude Opus 5

The ACP bridge's configOptions model-catalog path hard-coded
description: "" and the wire schema did not type the per-option
description, so agents like omp that send description: "provider/model"
on every select option lost it. The desktop picker renders only the
display name, so omp's colliding names (github-copilot/gpt-5.1 vs
openai-codex/gpt-5.1 and 14 more) were indistinguishable.

Bridge: type `description` on the select-option schema and carry it
through buildModelCatalogFromConfigOptions, mirroring the session-models
path. No protocol bump: AvailableModel.description was already a
required string on the wire.

Desktop: ModelPickerOption's route-provider field becomes a general
`qualifier`, built once in toModelPickerOptions. Only rows whose
formatted label collides within a list get a qualifier (the agent's
description when it is short, else the raw model id); Pi's route
provider is kept as before. Unique-label rows (Claude Code, Codex) are
unchanged, and row height does not change.

Fixes #2062

Co-Authored-By: Claude <noreply@anthropic.com>
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