Skip to content

fix(reasoning): respect user config and Effort::None for models without effort support#2941

Open
tivris wants to merge 2 commits intotailcallhq:mainfrom
tivris:fix/effort-none-reasoning
Open

fix(reasoning): respect user config and Effort::None for models without effort support#2941
tivris wants to merge 2 commits intotailcallhq:mainfrom
tivris:fix/effort-none-reasoning

Conversation

@tivris
Copy link
Copy Markdown
Contributor

@tivris tivris commented Apr 10, 2026

Summary

Fixes two interacting bugs that caused reasoning parameters to be sent to models that don't support them (e.g. Claude Haiku 4.5), even when the user explicitly disabled reasoning in .forge.toml.

Fixes #2924.

Bug 1: Config merge direction (agent.rs)

The reasoning config merge used overwrite_none with the agent as base, so the forge agent's hardcoded enabled: true silently overrode the user's enabled: false. Reversed the merge direction to match the compact config pattern already used in the same file: user config as base, agent defaults fill gaps.

Bug 2: Effort::None semantics (request.rs)

Effort::None is documented as "No reasoning; skips the thinking step entirely" but the Anthropic DTO mapped it to OutputEffort::Low, actively enabling reasoning. Now returns (None, None) to skip reasoning entirely, matching the OpenAI path which already handled this correctly.

Test plan

  • New test: user enabled=false overrides agent enabled=true (the [Bug]: Can't use model without _effort_ support. #2924 scenario)
  • New test: Effort::None with enabled=true skips reasoning on Anthropic
  • New test: Effort::None with enabled=false skips reasoning on Anthropic
  • New test: Effort::Minimal still maps to OutputEffort::Low
  • New test: agent fills unset config fields
  • Updated test: config fields take priority over agent (reversed from before)
  • RUSTFLAGS='-Dwarnings' cargo check -p forge_app passes
  • cargo test -p forge_app (576 tests) passes
  • cargo test -p forge_domain passes

Note

The Google provider (crates/forge_app/src/dto/google/request.rs) has the same class of bug: Effort::None + enabled=true still emits a ThinkingConfig, and effort is never mapped to thinking_level. That is a pre-existing issue outside the scope of this PR.

…ut effort support

Two bugs caused reasoning parameters to leak to models that don't
support them (e.g. Claude Haiku 4.5), even when the user explicitly
disabled reasoning in .forge.toml:

1. The reasoning config merge used agent-as-base with overwrite_none,
   so the forge agent's hardcoded `enabled: true` silently overrode
   the user's `enabled: false`. Reversed the merge direction to match
   the compact config pattern (user config as base, agent fills gaps).

2. Effort::None ("skip reasoning entirely") was mapped to
   OutputEffort::Low in the Anthropic DTO, actively enabling reasoning.
   Now returns (None, None) to skip reasoning, matching the OpenAI path.

Closes tailcallhq#2940, addresses tailcallhq#2924.
@github-actions github-actions bot added the type: fix Iterations on existing features or infrastructure. label Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: fix Iterations on existing features or infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Can't use model without _effort_ support.

1 participant