diff --git a/litellm/llms/vertex_ai/gemini/transformation.py b/litellm/llms/vertex_ai/gemini/transformation.py index b8343d735b4..57889284a8c 100644 --- a/litellm/llms/vertex_ai/gemini/transformation.py +++ b/litellm/llms/vertex_ai/gemini/transformation.py @@ -595,6 +595,8 @@ def _transform_request_body( safety_settings: Optional[List[SafetSettingsConfig]] = optional_params.pop( "safety_settings", None ) # type: ignore + # Drop output_config as it's not supported by Vertex AI + optional_params.pop("output_config", None) config_fields = GenerationConfig.__annotations__.keys() # If the LiteLLM client sends Gemini-supported parameter "labels", add it diff --git a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py index e05e64988d4..6bede1a2352 100644 --- a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py +++ b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py @@ -152,4 +152,8 @@ class VertexAIPartnerModelsAnthropicMessagesConfig(AnthropicMessagesConfig, Vert "output_format", None ) # do not pass output_format in request body to vertex ai - vertex ai does not support output_format as yet + anthropic_messages_request.pop( + "output_config", None + ) # do not pass output_config in request body to vertex ai - vertex ai does not support output_config + return anthropic_messages_request diff --git a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/transformation.py b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/transformation.py index 78418799eb1..4e2c2895f9e 100644 --- a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/transformation.py +++ b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/transformation.py @@ -107,6 +107,9 @@ class VertexAIAnthropicConfig(AnthropicConfig): # VertexAI doesn't support output_format parameter, remove it if present data.pop("output_format", None) + + # VertexAI doesn't support output_config parameter, remove it if present + data.pop("output_config", None) tools = optional_params.get("tools") tool_search_used = self.is_tool_search_used(tools) diff --git a/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_transformation.py b/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_transformation.py index 24e8162c344..4712a3585b8 100644 --- a/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_transformation.py +++ b/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_transformation.py @@ -489,3 +489,112 @@ def test_vertex_ai_partner_models_anthropic_remove_prompt_caching_scope_beta_hea assert ( "anthropic-beta" not in headers2 ), "Header should be removed if no supported values remain" + + +def test_vertex_ai_anthropic_output_config_dropped(): + """ + Test that output_config parameter is dropped from Vertex AI Anthropic requests. + + Vertex AI does not support the output_config parameter (used for effort settings + in Anthropic API). This test ensures it's properly removed to prevent + "Extra inputs are not permitted" errors. + """ + config = VertexAIAnthropicConfig() + + messages = [{"role": "user", "content": "What is 2+2?"}] + headers = {} + + # Simulate optional_params with output_config that would be passed in + optional_params = { + "max_tokens": 1024, + "output_config": { + "effort": "high" # This is Anthropic-specific and not supported by Vertex AI + }, + } + + # Call transform_request which should drop output_config + result = config.transform_request( + model="claude-3-5-sonnet-20241022", + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers=headers, + ) + + # Verify output_config was removed + assert "output_config" not in result, \ + "output_config should be dropped from Vertex AI Anthropic requests" + + # Verify other parameters are preserved + assert result["max_tokens"] == 1024, "max_tokens should be preserved" + assert "messages" in result, "messages should be present" + + +def test_vertex_ai_anthropic_output_format_and_output_config_both_dropped(): + """ + Test that both output_format and output_config are dropped from Vertex AI requests. + + This ensures that even if both parameters somehow make it to the transform_request, + they are properly cleaned up before sending to Vertex AI. + """ + config = VertexAIAnthropicConfig() + + messages = [{"role": "user", "content": "Extract structured data"}] + headers = {} + + optional_params = { + "max_tokens": 2048, + "output_format": { + "type": "json_schema", + "json_schema": { + "name": "data", + "schema": {"type": "object", "properties": {"result": {"type": "string"}}} + } + }, + "output_config": { + "effort": "high" + }, + } + + # Simulate parent class creating test_data with both parameters + # (as if the parent transform_request added them) + test_data = { + "model": "claude-3-5-sonnet-20241022", + "messages": messages, + "max_tokens": 2048, + "output_format": optional_params["output_format"], + "output_config": optional_params["output_config"], + } + + # Mock the parent transform_request to return data with both parameters + original_transform = config.__class__.__bases__[0].transform_request + + def mock_transform_request(self, model, messages, optional_params, litellm_params, headers): + return test_data.copy() + + config.__class__.__bases__[0].transform_request = mock_transform_request + + try: + result = config.transform_request( + model="claude-3-5-sonnet-20241022", + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers=headers, + ) + + # Verify both were removed + assert "output_format" not in result, \ + "output_format should be dropped from Vertex AI requests" + assert "output_config" not in result, \ + "output_config should be dropped from Vertex AI requests" + + # Verify essential params are preserved + assert result["max_tokens"] == 2048, "max_tokens should be preserved" + assert "messages" in result, "messages should be present" + assert "model" not in result, "model should also be dropped for Vertex AI" + + finally: + # Restore original method + config.__class__.__bases__[0].transform_request = original_transform +