Merge pull request #21598 from jtsaw/fix/anthropic-sonnet-4-6-reasoning-effort

support reasoning and effort parameters on sonnet 4.6
This commit is contained in:
Sameer Kankute 2026-02-20 08:24:29 +05:30 committed by GitHub
commit b405f64688
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 285 additions and 222 deletions

View file

@ -171,9 +171,22 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
return tool_call
@staticmethod
def _is_claude_opus_4_6(model: str) -> bool:
"""Check if the model is Claude Opus 4.5 or Sonnet 4.6."""
return "opus-4-6" in model.lower() or "opus_4_6" in model.lower() or "sonnet-4-6" in model.lower() or "sonnet_4_6" in model.lower() or "sonnet-4.6" in model.lower()
def _is_claude_4_6_model(model: str) -> bool:
"""Check if the model is a Claude 4.6 model that uses adaptive thinking."""
model_lower = model.lower()
return any(
model_variant in model_lower
for model_variant in (
"opus-4-6",
"opus_4_6",
"opus-4.6",
"opus_4.6",
"sonnet-4-6",
"sonnet_4_6",
"sonnet-4.6",
"sonnet_4.6",
)
)
def get_supported_openai_params(self, model: str):
params = [
@ -194,9 +207,13 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
"context_management",
]
if "claude-3-7-sonnet" in model or supports_reasoning(
model=model,
custom_llm_provider=self.custom_llm_provider,
if (
"claude-3-7-sonnet" in model
or AnthropicConfig._is_claude_4_6_model(model)
or supports_reasoning(
model=model,
custom_llm_provider=self.custom_llm_provider,
)
):
params.append("thinking")
params.append("reasoning_effort")
@ -207,27 +224,26 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
def filter_anthropic_output_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
"""
Filter out unsupported fields from JSON schema for Anthropic's output_format API.
Anthropic's output_format doesn't support certain JSON schema properties:
- maxItems/minItems: Not supported for array types
- minimum/maximum: Not supported for numeric types
- minLength/maxLength: Not supported for string types
This mirrors the transformation done by the Anthropic Python SDK.
See: https://platform.claude.com/docs/en/build-with-claude/structured-outputs#how-sdk-transformation-works
The SDK approach:
1. Remove unsupported constraints from schema
2. Add constraint info to description (e.g., "Must be at least 100")
3. Validate responses against original schema
Args:
schema: The JSON schema dictionary to filter
Returns:
A new dictionary with unsupported fields removed and descriptions updated
Related issues:
Related issues:
- https://github.com/BerriAI/litellm/issues/19444
"""
if not isinstance(schema, dict):
@ -236,7 +252,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
# All numeric/string/array constraints not supported by Anthropic
unsupported_fields = {
"maxItems", "minItems", # array constraints
"minimum", "maximum", # numeric constraints
"minimum", "maximum", # numeric constraints
"exclusiveMinimum", "exclusiveMaximum", # numeric constraints
"minLength", "maxLength", # string constraints
}
@ -706,12 +722,12 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
@staticmethod
def _map_reasoning_effort(
reasoning_effort: Optional[Union[REASONING_EFFORT, str]],
reasoning_effort: Optional[Union[REASONING_EFFORT, str]],
model: str,
) -> Optional[AnthropicThinkingParam]:
if reasoning_effort is None or reasoning_effort == "none":
return None
if AnthropicConfig._is_claude_opus_4_6(model):
if AnthropicConfig._is_claude_4_6_model(model):
return AnthropicThinkingParam(
type="adaptive",
)
@ -759,10 +775,10 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
)
if json_schema is None:
return None
# Filter out unsupported fields for Anthropic's output_format API
filtered_schema = self.filter_anthropic_output_schema(json_schema)
return AnthropicOutputSchema(
type="json_schema",
schema=filtered_schema,
@ -1140,7 +1156,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
"""
Ensure a beta header value is present in the anthropic-beta header.
Merges with existing values instead of overriding them.
Args:
headers: Dictionary of headers to update
beta_value: The beta header value to add
@ -1196,7 +1212,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
self, headers: dict, optional_params: dict
) -> dict:
"""Update headers with optional anthropic beta."""
# Skip adding beta headers for Vertex requests
# Vertex AI handles these headers differently
is_vertex_request = optional_params.get("is_vertex_request", False)
@ -1357,9 +1373,9 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
raise ValueError(
f"Invalid effort value: {effort}. Must be one of: 'high', 'medium', 'low', 'max'"
)
if effort == "max" and not self._is_claude_opus_4_6(model):
if effort == "max" and not self._is_claude_4_6_model(model):
raise ValueError(
f"effort='max' is only supported by Claude Opus 4.6. Got model: {model}"
f"effort='max' is only supported by Claude 4.6 models (Opus 4.6, Sonnet 4.6). Got model: {model}"
)
data["output_config"] = output_config
@ -1435,7 +1451,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
elif content["type"] == "web_fetch_tool_result":
if web_search_results is None:
web_search_results = []
web_search_results.append(content)
web_search_results.append(content)
else:
# All other tool results (bash_code_execution_tool_result, text_editor_code_execution_tool_result, etc.)
if tool_results is None:
@ -1452,7 +1468,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
thinking_blocks.append(
cast(ChatCompletionRedactedThinkingBlock, content)
)
## COMPACTION
elif content["type"] == "compaction":
if compaction_blocks is None:
@ -1660,7 +1676,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
provider_specific_fields["container"] = container
if compaction_blocks is not None:
provider_specific_fields["compaction_blocks"] = compaction_blocks
_message = litellm.Message(
tool_calls=tool_calls,
content=text_content or None,