From e0fd25ae42d3500e793aef01a4cb05402a69b1f3 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 8 Oct 2025 22:37:58 +0000 Subject: [PATCH] fix: handle global region correctly for Vertex AI Claude models - Add custom baseURL for global region to use aiplatform.googleapis.com - Prevents incorrect hostname construction (global-aiplatform.googleapis.com) - Add comprehensive test coverage for global region scenarios Fixes #8571 --- .../__tests__/anthropic-vertex.spec.ts | 50 +++++++++++++++++++ src/api/providers/anthropic-vertex.ts | 9 +++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/api/providers/__tests__/anthropic-vertex.spec.ts b/src/api/providers/__tests__/anthropic-vertex.spec.ts index 9d83f265c7..b7189e08c5 100644 --- a/src/api/providers/__tests__/anthropic-vertex.spec.ts +++ b/src/api/providers/__tests__/anthropic-vertex.spec.ts @@ -62,8 +62,58 @@ describe("VertexHandler", () => { expect(AnthropicVertex).toHaveBeenCalledWith({ projectId: "test-project", region: "us-central1", + baseURL: undefined, }) }) + + it("should use custom baseURL for global region", () => { + handler = new AnthropicVertexHandler({ + apiModelId: "claude-3-5-sonnet-v2@20241022", + vertexProjectId: "test-project", + vertexRegion: "global", + }) + + expect(AnthropicVertex).toHaveBeenCalledWith({ + projectId: "test-project", + region: "global", + baseURL: "https://aiplatform.googleapis.com/v1", + }) + }) + + it("should use custom baseURL for global region with JSON credentials", () => { + const mockCredentials = JSON.stringify({ type: "service_account", project_id: "test" }) + handler = new AnthropicVertexHandler({ + apiModelId: "claude-3-5-sonnet-v2@20241022", + vertexProjectId: "test-project", + vertexRegion: "global", + vertexJsonCredentials: mockCredentials, + }) + + expect(AnthropicVertex).toHaveBeenCalledWith( + expect.objectContaining({ + projectId: "test-project", + region: "global", + baseURL: "https://aiplatform.googleapis.com/v1", + }), + ) + }) + + it("should use custom baseURL for global region with key file", () => { + handler = new AnthropicVertexHandler({ + apiModelId: "claude-3-5-sonnet-v2@20241022", + vertexProjectId: "test-project", + vertexRegion: "global", + vertexKeyFile: "/path/to/keyfile.json", + }) + + expect(AnthropicVertex).toHaveBeenCalledWith( + expect.objectContaining({ + projectId: "test-project", + region: "global", + baseURL: "https://aiplatform.googleapis.com/v1", + }), + ) + }) }) describe("createMessage", () => { diff --git a/src/api/providers/anthropic-vertex.ts b/src/api/providers/anthropic-vertex.ts index c70a15926d..1db60d7b26 100644 --- a/src/api/providers/anthropic-vertex.ts +++ b/src/api/providers/anthropic-vertex.ts @@ -34,10 +34,16 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple const projectId = this.options.vertexProjectId ?? "not-provided" const region = this.options.vertexRegion ?? "us-east5" + // For the "global" region, we need to use a custom base URL + // The default would be "global-aiplatform.googleapis.com" which is incorrect + // The correct endpoint for global is "aiplatform.googleapis.com" + const baseURL = region === "global" ? `https://aiplatform.googleapis.com/v1` : undefined // Let the SDK use its default for other regions + if (this.options.vertexJsonCredentials) { this.client = new AnthropicVertex({ projectId, region, + baseURL, googleAuth: new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"], credentials: safeJsonParse(this.options.vertexJsonCredentials, undefined), @@ -47,13 +53,14 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple this.client = new AnthropicVertex({ projectId, region, + baseURL, googleAuth: new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"], keyFile: this.options.vertexKeyFile, }), }) } else { - this.client = new AnthropicVertex({ projectId, region }) + this.client = new AnthropicVertex({ projectId, region, baseURL }) } }