Skip to content

feat(reasoning): add reasoning-effort config settings#2775

Merged
tusharmath merged 28 commits intomainfrom
reasoning-implementation
Apr 2, 2026
Merged

feat(reasoning): add reasoning-effort config settings#2775
tusharmath merged 28 commits intomainfrom
reasoning-implementation

Conversation

@tusharmath
Copy link
Copy Markdown
Collaborator

@tusharmath tusharmath commented Apr 1, 2026

Summary

Implement dynamic reasoning configuration with provider-aware serialization, expanding the Effort enum and routing reasoning parameters to the correct Anthropic API format based on model capability.

Context

Reasoning support previously used a single fixed path: always serializing a thinking object with a token budget. This approach didn't support newer Anthropic models (e.g. claude-opus-4-6) that use an effort-based output_config API instead of a token budget. Additionally, the Effort enum only had three levels (Low, Medium, High), which didn't cover the full range supported by OpenAI/OpenRouter (none, minimal, xhigh, max). This PR unifies reasoning configuration across providers and adds proper serialization routing.

Changes

  • Added a new ReasoningConfig struct in forge_config with effort, max_tokens, exclude, and enabled fields, surfaced in the JSON schema
  • Expanded Effort enum in both forge_config and forge_domain from 3 to 7 levels: None, Minimal, Low, Medium, High, XHigh, Max
  • Updated the usize → Effort budget-to-effort mapping to cover all new levels
  • Implemented dynamic Anthropic serialization routing: max_tokensthinking object (older models), effort without budget → output_config.effort (newer models), enabled only → thinking with default budget
  • Added output_config field to the Anthropic Request DTO to support effort-based reasoning for newer models
  • Applied workflow-level reasoning config to agents with agent-level fields taking priority (merge semantics)
  • Simplified the ZSH plugin by removing Windows-specific normalize_script and create_temp_zsh_script dead code
  • Added a .forge/skills/test-reasoning skill with comprehensive shell scripts for validating reasoning serialization across providers

Key Implementation Details

The Anthropic serialization routing in dto/anthropic/request.rs follows three branches:

  1. enabled=true + max_tokensthinking object (extended-thinking API, older models)
  2. enabled=true + effort (no budget) → output_config.effort (newer effort-based API)
  3. enabled=true only (no effort, no budget) → thinking with a default 10,000-token budget

For config merging in agent.rs, the config-level Effort is converted to the domain Effort before merging, with agent-defined fields always taking priority over workflow defaults.

Testing

# Run all reasoning-related tests
cargo insta test --accept -p forge_app -p forge_config -p forge_domain

# Use the built-in test skill for end-to-end provider validation
# (requires FORGE_KEY or provider API keys)
forge run .forge/skills/test-reasoning/scripts/test-reasoning.sh

Links

@tusharmath tusharmath force-pushed the reasoning-implementation branch from c6aa50a to a50da3b Compare April 1, 2026 19:14
@tusharmath tusharmath changed the title reasoning implementation feat(reasoning): dynamic reasoning config with provider-aware serialization Apr 2, 2026
@github-actions github-actions bot added the type: feature Brand new functionality, features, pages, workflows, endpoints, etc. label Apr 2, 2026
/// reasoning (e.g. `claude-opus-4-6`). Mutually exclusive with `thinking`.
#[derive(Serialize, Default, Debug, PartialEq, Eq)]
pub struct OutputConfig {
pub effort: String,
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use an enum type for type safety allow only the official variants.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added an OutputEffort enum with only the four Anthropic-valid variants (Low, Medium, High, Max) and updated OutputConfig to use it. Non-Anthropic effort levels (None, Minimal, XHigh) are mapped to the nearest valid variant at conversion time.

Effort::Max
}
}
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Budget isn't required to be related to the effort. Lets only use the budget that is set in the config or work with defaults.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Removed the From<usize> for Effort impl from both forge_domain and forge_config (along with all associated tests). Also updated the SetReasoningEffort OpenAI transformer to no longer derive effort from max_tokens — when only a budget is configured, it now falls back to the default medium effort. Effort must be set explicitly in the config.

tusharmath and others added 2 commits April 2, 2026 16:17
- Use OutputEffort enum in OutputConfig instead of String for type safety;
  only exposes Anthropic-valid variants (Low/Medium/High/Max)
- Set default reasoning effort to 'high' in .forge.toml
- Remove From<usize> for Effort impl: budget and effort are independent
  concerns; effort must be set explicitly in config
- Update SetReasoningEffort transformer to not derive effort from max_tokens
- Remove all budget-to-effort conversion tests

Co-Authored-By: ForgeCode <noreply@forgecode.dev>
@tusharmath tusharmath changed the title feat(reasoning): dynamic reasoning config with provider-aware serialization feat(reasoning): add reasoning-effort config settings Apr 2, 2026
@tusharmath
Copy link
Copy Markdown
Collaborator Author

Should fix #1479

@tusharmath tusharmath force-pushed the reasoning-implementation branch from ca087f1 to 271e3d6 Compare April 2, 2026 12:11
@tusharmath tusharmath enabled auto-merge (squash) April 2, 2026 12:27
@tusharmath tusharmath merged commit 1e409fa into main Apr 2, 2026
9 checks passed
@tusharmath tusharmath deleted the reasoning-implementation branch April 2, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature Brand new functionality, features, pages, workflows, endpoints, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant