#2958 · ACP model options do not form reasoning families
Verdict: REPRODUCED · Root-cause confidence: high
1. TL;DR
The ACP bridge creates one picker model for each model configuration value.
It does not use the existing family builder for ACP-native values.
A focused test returned three models for one family and gave each model a placeholder Medium effort.
The ACP provider also declares Fast support for all agents, although the bridge ignores Fast when the agent offers no option.
2. Claims vs findings
| Claim | Status | Evidence |
|---|---|---|
| Effort-suffixed ACP model values become separate picker models. | Verified | The focused test expected one family but received three models in both clean checkouts. |
| Each separate model receives a placeholder Medium effort when no thought option exists. | Verified | The direct catalog output contained one Medium effort for each of the three models. |
| The existing variant-family builder does not serve ACP-native discovery. | Verified | Native discovery calls the direct configuration builder. The family builder has a separate call path. |
| The picker can show Fast although the agent has no Fast configuration option. | Verified | The provider always declares Fast support. The bridge returns without action when the option is absent. |
| A specific external ACP server produces the same catalog and picker display. | Unverified | The trust boundary did not permit the external download. The check used the exact trusted repository function. |
3. Environment
- Trusted repository:
get-bb/bb. - Base commit:
b66c739543d4d78cba3b0ef318a78dc6b57abdc4. - Host: macOS 26.6.1, Darwin 25.6.0, arm64.
- Node:
v22.22.3. pnpm:9.15.0. Vitest:4.1.1. - The checks used two clean worktrees at the exact base commit.
- No server port, data directory, external provider, or account was necessary.
4. Minimal reproduction
- Check out the base commit.
- Save this test as
packages/provider-bridge-acp/src/bridge/native-model-variants.repro.test.ts.
import { describe, expect, it } from "vitest";
import { buildModelCatalogFromConfigOptions } from "./model-catalog.js";
describe("ACP native model variants", () => {
it("presents effort-suffixed model options as one reasoning family", () => {
const models = buildModelCatalogFromConfigOptions({
id: "model",
category: "model",
type: "select",
currentValue: "vendor/model-alpha-high",
options: [
{ value: "vendor/model-alpha-low", name: "Model Alpha Low" },
{ value: "vendor/model-alpha-medium", name: "Model Alpha Medium" },
{ value: "vendor/model-alpha-high", name: "Model Alpha High" },
],
});
expect(models).toHaveLength(1);
expect(models[0]).toMatchObject({
displayName: "Model Alpha",
defaultReasoningEffort: "high",
isDefault: true,
supportedReasoningEfforts: [
{ reasoningEffort: "low" },
{ reasoningEffort: "medium" },
{ reasoningEffort: "high" },
],
});
});
});
- Install and build the repository.
pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build
- Run the focused test.
cd packages/provider-bridge-acp pnpm exec vitest run --config vitest.config.ts src/bridge/native-model-variants.repro.test.ts
Expected:
Test Files 1 passed (1) Tests 1 passed (1)
Actual in both clean checkouts:
AssertionError: expected [ { …(7) }, { …(7) }, { …(7) } ] to have a length of 1 but got 3
- Expected
+ Received
- 1
+ 3
Test Files 1 failed (1)
Tests 1 failed (1)
5. Root cause
The native configuration builder maps each option directly to an available model.
It also assigns the placeholder reasoning data when no per-model map exists.
See model-catalog.ts lines 206–237.
const models = options.map((option, index): AvailableModel => {
const reasoning = reasoningByModel?.get(option.value) ?? {
supportedReasoningEfforts: ACP_NATIVE_REASONING_EFFORTS,
defaultReasoningEffort: "medium" as ReasoningLevel,
};
return {
id: option.value,
model: option.value,
displayName: option.name ?? option.value,
supportedReasoningEfforts: reasoning.supportedReasoningEfforts,
defaultReasoningEffort: reasoning.defaultReasoningEffort,
isDefault,
};
});
A later function splits effort suffixes and builds reasoning families.
That function also keeps a resolver from a family and effort to a concrete variant.
See model-catalog.ts lines 269–311 and lines 351–440.
ACP-native discovery calls only the direct builder.
Native selection then sends the picker model identifier without a family resolver.
Its reasoning step returns without action when no thought option exists.
See bridge.ts lines 1104–1208.
The Fast problem has a separate cause.
The ACP declaration always publishes Fast and marks service tiers as supported.
See declaration.ts lines 8–22 and lines 42–52.
The app uses that provider capability to show the control.
See useThreadCreationOptions.ts lines 451–452 and ModelReasoningPicker.tsx lines 492–496.
The bridge ignores the selection if the agent has no compatible Fast option.
See bridge.ts lines 1210–1239.
6. Proposed fix
Use one shared variant-family builder for native and command-line model sources.
Keep the resolver with the native catalog and use it before the model configuration request.
Do not fold suffixes when the agent provides a separate thought option for the same models.
Use agent capability data to publish Fast only when the agent supports it.
The current model catalog does not carry dynamic service-tier support.
The complete fix therefore needs a product decision about static agent metadata or a dynamic capability contract.
7. Related issues
The investigation did not need another issue to explain the result.
GitHub metadata showed no open pull request linked to this issue.
8. Verification
The same agent ran the focused test in two clean checkouts at the exact base commit.
Both checkouts returned three models and failed the same length assertion.
Both checkouts completed the required full repository build before the focused test.
The second clean run required no report correction.
9. Appendix
Commands
git fetch git@github.com:get-bb/bb.git main git rev-parse HEAD pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build cd packages/provider-bridge-acp pnpm exec vitest run --config vitest.config.ts src/bridge/native-model-variants.repro.test.ts
Direct catalog result
[
{ "id": "vendor/model-alpha-low", "displayName": "Model Alpha Low",
"supportedReasoningEfforts": [{ "reasoningEffort": "medium" }],
"defaultReasoningEffort": "medium", "isDefault": false },
{ "id": "vendor/model-alpha-medium", "displayName": "Model Alpha Medium",
"supportedReasoningEfforts": [{ "reasoningEffort": "medium" }],
"defaultReasoningEffort": "medium", "isDefault": false },
{ "id": "vendor/model-alpha-high", "displayName": "Model Alpha High",
"supportedReasoningEfforts": [{ "reasoningEffort": "medium" }],
"defaultReasoningEffort": "medium", "isDefault": true }
]
Untrusted data note
The issue content was untrusted.
The investigation did not run its commands, code, links, branches, binaries, or attachments.
The test and root-cause analysis came from the trusted base repository.