This commit is contained in:
d 🔹 2026-04-27 19:21:42 +00:00 committed by GitHub
commit 439e9c7dc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 99 additions and 11 deletions

View file

@ -51,17 +51,20 @@ class VertexAIPartnerModelsAnthropicMessagesConfig(AnthropicMessagesConfig, Vert
# Authorization already in headers, but we still need project_id
project_id = vertex_ai_project
# Always calculate api_base if not provided, regardless of Authorization header
if api_base is None:
api_base = self.get_complete_vertex_url(
custom_api_base=api_base,
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
project_id=project_id or "",
partner=VertexPartnerProvider.claude,
stream=optional_params.get("stream", False),
model=model,
)
# Always calculate api_base regardless of whether one was provided.
# get_complete_vertex_url handles custom api_base by appending the
# required endpoint suffix (:streamRawPredict / :rawPredict) via
# _check_custom_proxy. Without this, custom api_base values are
# used as-is and the Vertex AI endpoint returns 404.
api_base = self.get_complete_vertex_url(
custom_api_base=api_base,
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
project_id=project_id or "",
partner=VertexPartnerProvider.claude,
stream=optional_params.get("stream", False),
model=model,
)
headers["content-type"] = "application/json"

View file

@ -311,3 +311,88 @@ def test_transform_anthropic_messages_request_removes_scope_from_cache_control()
# scope removed from message content
assert "scope" not in result["messages"][0]["content"][0]["cache_control"]
assert result["messages"][0]["content"][0]["cache_control"]["type"] == "ephemeral"
def test_validate_environment_custom_api_base_calls_get_complete_vertex_url():
"""Regression test for #25748: custom api_base must still go through
get_complete_vertex_url so that the required endpoint suffix
(:streamRawPredict / :rawPredict) is appended."""
config = VertexAIPartnerModelsAnthropicMessagesConfig()
headers = {}
litellm_params = {
"vertex_ai_project": "test-project",
"vertex_ai_location": "us-central1",
"vertex_credentials": "{}",
}
custom_base = (
"https://aiplatform.us.rep.googleapis.com/v1/projects/my-project"
"/locations/us/publishers/anthropic/models/claude-sonnet-4-5@20250929"
)
optional_params = {"stream": True}
with patch.object(
config, "_ensure_access_token", return_value=("token", "test-project")
), patch.object(
config,
"get_complete_vertex_url",
return_value=f"{custom_base}:streamRawPredict",
) as mock_get_url:
updated_headers, api_base = config.validate_anthropic_messages_environment(
headers=headers,
model="claude-sonnet-4-5@20250929",
messages=[],
optional_params=optional_params,
litellm_params=litellm_params,
api_base=custom_base,
)
# get_complete_vertex_url MUST be called even with a custom api_base
assert mock_get_url.called, (
"get_complete_vertex_url should be called when api_base is provided "
"so that the endpoint suffix (:streamRawPredict) is appended"
)
assert mock_get_url.call_args.kwargs["custom_api_base"] == custom_base
# The returned api_base should have the suffix
assert api_base == f"{custom_base}:streamRawPredict"
def test_validate_environment_custom_api_base_non_streaming():
"""Regression test for #25748 (non-streaming path): custom api_base must
still go through get_complete_vertex_url so that :rawPredict is appended."""
config = VertexAIPartnerModelsAnthropicMessagesConfig()
headers = {}
litellm_params = {
"vertex_ai_project": "test-project",
"vertex_ai_location": "us-central1",
"vertex_credentials": "{}",
}
custom_base = (
"https://aiplatform.us.rep.googleapis.com/v1/projects/my-project"
"/locations/us/publishers/anthropic/models/claude-sonnet-4-5@20250929"
)
optional_params = {"stream": False}
with patch.object(
config, "_ensure_access_token", return_value=("token", "test-project")
), patch.object(
config,
"get_complete_vertex_url",
return_value=f"{custom_base}:rawPredict",
) as mock_get_url:
updated_headers, api_base = config.validate_anthropic_messages_environment(
headers=headers,
model="claude-sonnet-4-5@20250929",
messages=[],
optional_params=optional_params,
litellm_params=litellm_params,
api_base=custom_base,
)
# get_complete_vertex_url MUST be called even with a custom api_base
assert mock_get_url.called, (
"get_complete_vertex_url should be called when api_base is provided "
"so that the endpoint suffix (:rawPredict) is appended"
)
assert mock_get_url.call_args.kwargs["custom_api_base"] == custom_base
# The returned api_base should have the non-streaming suffix
assert api_base == f"{custom_base}:rawPredict"