Skip to content

fix(agents): add google/google-vertex forward-compat for gemini-3.1 fallback models#36173

Closed
Sid-Qin wants to merge 1 commit intoopenclaw:mainfrom
Sid-Qin:fix/gemini-31-fallback-routing-36111
Closed

fix(agents): add google/google-vertex forward-compat for gemini-3.1 fallback models#36173
Sid-Qin wants to merge 1 commit intoopenclaw:mainfrom
Sid-Qin:fix/gemini-31-fallback-routing-36111

Conversation

@Sid-Qin
Copy link
Copy Markdown
Contributor

@Sid-Qin Sid-Qin commented Mar 5, 2026

Summary

  • Problem: Gemini 3.1 series models (gemini-3.1-pro-preview, gemini-3.1-flash-preview, gemini-3.1-flash-lite-preview) work correctly as the primary model but throw FailoverError: Unknown model when used in the fallbacks array. The forward-compat resolver only covered google-gemini-cli provider, not google or google-vertex.
  • Why it matters: Users configuring Gemini 3.1 models as fallbacks get hard failures instead of graceful model resolution, breaking failover workflows.
  • What changed: Added resolveGoogleGenai31ForwardCompatModel that handles google and google-vertex providers by cloning the nearest gemini-3-pro-preview / gemini-3-flash-preview template or synthesizing a model definition when no template exists.
  • What did NOT change (scope boundary): The existing google-gemini-cli forward-compat path is untouched. No changes to primary model resolution, provider config, or API routing.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

Gemini 3.1 models (google/gemini-3.1-pro-preview, google/gemini-3.1-flash-preview, google/gemini-3.1-flash-lite-preview) now resolve correctly when used in the fallbacks array, instead of throwing FailoverError: Unknown model.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS / Linux
  • Runtime: Node.js 22+

Steps

  1. Add google/gemini-3.1-flash-lite-preview to the fallbacks array in agent config
  2. Trigger a failover (e.g., primary model hits rate limit)
  3. Observe the error in diagnostic logs

Expected

  • Gemini 3.1 fallback model resolves and the agent uses it

Actual

  • Before: FailoverError: Unknown model: google/gemini-3.1-flash-lite-preview
  • After: Model resolves via forward-compat, agent runs on Gemini 3.1

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

7 new vitest unit tests covering:

  • google/gemini-3.1-pro-preview with template
  • google/gemini-3.1-flash-preview with template
  • google/gemini-3.1-flash-lite-preview with template
  • Synthetic model when no template exists
  • google-vertex provider resolution
  • Non-matching model IDs still return unknown-model error

Human Verification (required)

  • Verified scenarios: All 7 forward-compat resolution paths tested via vitest. Existing 5 tests continue to pass unchanged.
  • Edge cases checked: No template in registry (synthetic fallback), google-vertex provider, non-3.1 model IDs rejected, flash-lite variant.
  • What you did not verify: Live failover with actual Google API keys (requires production credentials).

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert: Revert this commit. Fallback resolution returns to previous behavior (only google-gemini-cli handled).
  • Files/config to restore: src/agents/model-forward-compat.ts

Risks and Mitigations

  • Risk: Synthetic model definition may have incorrect defaults for future Gemini 3.1 variants.
    • Mitigation: The synthetic path is only reached when no template exists in the registry. Once pi-ai adds native Gemini 3.1 definitions, the template-clone path takes precedence automatically.

…odels

Gemini 3.1 series models (gemini-3.1-pro-preview, gemini-3.1-flash-preview,
gemini-3.1-flash-lite-preview) work as primary models but fail with
"Unknown model" when used in fallbacks. The existing forward-compat
resolver only handled google-gemini-cli provider, not google/google-vertex.

Add resolveGoogleGenai31ForwardCompatModel that clones the nearest
gemini-3 template or synthesizes a model definition when no template
exists in the registry.

Closes openclaw#36111

Made-with: Cursor
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Mar 5, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Credential/endpoint confusion: google-vertex routed through google-generative-ai forward-compat fallback without Vertex endpoint constraints

1. 🟡 Credential/endpoint confusion: google-vertex routed through google-generative-ai forward-compat fallback without Vertex endpoint constraints

Property Value
Severity Medium
CWE CWE-16
Location src/agents/model-forward-compat.ts:171-215

Description

resolveGoogleGenai31ForwardCompatModel() now allows provider: "google-vertex" into the Google GenAI forward-compat path and can synthesize a Model with api: "google-generative-ai" while keeping provider: "google-vertex".

This creates a risky provider/api mismatch:

  • Input: user-controlled model ref google-vertex/gemini-3.1-… (from config / CLI selection)
  • Auth resolution: elsewhere, google-vertex credentials are resolved from gcloud ADC (resolveEnvApiKey() uses getEnvApiKey("google-vertex") and labels it "gcloud adc").
  • Transport selection: api: "google-generative-ai" selects the Gemini (public GenAI) transport.
  • When no template exists in the registry, the synthesized model omits an explicit baseUrl, so the underlying google-generative-ai transport will fall back to its default endpoint behavior.

Impact (security/privacy):

  • Users selecting google-vertex/* typically expect Vertex AI routing (project/region scoped, enterprise controls such as VPC-SC/org policies). This fallback can send prompts/tool output to a different backend path than intended.
  • The combination of Vertex-sourced credentials (ADC) with a GenAI transport increases the risk of misapplied credentials (e.g., OAuth/ADC material being attached in an unexpected way) and inadvertent data egress outside the expected Vertex perimeter.

Vulnerable code:

const GOOGLE_GENAI_ELIGIBLE_PROVIDERS = new Set(["google", "google-vertex"]);
...
return normalizeModelCompat({
  id: trimmed,
  name: trimmed,
  api: "google-generative-ai",
  provider: normalizedProvider,
  ...
});

Recommendation

Avoid routing google-vertex through the generic GenAI fallback unless you can guarantee Vertex-correct endpoint + auth semantics.

Safer options:

  1. Disallow google-vertex in this forward-compat resolver (only allow google).
const GOOGLE_GENAI_ELIGIBLE_PROVIDERS = new Set(["google"]);
  1. If you want forward-compat for Vertex, only allow cloning from an existing Vertex template (which should already contain the correct Vertex baseUrl and any required metadata). If no template exists, return undefined so the user gets a clear “Unknown model” instead of silent rerouting.
if (normalizedProvider === "google-vertex") {
  const cloned = cloneFirstTemplateModel({ ... });
  return cloned; // no synthetic fallback for vertex
}
  1. Additionally (defense-in-depth), when returning a forward-compat model in resolveModel(), consider applying any configured provider baseUrl override even for forward-compat models, so enterprise users can force Vertex/private endpoints.

Analyzed PR: #36173 at commit c96535e

Last updated on: 2026-03-05T14:09:26Z

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 5, 2026

Greptile Summary

This PR extends the existing forward-compat model resolution to cover the google and google-vertex providers for Gemini 3.1 series models, fixing FailoverError: Unknown model when those models are used as fallbacks. The implementation correctly follows the established pattern: attempt to clone a known template model from the registry, and synthesize a minimal model definition if no template is found.

Key issues:

  • Wrong api adapter in the synthetic fallback for google-vertex (src/agents/model-forward-compat.ts, lines 205–215): The fallback hardcodes api: "google-generative-ai", which is the correct adapter for the google (AI Studio) provider but not for google-vertex. If the Vertex AI registry doesn't contain a gemini-3-flash-preview or gemini-3-pro-preview template, the synthetic model will route calls through the wrong HTTP adapter, likely causing authentication or endpoint errors at runtime.

  • Missing api assertion in the google-vertex test (model.forward-compat.test.ts, line 144–152): The test exercises the exact synthetic fallback path that has the wrong api value, but does not assert on api, so it passes today and would continue to pass even after the bug is introduced. Adding an api assertion would both document the expected behavior and act as a regression guard.

Confidence Score: 3/5

  • Safe to merge for google provider users; carries a latent runtime risk for google-vertex users who hit the synthetic fallback path due to the wrong API adapter being set.
  • The template-clone path (the common case) is correct for both providers. The issue is narrowly scoped to the synthetic fallback, which is only triggered when neither gemini-3-pro-preview nor gemini-3-flash-preview exists in the google-vertex registry. If Vertex AI's built-in catalog always includes those templates, the bug is never reached in practice. However, it is a definite correctness gap that the test suite does not catch, warranting a score below 4.
  • Pay close attention to src/agents/model-forward-compat.ts lines 205–215 (synthetic fallback) and the google-vertex test case in src/agents/pi-embedded-runner/model.forward-compat.test.ts.

Last reviewed commit: c96535e

Comment on lines +205 to +215
return normalizeModelCompat({
id: trimmed,
name: trimmed,
api: "google-generative-ai",
provider: normalizedProvider,
reasoning: true,
input: ["text", "image"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: DEFAULT_CONTEXT_TOKENS,
maxTokens: DEFAULT_CONTEXT_TOKENS,
} as Model<Api>);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong API type hardcoded for google-vertex synthetic fallback

The synthetic fallback path always sets api: "google-generative-ai", which is the correct adapter for the google provider (Google AI Studio) but incorrect for google-vertex. Vertex AI uses a different endpoint and authentication scheme — routing it through the google-generative-ai adapter will cause authentication failures or wrong-endpoint errors at runtime.

This synthetic path is only hit when no template exists in the registry for the given provider (e.g. google-vertex has no gemini-3-flash-preview entry). For google-vertex users in that situation, the resolved model will silently point at the wrong API.

The fix should branch on normalizedProvider:

  const api =
    normalizedProvider === "google-vertex" ? "google-vertex-ai" : "google-generative-ai";

  return normalizeModelCompat({
    id: trimmed,
    name: trimmed,
    api,
    provider: normalizedProvider,
    reasoning: true,
    input: ["text", "image"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: DEFAULT_CONTEXT_TOKENS,
    maxTokens: DEFAULT_CONTEXT_TOKENS,
  } as Model<Api>);

(Replace "google-vertex-ai" with whatever string the rest of the codebase uses for the Vertex AI adapter.)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/model-forward-compat.ts
Line: 205-215

Comment:
**Wrong API type hardcoded for `google-vertex` synthetic fallback**

The synthetic fallback path always sets `api: "google-generative-ai"`, which is the correct adapter for the `google` provider (Google AI Studio) but incorrect for `google-vertex`. Vertex AI uses a different endpoint and authentication scheme — routing it through the `google-generative-ai` adapter will cause authentication failures or wrong-endpoint errors at runtime.

This synthetic path is only hit when no template exists in the registry for the given provider (e.g. `google-vertex` has no `gemini-3-flash-preview` entry). For `google-vertex` users in that situation, the resolved model will silently point at the wrong API.

The fix should branch on `normalizedProvider`:

```typescript
  const api =
    normalizedProvider === "google-vertex" ? "google-vertex-ai" : "google-generative-ai";

  return normalizeModelCompat({
    id: trimmed,
    name: trimmed,
    api,
    provider: normalizedProvider,
    reasoning: true,
    input: ["text", "image"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: DEFAULT_CONTEXT_TOKENS,
    maxTokens: DEFAULT_CONTEXT_TOKENS,
  } as Model<Api>);
```

(Replace `"google-vertex-ai"` with whatever string the rest of the codebase uses for the Vertex AI adapter.)

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +144 to +152
it("resolves google-vertex gemini-3.1 models via the same forward-compat path", () => {
const result = resolveModel("google-vertex", "gemini-3.1-flash-preview", "/tmp/agent");
expect(result.error).toBeUndefined();
expect(result.model).toMatchObject({
id: "gemini-3.1-flash-preview",
provider: "google-vertex",
reasoning: true,
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api field not asserted for google-vertex synthetic path

This test exercises the no-template synthetic fallback for google-vertex (no mock is set up, so discoverModels returns null and the fallback triggers). However, it doesn't assert api, so it would pass even though the synthetic model currently receives the wrong api: "google-generative-ai" value.

Adding an api assertion here would have caught the bug described above and would lock in the correct adapter going forward:

    expect(result.model).toMatchObject({
      id: "gemini-3.1-flash-preview",
      provider: "google-vertex",
      api: "google-vertex-ai", // or the correct vertex adapter string
      reasoning: true,
    });
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/model.forward-compat.test.ts
Line: 144-152

Comment:
**`api` field not asserted for `google-vertex` synthetic path**

This test exercises the no-template synthetic fallback for `google-vertex` (no mock is set up, so `discoverModels` returns `null` and the fallback triggers). However, it doesn't assert `api`, so it would pass even though the synthetic model currently receives the wrong `api: "google-generative-ai"` value.

Adding an `api` assertion here would have caught the bug described above and would lock in the correct adapter going forward:

```typescript
    expect(result.model).toMatchObject({
      id: "gemini-3.1-flash-preview",
      provider: "google-vertex",
      api: "google-vertex-ai", // or the correct vertex adapter string
      reasoning: true,
    });
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Gemini 3.1 series models not recognized in fallback routing

2 participants