Skip to content

Fix Bedrock reasoning for adaptive-thinking models (Claude Opus 4.8)#558

Open
gruel-coveo wants to merge 2 commits into
usestrix:mainfrom
gruel-coveo:fix/opus-4-8-adaptive-thinking
Open

Fix Bedrock reasoning for adaptive-thinking models (Claude Opus 4.8)#558
gruel-coveo wants to merge 2 commits into
usestrix:mainfrom
gruel-coveo:fix/opus-4-8-adaptive-thinking

Conversation

@gruel-coveo

Copy link
Copy Markdown

Problem

Running a scan against an AWS Bedrock Claude Opus 4.8 inference profile fails immediately with a 400 BadRequestError:

litellm.BadRequestError: BedrockException - {"message":"The model returned the
following errors: \"thinking.type.enabled\" is not supported for this model. Use
\"thinking.type.adaptive\" and \"output_config.effort\" to control thinking behavior."}

Root cause

Strix detects that the model supports reasoning and passes reasoning_effort to the SDK, which forwards it to LiteLLM. LiteLLM converts reasoning_effort into Bedrock's legacy thinking.type=enabled payload. Newer Anthropic models (e.g. Claude Opus 4.8) no longer accept that shape and require thinking.type=adaptive plus output_config.effort.

LiteLLM's own model metadata already flags these models with supports_adaptive_thinking: true (alongside supports_output_config), but its request-conversion code still emits the old shape, so the request is rejected before any tokens are generated.

Fix

  • Add model_supports_adaptive_thinking() which reads LiteLLM's supports_adaptive_thinking flag (refactors the shared model-cost lookup into a helper).
  • In make_model_settings, for reasoning-capable models that support adaptive thinking, send the adaptive-thinking API via extra_args (thinking.type=adaptive + output_config.effort) instead of the reasoning_effort scalar.

All other models keep their existing behavior.

Testing

Verified against live Bedrock:

  • The settings Strix now generates for the Opus 4.8 inference profile succeed in both non-streaming and streaming (converse-stream) calls. Before the change, the same call reproduced the thinking.type.enabled error.
  • Confirmed no behavior change for other model classes: o3 still uses the reasoning path, gpt-4o and Claude 3.5 Sonnet are unaffected.
  • ruff check and mypy pass on the changed files.

Models such as Claude Opus 4.8 on Bedrock reject the legacy
"thinking.type=enabled" payload that LiteLLM emits when it converts the
"reasoning_effort" argument, returning:

    "thinking.type.enabled" is not supported for this model. Use
    "thinking.type.adaptive" and "output_config.effort" to control
    thinking behavior.

LiteLLM's model metadata already flags these models with
"supports_adaptive_thinking", but its request conversion still sends the
old shape. Detect that flag and pass the adaptive-thinking API via
extra_args (thinking.type=adaptive + output_config.effort) instead of the
reasoning_effort scalar. All other models keep their existing behavior.
@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a Bedrock 400 error that occurs when running against Claude Opus 4.8 inference profiles, which reject the legacy thinking.type=enabled shape that LiteLLM emits from reasoning_effort and instead require thinking.type=adaptive + output_config.effort.

  • Refactors the repeated LiteLLM model-cost lookup in models.py into a shared _model_cost_entry helper, then adds model_supports_adaptive_thinking() that reads the supports_adaptive_thinking flag from it.
  • In make_model_settings, adaptive-thinking-capable models now receive the new API shape via extra_args rather than the Reasoning object used for all other reasoning-capable models; non-adaptive models are unchanged.

Confidence Score: 4/5

Safe to merge for the described scenario; edge cases around non-standard effort strings and future models with only the adaptive-thinking flag are low-risk today but worth documenting.

The core fix is correct and well-scoped: Claude Opus 4.8 gets the new API shape, all other models are untouched. Two minor concerns remain open: reasoning_effort values like "minimal" and "xhigh" are passed verbatim to output_config.effort on the new path, bypassing any LiteLLM normalization, which will surface as Bedrock 400s for those combinations. Additionally, a model that carries only supports_adaptive_thinking (without supports_reasoning) in LiteLLM's metadata would silently receive no thinking configuration at all due to the outer guard. Neither is likely to bite today, but both are assumptions worth hardening.

