Repository navigation
Description
Summary
resolve_model_switch_method() in crates/buzz-acp/src/acp.rs reads the configId key from each session/new configOptions entry and skips any entry that lacks it. The claude-agent-acp adapter (v0.61.0) keys those entries with id, not configId. Every model-category entry is therefore skipped, the desired model never matches, and the session silently falls back to the CLI default from the user's ~/.claude/settings.json.
Reproduction
Buzz Desktop 0.4.24, macOS arm64, claude-agent-acp 0.61.0, Claude Code CLI 2.1.219.
- Set a Claude Code agent's model to Opus in Buzz Desktop (per-agent or global default).
- Restart the agent.
buzz-acpis launched withBUZZ_ACP_MODEL=opus[1m]as expected. - Ask the agent what model it is running. It reports whatever
~/.claude/settings.jsonpins (in my caseclaude-fable-5[1m]), not Opus.
Harness log shows the fallback:
WARN pool::model: desired model opus[1m] not found in agent's available models - proceeding with agent default
The pool::model tracing target is not written to the per-agent log files, so nothing user-visible records the miss.
Root cause
The adapter's actual session/new response (captured with a stdio JSON-RPC probe against the bundled adapter):
{
"configOptions": [{
"id": "model",
"name": "Model",
"category": "model",
"type": "select",
"currentValue": "claude-fable-5[1m]",
"options": [
{ "value": "default" },
{ "value": "opus[1m]" },
{ "value": "claude-fable-5[1m]" },
{ "value": "sonnet" },
{ "value": "haiku" }
]
}],
"models": null
}Note the key is id. But resolve_model_switch_method() does:
let config_id = match config_opt.get("configId").and_then(|v| v.as_str()) {
Some(id) => id,
None => continue, // claude-agent-acp entries always take this branch
};So opus[1m] is a valid option value sitting right there in the response, and the exact-match loop never sees it. The unstable models path cannot rescue it either because the adapter returns models: null.
The unit tests all use configId-keyed fixtures, which is why they pass despite the drift.
The set side is unaffected: the ACP SDK's SetSessionConfigOptionRequest schema takes configId as the request param, and the adapter's setSessionConfigOption handler looks entries up by params.configId against o.id. Only the read side in buzz-acp is wrong.
Relationship to existing issues and PRs
- [Bug] Claude Code agents ignore the model set in Buzz Desktop — model picker persists but nothing applies it at spawn #2692 reports the user-visible symptom. A comment there traces this exact WARN but attributes the miss to a cold-start model-discovery race. It is not a race: the option list is present and complete in the
session/newresponse, the lookup just reads the wrong key. - fix(desktop): apply the configured model to Claude Code agents via ANTHROPIC_MODEL #2695, fix(desktop): Claude model picks + agent avatars after restart #2701, fix(desktop): apply Claude models and run Windows installers natively #2696 inject
ANTHROPIC_MODELat spawn from the desktop side. That masks the symptom for spawn-time selection but leaves the ACP config-option switch path broken, including for any future mid-session switching (feat(agents): allow changing an agent's model mid-session (like /model in Claude Code) #2543).
Fix
Accept both spellings when extracting the config id:
config_opt.get("configId").or_else(|| config_opt.get("id")).and_then(|v| v.as_str())PR incoming with this change plus a regression test using an id-keyed payload that mirrors the real adapter response.
Activity
jack-owen commentedon Jul 27, 2026
Still reproduces on current versions. Buzz Desktop 0.4.26, claude-agent-acp 0.62.0, Claude Code CLI 2.1.220, macOS 26.5.2.
The agent is configured as
sonnet, the live process carriesBUZZ_ACP_MODEL=sonnet, and the buzz-acp startup line logsmodel=sonnet. Three restarts in a row, and every assistant message in all three Claude transcripts recordsclaude-opus-5, which is what~/.claude/settings.jsonpins.One more thing consistent with your read-side diagnosis:
buzz-acp modelsprints the model group asconfigId: ?. The id is missing where the CLI displays it, not just where the switch resolves it.Nothing in the per-agent log records the miss, so from the user's side the setting simply appears to do nothing.
chillerno1 commentedon Jul 27, 2026
@wpfleger96 any chance you could take a look at PR #2795 ? Small fix in acp.rs to accept id-keyed config options when resolving a model switch.
fix(buzz-acp): accept id-keyed config options when resolving model sw…
fix(buzz-acp): accept id-keyed config options when resolving model sw…
fix(buzz-acp): accept id-keyed config options when resolving model sw…