From eb4ff6df8165320d88c6a45747c5a780c9646990 Mon Sep 17 00:00:00 2001 From: Sally O'Malley Date: Mon, 23 Feb 2026 11:04:31 -0500 Subject: [PATCH] Allow Claude model requests to route through Google Vertex AI (#23985) * feat: add anthropic-vertex provider for Claude via GCP Vertex AI Co-Authored-By: Claude Opus 4.6 Signed-off-by: sallyom * docs: add anthropic-vertex provider guide Co-Authored-By: Claude Opus 4.6 Signed-off-by: sallyom * Agents: validate Anthropic Vertex project env * Changelog: format update for Vertex entry * Providers: rename Anthropic Vertex to Google Vertex Claude * Providers: remove Vertex Claude provider path * Models: normalize Vercel Claude shorthand refs * Onboarding: default Vercel model to Claude shorthand * Changelog: add @vincentkoc credit for #23985 * Onboarding: keep canonical Vercel default model ref * Tests: expand Vercel model normalization coverage --------- Signed-off-by: sallyom Co-authored-by: Claude Opus 4.6 Co-authored-by: Vincent Koc --- CHANGELOG.md | 2 ++ docs/providers/vercel-ai-gateway.md | 8 ++++++++ src/agents/model-selection.test.ts | 25 +++++++++++++++++++++++++ src/agents/model-selection.ts | 7 +++++++ 4 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 960ae6052..579c3945c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Docs: https://docs.openclaw.ai ### Changes +- Providers/Vercel AI Gateway: accept Claude shorthand model refs (`vercel-ai-gateway/claude-*`) by normalizing to canonical Anthropic-routed model ids. (#23985) Thanks @sallyom, @markbooch, and @vincentkoc. + ### Breaking ### Fixes diff --git a/docs/providers/vercel-ai-gateway.md b/docs/providers/vercel-ai-gateway.md index 726a6040f..3b5053fba 100644 --- a/docs/providers/vercel-ai-gateway.md +++ b/docs/providers/vercel-ai-gateway.md @@ -48,3 +48,11 @@ openclaw onboard --non-interactive \ If the Gateway runs as a daemon (launchd/systemd), make sure `AI_GATEWAY_API_KEY` is available to that process (for example, in `~/.openclaw/.env` or via `env.shellEnv`). + +## Model ID shorthand + +OpenClaw accepts Vercel Claude shorthand model refs and normalizes them at +runtime: + +- `vercel-ai-gateway/claude-opus-4.6` -> `vercel-ai-gateway/anthropic/claude-opus-4.6` +- `vercel-ai-gateway/opus-4.6` -> `vercel-ai-gateway/anthropic/claude-opus-4-6` diff --git a/src/agents/model-selection.test.ts b/src/agents/model-selection.test.ts index b903189b2..df4298636 100644 --- a/src/agents/model-selection.test.ts +++ b/src/agents/model-selection.test.ts @@ -97,6 +97,31 @@ describe("model-selection", () => { }); }); + it("normalizes Vercel Claude shorthand to anthropic-prefixed model ids", () => { + expect(parseModelRef("vercel-ai-gateway/claude-opus-4.6", "openai")).toEqual({ + provider: "vercel-ai-gateway", + model: "anthropic/claude-opus-4.6", + }); + expect(parseModelRef("vercel-ai-gateway/opus-4.6", "openai")).toEqual({ + provider: "vercel-ai-gateway", + model: "anthropic/claude-opus-4-6", + }); + }); + + it("keeps already-prefixed Vercel Anthropic models unchanged", () => { + expect(parseModelRef("vercel-ai-gateway/anthropic/claude-opus-4.6", "openai")).toEqual({ + provider: "vercel-ai-gateway", + model: "anthropic/claude-opus-4.6", + }); + }); + + it("passes through non-Claude Vercel model ids unchanged", () => { + expect(parseModelRef("vercel-ai-gateway/openai/gpt-5.2", "openai")).toEqual({ + provider: "vercel-ai-gateway", + model: "openai/gpt-5.2", + }); + }); + it("should handle invalid slash usage", () => { expect(parseModelRef("/", "anthropic")).toBeNull(); expect(parseModelRef("anthropic/", "anthropic")).toBeNull(); diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index 6f6e6d10f..acdc2faf1 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -109,6 +109,13 @@ function normalizeProviderModelId(provider: string, model: string): string { if (provider === "anthropic") { return normalizeAnthropicModelId(model); } + if (provider === "vercel-ai-gateway" && !model.includes("/")) { + // Allow Vercel-specific Claude refs without an upstream prefix. + const normalizedAnthropicModel = normalizeAnthropicModelId(model); + if (normalizedAnthropicModel.startsWith("claude-")) { + return `anthropic/${normalizedAnthropicModel}`; + } + } if (provider === "google") { return normalizeGoogleModelId(model); }