diff --git a/changelog.d/fixes/8852-vertex-claude-partner-models.md b/changelog.d/fixes/8852-vertex-claude-partner-models.md new file mode 100644 index 0000000000..b5b616fd47 --- /dev/null +++ b/changelog.d/fixes/8852-vertex-claude-partner-models.md @@ -0,0 +1 @@ +- **fix(executors):** Vertex AI now routes current-generation Claude models (`claude-sonnet-4-6`, `claude-haiku-4-5`, etc.) through the partner endpoint instead of misrouting them as Google-publisher models ([#8852](https://github.com/diegosouzapw/OmniRoute/pull/8852)) — thanks @wgordon17 diff --git a/open-sse/executors/vertex.ts b/open-sse/executors/vertex.ts index 4ca1a1ab05..0344a456d6 100644 --- a/open-sse/executors/vertex.ts +++ b/open-sse/executors/vertex.ts @@ -116,9 +116,10 @@ export async function getAccessToken(sa: ServiceAccount): Promise { } const PARTNER_MODELS = new Set([ - "claude-3-5-sonnet", - "claude-3-opus", - "claude-3-haiku", + // Generic prefix, not pinned to a version: every Claude model on Vertex is an Anthropic + // partner model, never a Google-publisher one. Pinned prefixes (e.g. "claude-3-5-sonnet") + // silently break every time Anthropic ships a new generation — see issue #1985. + "claude-", "deepseek-v3", "deepseek-v3.2", "deepseek-v4", diff --git a/tests/unit/executor-vertex-extended.test.ts b/tests/unit/executor-vertex-extended.test.ts index f7ac599518..b8cbbe5900 100644 --- a/tests/unit/executor-vertex-extended.test.ts +++ b/tests/unit/executor-vertex-extended.test.ts @@ -90,6 +90,28 @@ test("VertexExecutor.buildUrl routes partner and org-prefixed models to the glob ); }); +test("VertexExecutor.buildUrl routes current-generation Claude models to the global partner endpoint (#1985)", () => { + const executor = new VertexExecutor(); + + // These model IDs post-date the old pinned "claude-3-5-sonnet" / "claude-3-opus" / + // "claude-3-haiku" prefixes and were previously misrouted to the Google-publisher path. + const claude4Sonnet = executor.buildUrl("claude-sonnet-4-6", false, 0, { + apiKey: createServiceAccountJson({ projectId: "proj-claude" }), + }); + const claude4Haiku = executor.buildUrl("claude-haiku-4-5@20251001", true, 0, { + apiKey: createServiceAccountJson({ projectId: "proj-claude" }), + }); + + assert.equal( + claude4Sonnet, + "https://aiplatform.googleapis.com/v1/projects/proj-claude/locations/global/endpoints/openapi/chat/completions" + ); + assert.equal( + claude4Haiku, + "https://aiplatform.googleapis.com/v1/projects/proj-claude/locations/global/endpoints/openapi/chat/completions" + ); +}); + test("VertexExecutor.buildHeaders includes Bearer token and SSE Accept only for streaming", () => { const executor = new VertexExecutor(); const streamHeaders = executor.buildHeaders({ accessToken: "ya29.stream" }, true);