strix/core/inputs.py — the branching logic in make_model_settings around effort value passthrough and the outer model_supports_reasoning guard.

Important Files Changed

Filename Overview
strix/config/models.py Refactors the shared LiteLLM model-cost lookup into _model_cost_entry, then adds model_supports_adaptive_thinking that reads the supports_adaptive_thinking flag from that entry. Straightforward and clean.
strix/core/inputs.py Adds a branch in make_model_settings that switches to extra_args (adaptive-thinking shape) for models flagged supports_adaptive_thinking. Works correctly for the described use case; non-standard effort strings ("minimal", "xhigh") bypass LiteLLM normalization on this path and are passed raw to the API.

Comments Outside Diff (1)

  1. strix/core/inputs.py, line 123-128 (link)

    P2 Adaptive-thinking models silently skipped if supports_reasoning is absent

    The outer condition gates on model_supports_reasoning(model_name), so a model that has supports_adaptive_thinking: true in LiteLLM's metadata but not supports_reasoning: true would reach neither branch and receive no thinking configuration at all — the call would proceed without any reasoning settings. The two flags are currently set together for Claude Opus 4.8, but if a future model only advertises supports_adaptive_thinking, this assumption will silently break. Checking model_supports_adaptive_thinking at the outer level (or combining the guard) would make the intent more resilient.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: strix/core/inputs.py
    Line: 123-128
    
    Comment:
    **Adaptive-thinking models silently skipped if `supports_reasoning` is absent**
    
    The outer condition gates on `model_supports_reasoning(model_name)`, so a model that has `supports_adaptive_thinking: true` in LiteLLM's metadata but **not** `supports_reasoning: true` would reach neither branch and receive no thinking configuration at all — the call would proceed without any reasoning settings. The two flags are currently set together for Claude Opus 4.8, but if a future model only advertises `supports_adaptive_thinking`, this assumption will silently break. Checking `model_supports_adaptive_thinking` at the outer level (or combining the guard) would make the intent more resilient.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
strix/core/inputs.py:128-143
**Non-standard effort values bypass normalization on the adaptive-thinking path**

`ReasoningEffort` includes `"minimal"` and `"xhigh"` in addition to the standard `"low"/"medium"/"high"`. On the legacy path those values were passed to `Reasoning(effort=...)` and then through LiteLLM's conversion layer, which may have normalized or rejected them internally. On the new `extra_args` path, `reasoning_effort` is embedded directly in `output_config.effort` and sent verbatim to Bedrock — Bedrock's API will reject any value outside its accepted set with a 400. If anyone runs an adaptive-thinking model with `STRIX_REASONING_EFFORT=minimal` or `STRIX_REASONING_EFFORT=xhigh`, the call will fail immediately with an opaque error.

### Issue 2 of 2
strix/core/inputs.py:123-128
**Adaptive-thinking models silently skipped if `supports_reasoning` is absent**

The outer condition gates on `model_supports_reasoning(model_name)`, so a model that has `supports_adaptive_thinking: true` in LiteLLM's metadata but **not** `supports_reasoning: true` would reach neither branch and receive no thinking configuration at all — the call would proceed without any reasoning settings. The two flags are currently set together for Claude Opus 4.8, but if a future model only advertises `supports_adaptive_thinking`, this assumption will silently break. Checking `model_supports_adaptive_thinking` at the outer level (or combining the guard) would make the intent more resilient.

Reviews (1): Last reviewed commit: "Fix Bedrock reasoning for adaptive-think..." | Re-trigger Greptile

Comment thread strix/core/inputs.py
Bedrock's output_config.effort only accepts low/medium/high (plus xhigh
on models that advertise it via supports_xhigh_reasoning_effort). The
ReasoningEffort range also includes "minimal" and "xhigh", which were
previously embedded verbatim and would trigger an opaque 400 on
adaptive-thinking models. Map "minimal" to "low", and downgrade
"xhigh" to "high" on models that don't support it.
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