From b3b766119bc25229c4d8d51fb0b8895ef4cceb8e Mon Sep 17 00:00:00 2001 From: mateo Date: Sat, 31 Oct 2026 22:13:01 +0000 Subject: [PATCH 1/2] fix(anthropic-messages): stop copying Anthropic-only params onto bridged chat requests Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../anthropic/messages/adapters/handler.py | 3 +-- .../messages/adapters/transformation.py | 6 ++++- .../translation/messages/params/__init__.py | 0 .../test_messages_params_anthropic_only.py | 27 +++++++++++++++++++ ...hropic_messages_adapters_transformation.py | 21 +++++++++++++++ 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/integration/translation/messages/params/__init__.py create mode 100644 tests/integration/translation/messages/params/test_messages_params_anthropic_only.py diff --git a/litellm/llms/anthropic/messages/adapters/handler.py b/litellm/llms/anthropic/messages/adapters/handler.py index d13fd4f47ff..b5adc982590 100644 --- a/litellm/llms/anthropic/messages/adapters/handler.py +++ b/litellm/llms/anthropic/messages/adapters/handler.py @@ -16,6 +16,7 @@ from litellm.litellm_core_utils.asyncify import run_async_function from litellm.litellm_core_utils.core_helpers import drops_unsupported_params from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObject from litellm.llms.anthropic.messages.adapters.transformation import ( + ANTHROPIC_ONLY_REQUEST_KEYS, AnthropicAdapter, ) from litellm.llms.anthropic.messages.context_management import ( @@ -51,8 +52,6 @@ if TYPE_CHECKING: from litellm.router import Router from litellm.types.proxy.auth.user_api_key_auth import UserAPIKeyAuth -# Anthropic-only keys already mapped by the translator; strip on extra_kwargs re-merge. -ANTHROPIC_ONLY_REQUEST_KEYS: Final[frozenset[str]] = frozenset({"output_config", "safeguards"}) _REQUEST_KWARGS: Final = TypeAdapter(Mapping[str, object]) _AnthropicMessages: TypeAlias = "list[dict[str, object]]" diff --git a/litellm/llms/anthropic/messages/adapters/transformation.py b/litellm/llms/anthropic/messages/adapters/transformation.py index 4b1b5a8a11a..b366189db10 100644 --- a/litellm/llms/anthropic/messages/adapters/transformation.py +++ b/litellm/llms/anthropic/messages/adapters/transformation.py @@ -215,6 +215,10 @@ from litellm.utils import supports_mid_conversation_system from .streaming_iterator import AnthropicSSEStream, AnthropicStreamWrapper +ANTHROPIC_ONLY_REQUEST_KEYS: Final[frozenset[str]] = frozenset( + {"output_config", "safeguards", "inference_geo", "mcp_servers", "speed"} +) + if TYPE_CHECKING: from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObject from litellm.llms.anthropic.messages.safeguards import SafeguardsEvaluator @@ -1272,7 +1276,7 @@ class LiteLLMAnthropicMessagesAdapter: """Copy through anthropic params that do not require translation.""" translatable_params: Final = self.translatable_anthropic_params() for k, v in anthropic_message_request.items(): - if k not in translatable_params: # pass remaining params as is + if k not in translatable_params and k not in ANTHROPIC_ONLY_REQUEST_KEYS: new_kwargs[k] = v def translate_anthropic_to_openai( diff --git a/tests/integration/translation/messages/params/__init__.py b/tests/integration/translation/messages/params/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/integration/translation/messages/params/test_messages_params_anthropic_only.py b/tests/integration/translation/messages/params/test_messages_params_anthropic_only.py new file mode 100644 index 00000000000..5d384b3cfee --- /dev/null +++ b/tests/integration/translation/messages/params/test_messages_params_anthropic_only.py @@ -0,0 +1,27 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.messages.bases.azure import GPT_5_4_TEST_CASE +from integration.translation.runner import assert_translation + +GPT_5_4_ANTHROPIC_ONLY_PARAMS_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="anthropic_only_params_dropped", + litellm_request={ + **GPT_5_4_TEST_CASE.litellm_request, + "inference_geo": "us", + "mcp_servers": [{"type": "url", "url": "https://mcp.example.com/sse", "name": "example"}], + "speed": "fast", + }, +) + +CASES: Final = (GPT_5_4_ANTHROPIC_ONLY_PARAMS_TEST_CASE,) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_messages_params_anthropic_only(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py b/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py index cc366dcde4c..47f8a25349c 100644 --- a/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py +++ b/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py @@ -4108,6 +4108,27 @@ def test_translate_anthropic_tool_choice_none(): assert result == "none" +def test_translate_anthropic_to_openai_drops_anthropic_only_params(): + adapter = LiteLLMAnthropicMessagesAdapter() + + new_kwargs, _ = adapter.translate_anthropic_to_openai( + { + "model": "gpt-5.4", + "max_tokens": 64, + "messages": [{"role": "user", "content": "Say hello."}], + "inference_geo": "us", + "mcp_servers": [{"type": "url", "url": "https://mcp.example.com/sse", "name": "example"}], + "speed": "fast", + "top_k": 7, + } + ) + + assert "inference_geo" not in new_kwargs + assert "mcp_servers" not in new_kwargs + assert "speed" not in new_kwargs + assert new_kwargs["top_k"] == 7 + + # --------------------------------------------------------------------------- # PolyfillResult integration tests # --------------------------------------------------------------------------- From 7104a05ec1af27ad1c38a899c9fea9083a4ca617 Mon Sep 17 00:00:00 2001 From: mateo Date: Sat, 31 Oct 2026 22:32:41 +0000 Subject: [PATCH 2/2] test(anthropic-messages): annotate the Anthropic-only params regression test Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../test_anthropic_messages_adapters_transformation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py b/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py index 47f8a25349c..523f3e35f0b 100644 --- a/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py +++ b/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py @@ -4108,8 +4108,8 @@ def test_translate_anthropic_tool_choice_none(): assert result == "none" -def test_translate_anthropic_to_openai_drops_anthropic_only_params(): - adapter = LiteLLMAnthropicMessagesAdapter() +def test_translate_anthropic_to_openai_drops_anthropic_only_params() -> None: + adapter: Final = LiteLLMAnthropicMessagesAdapter() new_kwargs, _ = adapter.translate_anthropic_to_openai( {