feat: add Vertex AI Anthropic provider for Claude on GCP#5994
feat: add Vertex AI Anthropic provider for Claude on GCP#5994markbooch wants to merge 3 commits intoopenclaw:mainfrom
Conversation
Adds support for Claude models hosted on Google Cloud Vertex AI, allowing users to leverage their GCP credits directly without routing through intermediaries like OpenRouter. Features: - Auto-discovery when GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION are set - Uses gcloud Application Default Credentials for authentication - Supports all Claude models available on Vertex AI (Opus, Sonnet, Haiku) - Full feature parity: streaming, tools, thinking/reasoning, vision Configuration: - Set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION env vars - Run 'gcloud auth application-default login' for authentication - Models appear as vertex-anthropic/claude-opus-4-5@20251101 etc. Files: - src/agents/vertex-anthropic-models.ts: Model catalog and provider builder - src/agents/vertex-anthropic-models.test.ts: Unit tests - src/agents/models-config.providers.ts: Import and auto-discovery - src/agents/model-auth.ts: Add gcloud ADC auth support - src/commands/models/list.status-command.ts: Add to env probe list - docs/vertex-anthropic.md: Setup and usage documentation - CHANGELOG.md: Add changelog entry
| // Vertex Anthropic provider - auto-discover if GCP credentials are available | ||
| const gcpProject = resolveGcpProject(); | ||
| const gcpLocation = resolveGcpLocation(); | ||
| if (gcpProject && gcpLocation && hasGcloudAdc()) { | ||
| providers["vertex-anthropic"] = { | ||
| ...buildVertexAnthropicProvider({ project: gcpProject, location: gcpLocation }), | ||
| apiKey: "gcloud-adc", // Placeholder; actual auth uses gcloud ADC | ||
| }; |
There was a problem hiding this comment.
Auto-discovery for vertex-anthropic only triggers when hasGcloudAdc() is true, but hasGcloudAdc currently returns true if GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT are set. Those env vars are not credentials, so this can cause the provider to be auto-added even when no ADC/service account is available, leading to runtime auth failures after the model appears “available”.
Representative occurrence: src/agents/models-config.providers.ts:470-477 (root cause in src/agents/vertex-anthropic-models.ts:181-187).
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/models-config.providers.ts
Line: 470:477
Comment:
Auto-discovery for `vertex-anthropic` only triggers when `hasGcloudAdc()` is true, but `hasGcloudAdc` currently returns true if `GOOGLE_CLOUD_PROJECT`/`GCLOUD_PROJECT` are set. Those env vars are not credentials, so this can cause the provider to be auto-added even when no ADC/service account is available, leading to runtime auth failures after the model appears “available”.
Representative occurrence: `src/agents/models-config.providers.ts:470-477` (root cause in `src/agents/vertex-anthropic-models.ts:181-187`).
How can I resolve this? If you propose a fix, please make it concise.| export async function resolveImplicitVertexAnthropicProvider(params: { | ||
| agentDir: string; | ||
| env?: NodeJS.ProcessEnv; | ||
| }): Promise<ProviderConfig | null> { | ||
| const env = params.env ?? process.env; |
There was a problem hiding this comment.
resolveImplicitVertexAnthropicProvider is declared async and takes agentDir, but it doesn’t await anything and agentDir is unused. This looks like leftover scaffolding and can be simplified to avoid dead params/API surface area.
| export async function resolveImplicitVertexAnthropicProvider(params: { | |
| agentDir: string; | |
| env?: NodeJS.ProcessEnv; | |
| }): Promise<ProviderConfig | null> { | |
| const env = params.env ?? process.env; | |
| export function resolveImplicitVertexAnthropicProvider(params: { | |
| env?: NodeJS.ProcessEnv; | |
| }): ProviderConfig | null { |
(Or remove the function entirely if resolveImplicitProviders is the only call site.)
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/vertex-anthropic-models.ts
Line: 210:214
Comment:
`resolveImplicitVertexAnthropicProvider` is declared `async` and takes `agentDir`, but it doesn’t await anything and `agentDir` is unused. This looks like leftover scaffolding and can be simplified to avoid dead params/API surface area.
```suggestion
export function resolveImplicitVertexAnthropicProvider(params: {
env?: NodeJS.ProcessEnv;
}): ProviderConfig | null {
```
(Or remove the function entirely if `resolveImplicitProviders` is the only call site.)
How can I resolve this? If you propose a fix, please make it concise.
Additional Comments (1)
Also affects Files/lines: Prompt To Fix With AIThis is a comment left during a code review.
Path: src/agents/model-auth.ts
Line: 193:200
Comment:
`resolveApiKeyForProvider` sets `mode` based on `envResolved.source.includes("OAUTH_TOKEN")`, but for `vertex-anthropic`/`google-vertex` the env resolver returns `source: "gcloud adc"`. That makes the mode default to `"api-key"` even though the provider is configured with `auth: "token"`, which can cause confusing status output and potentially incorrect downstream behavior if anything branches on `auth.mode`.
Also affects `google-vertex` via the same `source: "gcloud adc"` path.
Files/lines: `src/agents/model-auth.ts:193-200`, env source set at `src/agents/model-auth.ts:263-277`
How can I resolve this? If you propose a fix, please make it concise. |
- hasGcloudAdc() now only returns true when GOOGLE_APPLICATION_CREDENTIALS is set, not just project env vars (prevents false positive auto-discovery) - resolveApiKeyForProvider() correctly sets mode='token' for gcloud ADC (was defaulting to 'api-key' due to source string mismatch) - Removed unused async/agentDir from resolveImplicitVertexAnthropicProvider
|
Thanks for the review feedback! Pushed a fix (9583edd) addressing all three issues:
|
- Fix hasGcloudAdc to only check GOOGLE_APPLICATION_CREDENTIALS (actual credentials) - Remove unused async/agentDir from resolveImplicitVertexAnthropicProvider - Fix markdown table formatting in docs
|
CLAWDINATOR FIELD REPORT // PR Closure I am CLAWDINATOR — cybernetic crustacean, maintainer triage bot for OpenClaw. I was sent from the future to keep this repo shipping clean code. Context: OpenClaw serves ~1M users. Provider integrations and platform additions are not being accepted without prior discussion. The queue is too large to review unsolicited features. If this integration is critical for users, open a GitHub issue first to discuss with maintainers. TERMINATED. 🤖 This is an automated message from CLAWDINATOR, the OpenClaw maintainer bot. |
Summary
Adds support for Claude models hosted on Google Cloud Vertex AI, allowing users to leverage their GCP credits directly without routing through intermediaries like OpenRouter (which charges 5% on all requests).
Motivation
Users with GCP credits want to use Claude models directly on Vertex AI without paying intermediary fees. This PR adds a new
vertex-anthropicprovider that:GOOGLE_CLOUD_PROJECTandGOOGLE_CLOUD_LOCATIONare setChanges
src/agents/vertex-anthropic-models.tssrc/agents/vertex-anthropic-models.test.tssrc/agents/models-config.providers.tssrc/agents/model-auth.tssrc/commands/models/list.status-command.tsdocs/vertex-anthropic.mdCHANGELOG.mdUsage
Testing
AI Disclosure
This PR was developed with AI assistance (Claude). The implementation was tested on a live GCP instance with actual Vertex AI API calls confirming functionality.
cc @steipete
Greptile Overview
Greptile Summary
Adds a new
vertex-anthropicmodel provider that targets Claude models hosted on Google Cloud Vertex AI, including a static model catalog, env-based auto-discovery when GCP project/location are set, and wiring intomodels list/statusso users can see the provider and credential state. Also extends env auth resolution sovertex-anthropicreuses the existinggoogle-vertexgcloud ADC token flow.Main integration points are provider auto-discovery (
src/agents/models-config.providers.ts) and env credential resolution (src/agents/model-auth.ts), with supporting docs and tests for the new helper module.Confidence Score: 3/5
(2/5) Greptile learns from your feedback when you react with thumbs up/down!