diff --git a/litellm/llms/vertex_ai/common_utils.py b/litellm/llms/vertex_ai/common_utils.py index a36c920dda0..970759479fe 100644 --- a/litellm/llms/vertex_ai/common_utils.py +++ b/litellm/llms/vertex_ai/common_utils.py @@ -998,6 +998,16 @@ def replace_project_and_location_in_route(requested_route: str, vertex_project: return modified_route +def _api_version_for_route(requested_route: str) -> Literal["v1", "v1beta1"]: + return "v1beta1" if "cachedContent" in requested_route else "v1" + + +def _with_api_version(requested_route: str) -> str: + if not requested_route.startswith("/projects/"): + return requested_route + return f"/{_api_version_for_route(requested_route)}{requested_route}" + + def construct_target_url( base_url: str, requested_route: str, @@ -1017,18 +1027,19 @@ def construct_target_url( new_base_url: Final = httpx.URL(base_url) if "locations" in requested_route: # contains the target project id + location - if vertex_project and vertex_location: - requested_route = replace_project_and_location_in_route(requested_route, vertex_project, vertex_location) - return new_base_url.copy_with(path=requested_route) + targeted_route: Final = ( + replace_project_and_location_in_route(requested_route, vertex_project, vertex_location) + if vertex_project and vertex_location + else requested_route + ) + return new_base_url.copy_with(path=_with_api_version(targeted_route)) """ - Add endpoint version (e.g. v1beta for cachedContent, v1 for rest) - Add default project id - Add default location """ - vertex_version: Literal["v1", "v1beta1"] = "v1" - if "cachedContent" in requested_route: - vertex_version = "v1beta1" + vertex_version: Literal["v1", "v1beta1"] = _api_version_for_route(requested_route) # Check if the requested route starts with a version # e.g. /v1beta1/publishers/google/models/gemini-3-pro-preview:streamGenerateContent diff --git a/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py b/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py index d1d751989ea..624646ab328 100644 --- a/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py +++ b/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py @@ -964,6 +964,48 @@ def test_construct_target_url_with_version_prefix(): assert str(target_url) == expected_url +@pytest.mark.parametrize( + ("requested_route", "expected_url"), + [ + ( + "/projects/test-project/locations/global/publishers/anthropic/models/claude-sonnet-4-6:streamRawPredict", + "https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/anthropic/models/claude-sonnet-4-6:streamRawPredict", + ), + ( + "/projects/test-project/locations/global/publishers/anthropic/models/count-tokens:rawPredict", + "https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/anthropic/models/count-tokens:rawPredict", + ), + ( + "/projects/other-project/locations/us-east5/publishers/anthropic/models/claude-sonnet-4-6:rawPredict", + "https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/anthropic/models/claude-sonnet-4-6:rawPredict", + ), + ( + "/projects/test-project/locations/global/cachedContents", + "https://aiplatform.googleapis.com/v1beta1/projects/test-project/locations/global/cachedContents", + ), + ( + "/v1/projects/test-project/locations/global/publishers/anthropic/models/claude-sonnet-4-6:streamRawPredict", + "https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/anthropic/models/claude-sonnet-4-6:streamRawPredict", + ), + ( + "/v1beta1/projects/test-project/locations/global/cachedContents", + "https://aiplatform.googleapis.com/v1beta1/projects/test-project/locations/global/cachedContents", + ), + ], +) +def test_construct_target_url_versionless_project_route_gets_api_version(requested_route, expected_url): + from litellm.llms.vertex_ai.common_utils import construct_target_url + + target_url = construct_target_url( + base_url="https://aiplatform.googleapis.com", + requested_route=requested_route, + vertex_project="test-project", + vertex_location="global", + ) + + assert str(target_url) == expected_url + + def test_fix_enum_types(): """ Test _fix_enum_types function removes enum fields when type is not string.