Skip to content

Conversation

@ben-vargas
Copy link
Collaborator

Problem

Claude Opus 4.6 Thinking introduced a new API contract for thinking configuration: thinking.type: "adaptive" paired with output_config.effort, replacing the legacy thinking.type: "enabled" + thinking.budget_tokens shape used by older models (Sonnet 4.5, Opus 4.5).

Partial support existed at the translator layer (938a799): when a client sent a raw request already containing thinking.type: "adaptive", the translators could recognize it and convert it to other provider formats (e.g. Gemini's thinkingLevel, OpenAI's reasoning_effort), or pass it through for Claude-to-Claude. However, the applier -- the component responsible for producing the thinking shape from model suffixes and validated configs -- still only emitted the legacy format:

{ "thinking": { "type": "enabled", "budget_tokens": 16384 } }

This meant that when a user configured thinking via a model suffix (e.g. model-name(high) or model-name(auto)), the pipeline (suffix parsing → validation → applier) always produced the legacy budget-based shape, even for Opus 4.6 which expects the adaptive format. The system could forward an adaptive request but could never originate one.

What this PR does

  1. New AdaptiveAllowed capability flag on ThinkingSupport in the model registry, along with a Levels list for Opus 4.6 (low, medium, high, max). This lets the applier distinguish adaptive-capable models from legacy budget-only models.

  2. Splits the Claude applier into two code paths:

    • applyAdaptive -- for models with AdaptiveAllowed: true. Produces the correct upstream shape:
      { "thinking": { "type": "adaptive" }, "output_config": { "effort": "high" } }
      Budget-based inputs are auto-mapped to the nearest effort level. The budget_tokens field is always stripped.
    • applyLegacy -- preserves the existing thinking.type: "enabled" + budget_tokens behavior for all pre-Opus-4.6 models. Zero behavioral change for Sonnet 4.5, Opus 4.5, etc.
  3. Backward-compatible level aliasing -- xhigh (used by some existing configurations and the translator layer) is transparently normalized to max for adaptive models that don't define xhigh in their level set, so existing configs continue to work.

  4. Validation-layer updates -- ValidateConfig now runs adaptive-aware alias normalization before level validation, preventing false rejection of valid inputs. The logger includes the new effort field for observability.

  5. Test coverage -- new test cases verify adaptive body output (effort present, budget_tokens absent), disabled/auto modes on adaptive models, xhigh-to-max aliasing, and cross-provider conversion involving adaptive models. A new claude-adaptive-model test fixture and absentFields assertion helper support negative-field checks.

Impact

  • The full pipeline (suffix → validate → apply) now produces the correct adaptive + effort shape for Opus 4.6, closing the gap left by the translator-only support.
  • Users on older Claude thinking models see zero behavioral change.
  • Level-based inputs (e.g. (high), (low)) are passed through semantically as effort levels instead of being lossy-converted to arbitrary token budgets.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ben-vargas, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the system's support for Claude Opus 4.6's adaptive reasoning capabilities. It enables the full pipeline to correctly originate and process adaptive thinking configurations, moving beyond the previous translator-only support. The changes ensure that newer Claude models can leverage their advanced thinking modes while maintaining full backward compatibility for older models and existing configurations, improving the accuracy and flexibility of thinking parameter application.

