Skip to content

feat(acp): honor managed-agent reasoning effort - #5507

Closed
rsaulo wants to merge 2 commits into
block:mainfrom
rsaulo:feat/acp-thinking-effort
Closed

feat(acp): honor managed-agent reasoning effort#5507
rsaulo wants to merge 2 commits into
block:mainfrom
rsaulo:feat/acp-thinking-effort

Conversation

@rsaulo

@rsaulo rsaulo commented Aug 10, 2026

Copy link
Copy Markdown

Problem

Buzz Desktop exposes an effort selector (EffortSelectField), but that field is not rendered for BYOH harnesses; I verified this in the UI with several models. Separately, BUZZ_AGENT_THINKING_EFFORT has exactly one runtime consumer today, in crates/buzz-agent/src/config.rs; nothing in buzz-acp reads it. As a result, managed agents running Claude Code, Codex, or opencode stay at the harness default with no effort control.

Why named effort through _meta, not MAX_THINKING_TOKENS

A token budget loses operator intent: high, xhigh, and max all collapse to 32,768 tokens. The Claude Agent SDK exposes named effort, and the adapter spreads ...userProvidedOptions after its defaults, so the client-provided value wins while preserving those distinctions.

Why the model-family table lives in buzz-core

This is a means, not an end: both the native runner and the external ACP path need the same Anthropic model-family classification. Sharing it avoids two tables silently diverging when a new model family is added. buzz-agent behavior remains identical, and its existing suite remains intact.

Harness-specific behavior

  • Claude Code: sends named effort through _meta.claudeCode.options (and retains manual token budgets for legacy model families).
  • Codex: deep-merges the effort into CODEX_CONFIG, preserving unrelated settings such as approval_policy and sandbox_mode.
  • opencode: deliberately does not write an operator config file. A configured effort fails explicitly at startup with guidance instead.
  • A context-window suffix such as [1m] is ignored for model-family classification.
  • An unversioned alias omits the option with an actionable message, because it cannot safely be classified as adaptive thinking versus a manual token budget.

Tests

  • cargo test -p buzz-core
  • cargo test -p buzz-agent
  • cargo test -p buzz-acp

rsaulo added 2 commits August 10, 2026 15:59
The Desktop exposes an effort selector, but it is not rendered for BYOH harnesses. BUZZ_AGENT_THINKING_EFFORT therefore had only one runtime consumer in buzz-agent, leaving managed Claude Code, Codex, and opencode agents pinned to each harness default.

Teach buzz-acp to validate the shared setting and translate it per harness. Claude receives adaptive or manual thinking through session/new _meta.claudeCode.options, Codex receives a deep-merged model_reasoning_effort without losing approval or sandbox policy, and opencode fails explicitly rather than writing user configuration.

The ThinkingEffort type and Anthropic family table move to buzz-core only as the means to keep the native runner and ACP path on one source of truth, not as a standalone refactor.

Claude uses _meta instead of MAX_THINKING_TOKENS because the token budget collapses high, xhigh, and max to 32,768 tokens and would erase the user's selected distinction.

Signed-off-by: rsaulo <rsaulo@me.com>
Signed-off-by: rsaulo <rsaulo@me.com>
@rsaulo
rsaulo requested a review from a team as a code owner August 10, 2026 19:35
@rsaulo

rsaulo commented Sep 3, 2026

Copy link
Copy Markdown
Author

Closing this in favour of #4625, and of #4557 which landed the ACP-side wire path.

Both solve the problem this PR was aimed at, and solve it better. The thing I got wrong here was hardcoding an effort axis: #4625 routes the effective value through BUZZ_ACP_EFFORT_LEVEL and lets the adapter's advertised thought_level option define the vocabulary, so Claude, Codex and OpenCode each get exactly the levels their current model supports — discovered rather than tabulated. The single-destination-key projection and the suppress set also close a class of double-authority bug this PR never addressed, and applying against the post-switch snapshot gets the model-then-effort ordering right. My Anthropic model-family table in buzz-core would have drifted within a release or two.

One narrow gap I'd like to file separately: models exposing a manual thinking budget rather than named effort (claude-3*, claude-opus-4-5) advertise no thought_level option, so a configured effort is silently dropped for them. Happy to open an issue.

Thanks for the thorough design here.

@rsaulo rsaulo closed this Sep 3, 2026
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.

1 participant