mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
fix(anthropic): dedup trailing /v1 in api_base before appending /v1/messages
AnthropicMessagesConfig.get_complete_url appended /v1/messages to any api_base that didn't already end in it, so a base ending in /v1 (e.g. an Anthropic-compatible gateway root) produced /v1/v1/messages and a 404. The openai_like and deepseek messages configs already normalize this; mirror their rstrip/removesuffix handling and add the matching parametrized tests. Fixes #36956
This commit is contained in:
parent
b77923fc87
commit
d0a63b472a
2 changed files with 48 additions and 3 deletions
|
|
@ -225,9 +225,13 @@ 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
|
||||
# Normalize like OpenAILikeAnthropicMessagesConfig: an api_base that
|
||||
# already ends in /v1 must not become /v1/v1/messages.
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
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",
|
||||
[
|
||||
# default when no api_base is configured
|
||||
(None, "https://api.anthropic.com/v1/messages"),
|
||||
# bases without a version suffix
|
||||
("https://host", "https://host/v1/messages"),
|
||||
("https://host/", "https://host/v1/messages"),
|
||||
# bases that already carry /v1 must not become /v1/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"),
|
||||
# full endpoint passes through untouched
|
||||
("https://host/v1/messages", "https://host/v1/messages"),
|
||||
# provider-prefixed path segments are preserved
|
||||
("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)
|
||||
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
|
||||
Loading…
Add table
Reference in a new issue