Highlights

  • Adaptive Thinking Capability Flag: Introduced a new AdaptiveAllowed capability flag in the model registry's ThinkingSupport struct, along with defining specific Levels (low, medium, high, max) for Claude Opus 4.6, enabling the system to differentiate adaptive-capable models.
  • Split Claude Applier Logic: Divided the Claude thinking applier into two distinct code paths: applyAdaptive for models supporting adaptive thinking (emitting thinking.type: "adaptive" and output_config.effort), and applyLegacy for older models, preserving their existing thinking.type: "enabled" and budget_tokens behavior.
  • Backward-Compatible Level Aliasing: Implemented transparent normalization for xhigh thinking level to max for adaptive models that support max but not xhigh, ensuring existing configurations continue to function correctly without validation errors.
  • Validation and Logging Updates: Updated the validation layer to perform adaptive-aware alias normalization before level validation, preventing false rejections, and enhanced the logger to include the new effort field for improved observability.
  • Expanded Test Coverage: Added comprehensive test cases to verify adaptive body output (presence of effort, absence of budget_tokens), handling of disabled/auto modes on adaptive models, xhigh-to-max aliasing, and cross-provider conversion scenarios involving adaptive models, including new test fixtures and assertion helpers.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • internal/logging/global_logger.go
    • Added 'effort' to the ordered list of log fields for better observability.
  • internal/registry/model_definitions_static_data.go
    • Updated Claude Opus 4.6 model definitions to include AdaptiveAllowed: true and a list of Levels (low, medium, high, max) for thinking support.
  • internal/registry/model_registry.go
    • Added AdaptiveAllowed boolean field and updated comments to the ThinkingSupport struct to indicate support for adaptive thinking mode.
  • internal/thinking/apply.go
    • Updated comments for extractClaudeConfig to reflect support for 'adaptive' thinking type and output_config.effort.
    • Implemented logic in extractClaudeConfig to parse adaptive thinking configurations from the request body.
    • Refactored the Apply method to dispatch to applyAdaptive or applyLegacy based on the model's AdaptiveAllowed capability.
    • Created applyAdaptive function to construct adaptive thinking configurations, converting budgets to effort levels and stripping legacy budget fields.
    • Introduced clampAdaptiveEffort and hasLevel helper functions to normalize adaptive effort levels.
    • Modified applyLegacy to explicitly delete the output_config field to prevent stale data.
    • Removed redundant comments from normalizeClaudeBudget and effectiveMaxTokens.
    • Updated applyCompatibleClaude to handle ModeLevel and to emit adaptive format for user-defined models with level configurations, also ensuring output_config is deleted for non-adaptive modes.
  • internal/thinking/convert.go
    • Added 'max' to the levelToBudgetMap and updated associated comments.
    • Introduced ThresholdXHigh constant and updated ConvertBudgetToLevel comments to include 'max' threshold.
    • Adjusted ConvertBudgetToLevel logic to correctly map budgets to LevelXHigh and LevelMax.
  • internal/thinking/strip.go
    • Included 'output_config' in the list of paths to strip for Claude provider requests.
  • internal/thinking/suffix.go
    • Added 'max' as a recognized thinking level in ParseLevelSuffix.
  • internal/thinking/types.go
    • Defined LevelMax as a new ThinkingLevel constant for maximum thinking effort in Claude Opus 4.6 adaptive mode.
  • internal/thinking/validate.go
    • Integrated normalizeAdaptiveLevelAlias into ValidateConfig to handle level aliasing before validation.
    • Added LevelMax to the standardLevelOrder for canonical level ordering.
    • Implemented normalizeAdaptiveLevelAlias to convert 'xhigh' to 'max' for adaptive-capable models that support 'max'.
  • test/thinking_conversion_test.go
    • Added absentFields to the thinkingTestCase struct for verifying the absence of specific fields in test outputs.
    • Updated existing test cases (68, 73, 68, 73) to reflect the new 'max' thinking level instead of 'xhigh' for budget conversions.
    • Added new test cases (A5b, A5c, A5d) to validate adaptive model budget conversion, clearing of stale output_config, and user-defined model behavior.
    • Introduced TestThinkingClaudeAdaptiveXHighAlias to specifically test the backward-compatible aliasing of 'xhigh' to 'max' for adaptive models.
    • Added a new claude-adaptive-model test fixture to getTestModels.
    • Incorporated absentFields checks into the runThinkingTests utility function.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively unifies the behavior for Claude's adaptive reasoning, introducing support for the thinking.type: "adaptive" and output_config.effort API. The changes are well-structured, splitting the logic into adaptive and legacy paths, and include backward compatibility for xhigh level aliasing. The test coverage is comprehensive, validating the new adaptive behavior and ensuring no regressions for older models. I've added a few minor suggestions to improve code conciseness by using sjson.DeleteManyBytes where multiple fields are being deleted. Overall, this is a solid implementation.

Comment on lines +87 to +88
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For conciseness, you can use sjson.DeleteManyBytes to remove multiple fields at once.

Suggested change
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
result, _ = sjson.DeleteManyBytes(result, "thinking.budget_tokens", "output_config")

Comment on lines 159 to +160
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For conciseness, you can use sjson.DeleteManyBytes to remove multiple fields at once.

Suggested change
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
result, _ = sjson.DeleteManyBytes(result, "thinking.budget_tokens", "output_config")

Comment on lines 228 to +229
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For conciseness, you can use sjson.DeleteManyBytes to remove multiple fields at once.

Suggested change
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
result, _ = sjson.DeleteManyBytes(result, "thinking.budget_tokens", "output_config")

Comment on lines 233 to +234
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For conciseness, you can use sjson.DeleteManyBytes to remove multiple fields at once.

Suggested change
result, _ = sjson.DeleteBytes(result, "thinking.budget_tokens")
result, _ = sjson.DeleteBytes(result, "output_config")
result, _ = sjson.DeleteManyBytes(result, "thinking.budget_tokens", "output_config")

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