diff --git a/headroom/providers/proxy_routes.py b/headroom/providers/proxy_routes.py index 0b1e1ae97..40a4faea5 100644 --- a/headroom/providers/proxy_routes.py +++ b/headroom/providers/proxy_routes.py @@ -732,6 +732,24 @@ def register_provider_routes(app: FastAPI, proxy: Any) -> None: ) return await vertex_publisher_passthrough(request, publisher, "rawPredict") + @app.post( + "/projects/{project}/locations/{location}/publishers/anthropic/models/{model}:rawPredict" + ) + async def vertex_raw_predict_no_version( + request: Request, + project: str, + location: str, + model: str, + ): + del project + target = _vertex_target_for_location(proxy, location).rstrip("/") + "/v1" + return await proxy.handle_anthropic_messages( + request, + target, + "vertex:anthropic", + model, + ) + @app.post( "/{api_version}/projects/{project}/locations/{location}/publishers/{publisher}/models/{model}:streamRawPredict" ) @@ -754,6 +772,25 @@ def register_provider_routes(app: FastAPI, proxy: Any) -> None: ) return await vertex_publisher_passthrough(request, publisher, "streamRawPredict") + @app.post( + "/projects/{project}/locations/{location}/publishers/anthropic/models/{model}:streamRawPredict" + ) + async def vertex_stream_raw_predict_no_version( + request: Request, + project: str, + location: str, + model: str, + ): + del project + target = _vertex_target_for_location(proxy, location).rstrip("/") + "/v1" + return await proxy.handle_anthropic_messages( + request, + target, + "vertex:anthropic", + model, + True, + ) + @app.get("/v1/models") async def list_models(request: Request): chatgpt_response = await _handle_chatgpt_model_metadata( diff --git a/tests/test_provider_proxy_routes.py b/tests/test_provider_proxy_routes.py index 32312ba37..3b8a79a17 100644 --- a/tests/test_provider_proxy_routes.py +++ b/tests/test_provider_proxy_routes.py @@ -163,6 +163,24 @@ def test_provider_passthrough_routes_forward_expected_targets(monkeypatch) -> No "model": "claude-3-5-sonnet@20240620", "force_stream": False, } + assert client.post( + "/projects/p/locations/us-central1/publishers/anthropic/models/claude-3-5-sonnet@20240620:rawPredict" + ).json() == { + "handler": "handle_anthropic_messages", + "path": "/projects/p/locations/us-central1/publishers/anthropic/models/claude-3-5-sonnet@20240620:rawPredict", + "upstream_base_url": "https://vertex.test/v1", + "provider": "vertex:anthropic", + "model": "claude-3-5-sonnet@20240620", + "force_stream": False, + } + non_anthropic_raw = client.post( + "/projects/p/locations/us-central1/publishers/google/models/gemini-2.0-flash:rawPredict" + ).json() + assert non_anthropic_raw.get("handler") != "handle_anthropic_messages" + non_anthropic_stream = client.post( + "/projects/p/locations/us-central1/publishers/google/models/gemini-2.0-flash:streamRawPredict" + ).json() + assert non_anthropic_stream.get("handler") != "handle_anthropic_messages" assert client.post("/v1beta/cachedContents").json()["sub_path"] == "cachedContents" assert client.get("/v1beta/cachedContents").json()["sub_path"] == "cachedContents" assert client.get("/v1beta/cachedContents/cache-1").json()["sub_path"] == "cachedContents" @@ -201,7 +219,7 @@ def test_provider_passthrough_routes_forward_expected_targets(monkeypatch) -> No assert len(calls) >= 16 assert len(gemini_calls) >= 1 assert len(gemini_count_calls) >= 1 - assert len(anthropic_calls) >= 1 + assert len(anthropic_calls) >= 2 def test_proxy_route_helpers_prefer_legacy_targets_and_gemini_passthrough() -> None: @@ -339,6 +357,21 @@ def test_provider_specific_routes_delegate_to_expected_proxy_handlers(monkeypatc "claude-3-5-sonnet@20240620", True, ] + assert client.post( + "/projects/p/locations/us-central1/publishers/anthropic/models/claude-3-5-sonnet@20240620:rawPredict" + ).json()["args"] == [ + "https://vertex.test/v1", + "vertex:anthropic", + "claude-3-5-sonnet@20240620", + ] + assert client.post( + "/projects/p/locations/us-central1/publishers/anthropic/models/claude-3-5-sonnet@20240620:streamRawPredict" + ).json()["args"] == [ + "https://vertex.test/v1", + "vertex:anthropic", + "claude-3-5-sonnet@20240620", + True, + ] assert client.post("/v1internal:streamGenerateContent").json()["handler"] == ( "handle_google_cloudcode_stream" ) @@ -356,7 +389,7 @@ def test_provider_specific_routes_delegate_to_expected_proxy_handlers(monkeypatc "handle_google_batch_passthrough" ) - assert len(delegated) >= 24 + assert len(delegated) >= 26 def test_openai_response_websocket_aliases_delegate_to_openai_ws_handler(monkeypatch) -> None: