feat(google): add Google Vertex AI provider with ADC auth and global endpoint routing#60860
feat(google): add Google Vertex AI provider with ADC auth and global endpoint routing#60860PewterZz wants to merge 12 commits into
Conversation
Greptile SummaryThis PR adds a
Confidence Score: 4/5Safe to merge after fixing the wrong auth-presence predicate in model-auth-env.ts; all other concerns are minor. One P1 defect: google-vertex availability is gated by the Anthropic Vertex auth check (ANTHROPIC_VERTEX_USE_GCP_METADATA=1 without an ADC file returns the sentinel but fails at token-fetch time). The rest of the implementation — Vertex URL routing, ADC token exchange, thought_signature capture, provider registration — looks correct. src/agents/model-auth-env.ts — wrong auth-presence function used for google-vertex Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/model-auth-env.ts
Line: 45-46
Comment:
**Wrong auth-presence check for `google-vertex`**
`hasAnthropicVertexAvailableAuth` is imported from `anthropic-vertex-auth-presence.ts` and returns `true` when `ANTHROPIC_VERTEX_USE_GCP_METADATA=1` *even with no ADC file on disk*. If a user sets that env var (for their Anthropic Vertex setup) but has no `application_default_credentials.json`, this block returns the `GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER` sentinel — but `resolveGoogleVertexAccessToken` in `google-vertex-adc.ts` then reads the ADC file, gets `null`, and the request fails at runtime with no helpful error.
The equivalent check for Google's ADC presence is `hasGoogleVertexAvailableAuth` (already exported from `extensions/google/vertex-region.ts`), but since that lives in the extension package it can't be imported here directly. The same gating logic that the extension's catalog uses (`canReadAdc`) should be replicated in core — similar to how `canReadAnthropicVertexAdc` is defined locally in `anthropic-vertex-auth-presence.ts`. A minimal fix is to inline an ADC-file-readable check here, or add a dedicated `hasGoogleVertexAdcAvailableAuth` helper in a new `google-vertex-auth-presence.ts` alongside its Anthropic sibling.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/agents/google-vertex-adc.ts
Line: 81-98
Comment:
**Service-account ADC type silently falls through**
Only `authorized_user` credentials are exchanged for a token; all other ADC types (most commonly `service_account` JSON key files) reach the final `return null` with no diagnostic. Production GCP workloads typically use service-account keys, so this creates a confusing silent failure. Consider throwing or logging a clear message when the ADC file is present but its `type` is unhandled, so users aren't left wondering why auth is failing.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/google/vertex-provider-catalog.ts
Line: 13
Comment:
**Duplicated marker constant**
`GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER` is defined as a private constant in both this file and `vertex-region.ts` (and exported from `src/agents/model-auth-markers.ts`). Within the extension package, `vertex-provider-catalog.ts` could import it from `./vertex-region.js` if it were exported there, avoiding silent value drift if the marker is ever renamed.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat(google): add Google Vertex AI provi..." | Re-trigger Greptile Re-review progress:
|
| if (hasAnthropicVertexAvailableAuth(env)) { | ||
| return { apiKey: GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER, source: "gcloud adc" }; |
There was a problem hiding this comment.
Wrong auth-presence check for
google-vertex
hasAnthropicVertexAvailableAuth is imported from anthropic-vertex-auth-presence.ts and returns true when ANTHROPIC_VERTEX_USE_GCP_METADATA=1 even with no ADC file on disk. If a user sets that env var (for their Anthropic Vertex setup) but has no application_default_credentials.json, this block returns the GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER sentinel — but resolveGoogleVertexAccessToken in google-vertex-adc.ts then reads the ADC file, gets null, and the request fails at runtime with no helpful error.
The equivalent check for Google's ADC presence is hasGoogleVertexAvailableAuth (already exported from extensions/google/vertex-region.ts), but since that lives in the extension package it can't be imported here directly. The same gating logic that the extension's catalog uses (canReadAdc) should be replicated in core — similar to how canReadAnthropicVertexAdc is defined locally in anthropic-vertex-auth-presence.ts. A minimal fix is to inline an ADC-file-readable check here, or add a dedicated hasGoogleVertexAdcAvailableAuth helper in a new google-vertex-auth-presence.ts alongside its Anthropic sibling.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/model-auth-env.ts
Line: 45-46
Comment:
**Wrong auth-presence check for `google-vertex`**
`hasAnthropicVertexAvailableAuth` is imported from `anthropic-vertex-auth-presence.ts` and returns `true` when `ANTHROPIC_VERTEX_USE_GCP_METADATA=1` *even with no ADC file on disk*. If a user sets that env var (for their Anthropic Vertex setup) but has no `application_default_credentials.json`, this block returns the `GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER` sentinel — but `resolveGoogleVertexAccessToken` in `google-vertex-adc.ts` then reads the ADC file, gets `null`, and the request fails at runtime with no helpful error.
The equivalent check for Google's ADC presence is `hasGoogleVertexAvailableAuth` (already exported from `extensions/google/vertex-region.ts`), but since that lives in the extension package it can't be imported here directly. The same gating logic that the extension's catalog uses (`canReadAdc`) should be replicated in core — similar to how `canReadAnthropicVertexAdc` is defined locally in `anthropic-vertex-auth-presence.ts`. A minimal fix is to inline an ADC-file-readable check here, or add a dedicated `hasGoogleVertexAdcAvailableAuth` helper in a new `google-vertex-auth-presence.ts` alongside its Anthropic sibling.
How can I resolve this? If you propose a fix, please make it concise.| adc.project_id || | ||
| undefined; | ||
|
|
||
| if (adc.type === "authorized_user") { | ||
| const result = await refreshAuthorizedUserToken(adc as AdcAuthorizedUser); | ||
| cachedToken = { | ||
| accessToken: result.access_token, | ||
| projectId, | ||
| expiresAt: Date.now() + result.expires_in * 1000, | ||
| }; | ||
| return cachedToken; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| export function clearGoogleVertexTokenCache(): void { | ||
| cachedToken = null; |
There was a problem hiding this comment.
Service-account ADC type silently falls through
Only authorized_user credentials are exchanged for a token; all other ADC types (most commonly service_account JSON key files) reach the final return null with no diagnostic. Production GCP workloads typically use service-account keys, so this creates a confusing silent failure. Consider throwing or logging a clear message when the ADC file is present but its type is unhandled, so users aren't left wondering why auth is failing.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/google-vertex-adc.ts
Line: 81-98
Comment:
**Service-account ADC type silently falls through**
Only `authorized_user` credentials are exchanged for a token; all other ADC types (most commonly `service_account` JSON key files) reach the final `return null` with no diagnostic. Production GCP workloads typically use service-account keys, so this creates a confusing silent failure. Consider throwing or logging a clear message when the ADC file is present but its `type` is unhandled, so users aren't left wondering why auth is failing.
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| export const GOOGLE_VERTEX_DEFAULT_MODEL_ID = "gemini-3.1-pro-preview"; | ||
| const GOOGLE_VERTEX_DEFAULT_CONTEXT_WINDOW = 1_000_000; | ||
| const GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER = "gcp-vertex-google-credentials"; |
There was a problem hiding this comment.
GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER is defined as a private constant in both this file and vertex-region.ts (and exported from src/agents/model-auth-markers.ts). Within the extension package, vertex-provider-catalog.ts could import it from ./vertex-region.js if it were exported there, avoiding silent value drift if the marker is ever renamed.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/google/vertex-provider-catalog.ts
Line: 13
Comment:
**Duplicated marker constant**
`GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER` is defined as a private constant in both this file and `vertex-region.ts` (and exported from `src/agents/model-auth-markers.ts`). Within the extension package, `vertex-provider-catalog.ts` could import it from `./vertex-region.js` if it were exported there, avoiding silent value drift if the marker is ever renamed.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ebab852f19
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (adc.type === "authorized_user") { | ||
| const result = await refreshAuthorizedUserToken(adc as AdcAuthorizedUser); | ||
| cachedToken = { | ||
| accessToken: result.access_token, | ||
| projectId, |
There was a problem hiding this comment.
Support non-user ADC credentials for Vertex auth
The new Vertex token resolver only exchanges tokens when the ADC file is type: "authorized_user"; all other ADC types fall through with no token. In environments that use service-account ADC (GOOGLE_APPLICATION_CREDENTIALS in CI/GKE/Cloud Run), this makes runtime auth unresolved and requests end up unauthenticated (or sent with the marker as an API key), causing Vertex calls to fail consistently. Please add token minting for service-account/metadata ADC or refuse to advertise Vertex auth when the ADC type is unsupported.
Useful? React with 👍 / 👎.
| if (hasAnthropicVertexAvailableAuth(env)) { | ||
| return { apiKey: GCP_VERTEX_GOOGLE_CREDENTIALS_MARKER, source: "gcloud adc" }; |
There was a problem hiding this comment.
Gate google-vertex env auth with the correct capability check
The google-vertex branch uses hasAnthropicVertexAvailableAuth, which can return true via Anthropic-specific metadata opt-in even when Google Vertex cannot actually resolve a token in this implementation. That emits the gcp-vertex-google-credentials marker and leads to failed runtime auth for google-vertex configs without readable Google ADC credentials. This should use a Google-specific availability predicate that matches what the Google resolver can truly handle.
Useful? React with 👍 / 👎.
| return { | ||
| ...implicit, | ||
| ...existing, |
There was a problem hiding this comment.
Recompute Vertex location when baseUrl is overridden
Merging implicit and configured provider settings allows existing.baseUrl to override the implicit endpoint, but the region/header state is not recomputed from that effective URL. As a result, users who set models.providers.google-vertex.baseUrl to another region can still send /locations/us-central1/... paths, which causes Vertex INVALID_ARGUMENT request routing failures. The merge should derive location from the final base URL (or synchronize headers accordingly).
Useful? React with 👍 / 👎.
ebab852 to
72aece9
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4e0c16151e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const origin = baseUrl.replace(/\/+$/, ""); | ||
| const modelPath = modelId.startsWith("publishers/") | ||
| ? modelId | ||
| : `publishers/google/models/${modelId}`; | ||
| return `${origin}/v1/projects/${projectId}/locations/${location}/${modelPath}:streamGenerateContent?alt=sse`; |
There was a problem hiding this comment.
Strip path from Vertex baseUrl before composing request URL
This URL builder uses the full configured baseUrl as the prefix and then appends /v1/projects/..., so a valid override like https://us-central1-aiplatform.googleapis.com/v1 produces .../v1/v1/projects/... and Vertex requests fail. This commit newly supports google-vertex baseUrl overrides, so users who copy a /v1 endpoint form will get hard request failures until the builder normalizes to URL origin (or strips an existing /v1) before appending the path.
Useful? React with 👍 / 👎.
| if (params.model.provider === "google-vertex") { | ||
| const boundaryAwareStreamFn = createBoundaryAwareStreamFnForModel(params.model); | ||
| if (boundaryAwareStreamFn) { | ||
| return boundaryAwareStreamFn; |
There was a problem hiding this comment.
Preserve explicit session streamFn for google-vertex models
This new provider-specific branch returns a boundary-aware stream function before the existing custom-stream fallback, so any explicitly supplied currentStreamFn is ignored whenever model.provider === "google-vertex". That is a behavior regression for integrations that attach custom stream wrappers (for telemetry, retries, policy checks, etc.), because those wrappers now silently stop running for Vertex models.
Useful? React with 👍 / 👎.
f89cdae to
e47140a
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 39e250c4ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const modelPath = modelId.startsWith("publishers/") | ||
| ? modelId | ||
| : `publishers/google/models/${modelId}`; |
There was a problem hiding this comment.
Preserve prequalified Vertex model IDs in request paths
The Vertex URL builder always prefixes non-publishers/ model IDs with publishers/google/models/, so inputs like models/gemini-2.5-pro or tunedModels/... become invalid paths such as .../publishers/google/models/models/.... This causes Vertex requests to fail for model ID formats that are already accepted in the non-Vertex Google path logic, so the builder should treat already-qualified IDs as complete instead of blindly prefixing.
Useful? React with 👍 / 👎.
| ("quota_project_id" in adc ? adc.quota_project_id : undefined) || | ||
| adc.project_id || |
There was a problem hiding this comment.
Prefer ADC project_id over quota_project_id for routing
This resolves the ADC project as quota_project_id before project_id, which conflicts with the implicit provider project resolution (in extensions/google/vertex-region.ts) that prefers project_id first. Because request URL construction prioritizes the token-derived project, ADC files containing both fields can route calls to the quota/billing project instead of the intended Vertex project, leading to avoidable permission or not-found failures.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a98d4fd690
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const normalizedBaseUrl = normalizeGoogleApiBaseUrl(model.baseUrl); | ||
| return `${normalizedBaseUrl}/${resolveGoogleModelPath(model.id)}:streamGenerateContent?alt=sse`; |
There was a problem hiding this comment.
Fail fast when Vertex project ID is unavailable
When baseUrl is a Vertex endpoint but no project id can be resolved (no GOOGLE_CLOUD_PROJECT, no provider header, and no ADC-derived project), this code falls back to the generic Gemini URL shape (.../models/...) on the Vertex host instead of returning a clear configuration error. That request shape is invalid for Vertex and will fail at runtime with a confusing API error, so users with ADC credentials lacking project metadata get broken requests rather than actionable guidance.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9a4d659ee6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const location = | ||
| model.headers?.["x-openclaw-vertex-location"] || | ||
| process.env.GOOGLE_CLOUD_LOCATION || | ||
| "us-central1"; | ||
| return JSON.stringify({ |
There was a problem hiding this comment.
Let Vertex request URL infer location from endpoint
When ADC is used, this helper always injects a location field and defaults it to "us-central1"; later buildGoogleRequestUrl prioritizes that value over the endpoint-derived region. In configs that point baseUrl at another Vertex region (or the global host) without explicitly setting x-openclaw-vertex-location, requests are routed to /locations/us-central1/... on the wrong endpoint and fail with Vertex routing/INVALID_ARGUMENT errors. Leave location unset unless it is explicitly known so URL construction can fall back to the base URL region.
Useful? React with 👍 / 👎.
9a4d659 to
36f9839
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f72b5396c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| normalizeModelId: ({ modelId }) => normalizeGoogleModelId(modelId), | ||
| resolveDynamicModel: (ctx) => | ||
| resolveGoogle31ForwardCompatModel({ providerId: "google-vertex", ctx }), | ||
| ...GOOGLE_GEMINI_PROVIDER_HOOKS_WITH_TOOL_COMPAT, |
There was a problem hiding this comment.
Import Vertex hook bundle before provider registration
This spread references GOOGLE_GEMINI_PROVIDER_HOOKS_WITH_TOOL_COMPAT, but that identifier is never defined or imported in this module. When register(api) runs, evaluating this object literal throws a ReferenceError, which aborts Google plugin registration and prevents the new Vertex provider from being registered at runtime. Please import the hook bundle (and the other newly referenced helpers below) before constructing this provider object.
Useful? React with 👍 / 👎.
0f72b53 to
d4f4595
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d4f4595451
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -115,5 +133,73 @@ export default definePluginEntry({ | |||
| api.registerMusicGenerationProvider(buildGoogleMusicGenerationProvider()); | |||
| api.registerVideoGenerationProvider(buildGoogleVideoGenerationProvider()); | |||
| api.registerWebSearchProvider(createGeminiWebSearchProvider()); | |||
| api.registerProvider({ | |||
| id: "google-vertex", | |||
There was a problem hiding this comment.
Prefer exact provider ownership for google-vertex hooks
Registering a real google-vertex provider here collides with the existing google hook alias (hookAliases: ["google-vertex"] in extensions/google/provider-registration.ts), and runtime hook resolution uses first-match semantics (resolveProviderRuntimePlugin(...).find(matchesProviderId)). In that ordering, google can claim google-vertex first, so this provider's custom hooks (especially formatApiKey and refreshOAuth) are skipped; in auth-profile flows that means the raw OAuth access token is used instead of the JSON Bearer payload expected by parseGeminiAuth, leading to malformed Vertex auth. Ensure exact provider-id matches win (or remove the legacy alias) when google-vertex is registered.
Useful? React with 👍 / 👎.
d4f4595 to
920f6a1
Compare
|
Codex review: needs real behavior proof before merge. Reviewed June 11, 2026, 1:08 AM ET / 05:08 UTC. Summary PR surface: Source +661, Tests +289. Total +950 across 29 files. Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Review detailsBest possible solution: Retry the Codex review after fixing the execution failure. Do we have a high-confidence way to reproduce the issue? Unclear. The review failed before ClawSweeper could establish a reproduction path. Is this the best way to solve the issue? Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model internal, reasoning high; reviewed against 418d7e1e83c5. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +661, Tests +289. Total +950 across 29 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
c8a14e7 to
9c1fa95
Compare
… routing Registers a new google-vertex provider in the Google plugin that routes to aiplatform.googleapis.com using Application Default Credentials (ADC). The existing GCP_VERTEX_CREDENTIALS_MARKER and main's google-vertex auth-presence check in src/agents/model-auth-env.ts are reused; no new core marker or hard-coded provider branch is added. Provider follows the anthropic-vertex pattern with resolveSyntheticAuth(), manifest-declared nonSecretAuthMarkers, and an implicit catalog from buildGoogleVertexProvider(). hookAliases:[google-vertex] is removed from the Google AI Studio provider so the new provider's hooks own google-vertex configs. ADC token exchange supports both authorized_user (gcloud login) and service_account (CI/CD JSON keys) types; unsupported ADC types throw a clear error rather than silently falling through. Vertex URL builder strips trailing /v1 from custom baseUrls, preserves already-qualified model paths (publishers/.../, tunedModels/, projects/), infers the location from the configured baseUrl when set, and fails fast when no project ID is resolvable. Closes openclaw#49039 Closes openclaw#56253 Closes openclaw#58775 Closes openclaw#60736
Adds vertex-adc.test.ts with coverage for: missing ADC file, authorized_user refresh, service_account JWT-bearer minting, unsupported ADC type rejection, token endpoint error surfacing, in-memory cache reuse, and env project override over the ADC project_id.
…ovider # Conflicts: # extensions/google/transport-stream.test.ts # extensions/google/transport-stream.ts
|
ClawSweeper PR egg 🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat. Where did the egg go?
|
|
Adding production evidence — running OpenClaw Specifically validating two things this PR touches: 1. 2. ADC bearer exchange. I'm currently using Session JSONL after my hack-workaround: {"role":"assistant","api":"google-vertex","provider":"google",
"model":"gemini-3.5-flash","stopReason":"stop",
"responseId":"8xAOaqW7H4nItfAP-uanuAE", ...}Multi-turn works. Happy to test the official build end-to-end against a real third-party GCP billing account once a maintainer-buildable tag exists. The reseller-billing angle is a useful real-world stress test for |
|
Bundled the full reproduction (env vars, ADC setup, auth-profiles.json sentinel, patch scripts, session-log proof) into a gist for anyone else hitting this in the meantime: https://gist.github.com/wiselancer/edcb1d8b766518ecb9849287d5fc2e36 Will delete it / replace with a "use the official path" note once this PR (or #60860) lands. |
|
This pull request has been automatically marked as stale due to inactivity. |
Summary
google-vertexprovider in the Google plugin that routes toaiplatform.googleapis.comusing Application Default Credentials (ADC), separate from the existinggoogle-gemini-cliOAuth pathvertex-region.tsfor region/project/baseUrl resolution (env vars + ADC file fallback), withgloballocation producing the unprefixedaiplatform.googleapis.comendpointvertex-provider-catalog.tswith the Gemini 3.x model catalog for Vertex AI/v1/projects/{project}/locations/{location}/publishers/google/models/{model}:streamGenerateContent)"<authenticated>"sentinel that was previously sent as a literal API key causing 401sthought_signaturefrom Gemini 3 thinking-mode tool call responses so multi-turn conversations replay correctly (fixes 400INVALID_ARGUMENTon second turn)GCP_VERTEX_GOOGLE_CREDENTIALS_MARKERsentinel and registersgoogle-vertexinopenclaw.plugin.jsonCloses #49039
Closes #56253
Closes #58775
Closes #60736
Test plan
pnpm test extensions/google/vertex-region.test.ts— 20 cases, all passpnpm test extensions/google/vertex-provider-catalog.test.ts— 7 cases, all passpnpm test src/infra/gemini-auth.test.ts— 5 cases, all passgoogle-vertex/gemini-3-flash-previewwithGOOGLE_CLOUD_LOCATION=globalandGOOGLE_CLOUD_PROJECTset — correct Vertex URL, Bearer auth, successful response