fix(bedrock): only drop reasoning params for DeepSeek, not all non-allowlisted models
Some checks failed
LiteLLM Rust / rustfmt, clippy, test (push) Has been cancelled

The DeepSeek leak fix gated the drop of thinking/reasoning_effort on a positive allowlist (_model_accepts_anthropic_thinking_param). Its negation dropped the params for any model the allowlist and ARN introspection missed, so Claude behind application-inference-profile ARNs, gpt-oss-safeguard (absent from the cost map so supports_reasoning is False), and Nova 2 custom-import ARNs all silently lost reasoning in prod.

Gate the drop on a narrow denylist instead: only DeepSeek reasons natively and 400s on the request field, so drop only there and leave every other model (including opaque ARNs and gpt-oss/Nova 2 which route reasoning_effort through their own shapes) untouched.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
mateo 2026-07-23 03:29:45 +00:00
parent f64b944b34
commit ab1f739188
2 changed files with 61 additions and 3 deletions

View file

@ -510,6 +510,18 @@ class AmazonConverseConfig(BaseConfig):
or supports_reasoning(model=base_model, custom_llm_provider=self.custom_llm_provider)
)
def _model_reasons_natively_and_rejects_request_param(self, model: str, base_model: str) -> bool:
"""Whether the model reasons natively and rejects any reasoning request field on Converse.
The Converse mapping serializes ``thinking`` into ``additionalModelRequestFields`` in Anthropic's
shape and ``reasoning_effort`` into a provider-specific shape. DeepSeek reasons on its own and
returns a 400 when either field is sent, even though it advertises ``supports_reasoning``, so both
must be dropped for it. Every other model either accepts one of those shapes (Claude ``thinking``,
gpt-oss / Nova 2 ``reasoning_effort``) or is an opaque ARN we can't introspect, so we leave those
untouched rather than silently degrading reasoning.
"""
return "deepseek" in model or "deepseek" in base_model
def get_supported_openai_params(self, model: str) -> List[str]:
from litellm.utils import supports_function_calling
@ -857,7 +869,7 @@ class AmazonConverseConfig(BaseConfig):
drop_params: bool,
) -> dict:
is_thinking_enabled = self.is_thinking_enabled(non_default_params)
accepts_thinking_param = self._model_accepts_anthropic_thinking_param(
drop_reasoning_request_param = self._model_reasons_natively_and_rejects_request_param(
model=model, base_model=BedrockModelInfo.get_base_model(model)
)
@ -909,7 +921,7 @@ class AmazonConverseConfig(BaseConfig):
optional_params["_parallel_tool_use_config"] = {
"tool_choice": {"disable_parallel_tool_use": disable_parallel}
}
if param == "thinking" and not accepts_thinking_param:
if param == "thinking" and drop_reasoning_request_param:
verbose_logger.debug(
"Dropping unsupported `thinking` param for Bedrock model=%s; it reasons natively and rejects it.",
model,
@ -937,7 +949,7 @@ class AmazonConverseConfig(BaseConfig):
litellm.verbose_logger.warning(DROP_UNSUPPORTED_ADAPTIVE_THINKING_WARNING, model)
else:
optional_params["thinking"] = value
elif param == "reasoning_effort" and isinstance(value, str) and not accepts_thinking_param:
elif param == "reasoning_effort" and isinstance(value, str) and drop_reasoning_request_param:
verbose_logger.debug(
"Dropping unsupported `reasoning_effort` param for Bedrock model=%s; it reasons natively and rejects it.",
model,

View file

@ -633,6 +633,52 @@ def test_bedrock_deepseek_r1_reasoning_params_not_forwarded_by_map(param):
assert request.get("additionalModelRequestFields") is None
@pytest.mark.parametrize(
"model, param, value, kept_key",
[
(
"bedrock/us.anthropic.claude-opus-4-20250514-v1:0",
"thinking",
{"type": "enabled", "budget_tokens": 1024},
"thinking",
),
(
"bedrock/arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/abc123",
"thinking",
{"type": "enabled", "budget_tokens": 1024},
"thinking",
),
(
"bedrock/openai.gpt-oss-safeguard-20b-1:0",
"reasoning_effort",
"high",
"reasoning_effort",
),
(
"bedrock/us.amazon.nova-2-lite-v1:0",
"reasoning_effort",
"high",
"reasoningConfig",
),
],
)
def test_bedrock_non_deepseek_reasoning_params_preserved(model, param, value, kept_key):
"""The DeepSeek leak fix must only drop reasoning request params for DeepSeek.
Claude behind an application-inference-profile ARN, gpt-oss-safeguard (absent from the
cost map so `supports_reasoning` is False), and Nova 2 all reason via a request param and
must keep it. Regression guard against gating the drop on a positive allowlist, which
silently degraded reasoning for anything the allowlist/ARN introspection missed."""
config = AmazonConverseConfig()
optional_params = config.map_openai_params(
non_default_params={param: value, "max_tokens": 100},
optional_params={},
model=model,
drop_params=False,
)
assert kept_key in optional_params
def test_get_supported_openai_params_bedrock_converse():
"""
Test that all documented bedrock converse models have the same set of supported openai params when using