diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index 82aa739018..a1e3f59de1 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -834,6 +834,10 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): "sonnet-4-5", "opus-4.1", "opus-4-1", + "opus-4.5", + "opus-4-5", + "opus-4.6", + "opus-4-6", } ): _output_format = ( diff --git a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py index e3bd7d2bb3..57e0dd494e 100644 --- a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py +++ b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py @@ -3,7 +3,6 @@ import os import sys import pytest -from fastapi.testclient import TestClient sys.path.insert( 0, os.path.abspath("../../../../..") @@ -855,6 +854,92 @@ def test_anthropic_structured_output_beta_header(): ) +@pytest.mark.parametrize( + "model_name", + [ + "claude-opus-4-6-20250918", + "claude-opus-4.6-20250918", + "claude-opus-4-5-20251101", + "claude-opus-4.5-20251101", + ], +) +def test_opus_uses_native_structured_output(model_name): + """ + Test that Opus 4.5 and 4.6 models use native Anthropic structured outputs + (output_format) rather than the tool-based workaround. + """ + config = AnthropicConfig() + + response_format = { + "type": "json_schema", + "json_schema": { + "name": "test_schema", + "schema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"}, + }, + "required": ["name", "age"], + "additionalProperties": False, + }, + }, + } + + optional_params = config.map_openai_params( + non_default_params={"response_format": response_format}, + optional_params={}, + model=model_name, + drop_params=False, + ) + + # Should use output_format (native structured outputs) + assert "output_format" in optional_params + assert optional_params["output_format"]["type"] == "json_schema" + + # Should NOT create a tool-based workaround + assert "tools" not in optional_params + assert "tool_choice" not in optional_params + + # Should set json_mode + assert optional_params.get("json_mode") is True + + +def test_non_structured_output_model_uses_tool_workaround(): + """ + Test that models NOT in the native structured output list still use the + tool-based workaround for response_format. + """ + config = AnthropicConfig() + + response_format = { + "type": "json_schema", + "json_schema": { + "name": "test_schema", + "schema": { + "type": "object", + "properties": {"result": {"type": "string"}}, + "required": ["result"], + "additionalProperties": False, + }, + }, + } + + optional_params = config.map_openai_params( + non_default_params={"response_format": response_format}, + optional_params={}, + model="claude-3-5-sonnet-20241022", + drop_params=False, + ) + + # Should NOT use output_format + assert "output_format" not in optional_params + + # Should use tool-based workaround + assert "tools" in optional_params + assert "tool_choice" in optional_params + + # ============ Tool Search Tests ============