diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py b/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py index 032bf0130ce..d5e7279bef0 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py @@ -290,9 +290,11 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig): stream: bool | None = None, ) -> str: api_base = AnthropicModelInfo.get_api_base(api_base) or "https://api.anthropic.com" - if not api_base.endswith("/v1/messages"): - api_base = f"{api_base}/v1/messages" - return api_base + base = api_base.rstrip("/") + if base.endswith("/v1/messages"): + return base + base = base.removesuffix("/v1") + return f"{base}/v1/messages" def validate_anthropic_messages_environment( self, diff --git a/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_messages_get_complete_url.py b/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_messages_get_complete_url.py new file mode 100644 index 00000000000..46082bb8198 --- /dev/null +++ b/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_messages_get_complete_url.py @@ -0,0 +1,37 @@ +import pytest + +from litellm.llms.anthropic.experimental_pass_through.messages.transformation import ( + AnthropicMessagesConfig, +) + + +@pytest.fixture +def config() -> AnthropicMessagesConfig: + return AnthropicMessagesConfig() + + +@pytest.mark.parametrize( + "api_base, expected", + [ + (None, "https://api.anthropic.com/v1/messages"), + ("https://host", "https://host/v1/messages"), + ("https://host/", "https://host/v1/messages"), + ("https://host/v1", "https://host/v1/messages"), + ("https://host/v1/", "https://host/v1/messages"), + ("https://api.groq.com/openai/v1", "https://api.groq.com/openai/v1/messages"), + ("https://host/v1/messages", "https://host/v1/messages"), + ("https://gateway.example.com/anthropic", "https://gateway.example.com/anthropic/v1/messages"), + ("https://gateway.example.com/anthropic/v1", "https://gateway.example.com/anthropic/v1/messages"), + ], +) +def test_get_complete_url_deduplicates_trailing_v1(config, api_base, expected, monkeypatch): + monkeypatch.delenv("ANTHROPIC_API_BASE", raising=False) + monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False) + url = config.get_complete_url( + api_base=api_base, + api_key="sk-test", + model="claude-sonnet-4-5", + optional_params={}, + litellm_params={}, + ) + assert url == expected