Skip to content

fix(agents): extend Gemini 3.1 forward-compat to google provider#36145

Closed
Sid-Qin wants to merge 1 commit intoopenclaw:mainfrom
Sid-Qin:fix/36134-google-gemini-31-forward-compat
Closed

fix(agents): extend Gemini 3.1 forward-compat to google provider#36145
Sid-Qin wants to merge 1 commit intoopenclaw:mainfrom
Sid-Qin:fix/36134-google-gemini-31-forward-compat

Conversation

@Sid-Qin
Copy link
Copy Markdown
Contributor

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

Summary

  • Problem: Gemini 3.1 models (gemini-3.1-pro-preview, gemini-3.1-flash-lite-preview) are not recognized when used with the google provider (Gemini API key auth). The existing forward-compat only covered google-gemini-cli, so google/gemini-3.1-* gets "Unknown model" and silently falls back to Anthropic with modelApplied: true — a 10x cost increase with no visibility.
  • Why it matters: Users targeting Gemini 3.1 models via sessions_spawn or fallback chains get silent, expensive fallback to Anthropic instead of an error or correct routing.
  • What changed:
    • src/agents/model-forward-compat.ts — extended resolveGoogleGemini31ForwardCompatModel to accept both google-gemini-cli and google providers via GOOGLE_GEMINI_31_ELIGIBLE_PROVIDERS set. The function clones the nearest gemini-3 template model and sets reasoning: true.
    • src/agents/models-config.providers.ts — added bare-ID normalization for gemini-3.1-pro, gemini-3.1-flash, gemini-3.1-flash-lite (and dash variants) in normalizeGoogleModelId().
  • What did NOT change: google-gemini-cli forward-compat behavior is preserved. Default aliases remain unchanged.

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

  • google/gemini-3.1-pro-preview, google/gemini-3.1-flash-preview, and google/gemini-3.1-flash-lite-preview now resolve correctly via the google provider.
  • Bare IDs like gemini-3.1-pro and gemini-3.1-flash-lite are normalized to their -preview counterparts.
  • Fallback chains containing these models no longer produce "Unknown model" errors.

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+
  • Integration/channel: Any (model routing is channel-agnostic)

Steps

  1. Configure both anthropic and google auth profiles
  2. Spawn a sub-agent: sessions_spawn({ task: "Identify yourself", model: "google/gemini-3.1-flash-lite-preview", mode: "run" })
  3. Check output for model identification

Expected

  • Sub-agent runs on Gemini 3.1 Flash Lite and identifies itself as Gemini

Actual

  • Before fix: Silent fallback to Anthropic/Claude with modelApplied: true
  • After fix: Correct routing to Gemini 3.1

Evidence

Forward-compat test matrix:

Model Parameter Provider Before After
gemini-3.1-pro-preview google Unknown model → Anthropic fallback Resolved via template clone
gemini-3.1-flash-lite-preview google Unknown model → Anthropic fallback Resolved via template clone
gemini-3.1-flash-preview google-gemini-cli Already worked Still works
gemini-3.1-pro (bare) google Unknown model Normalized to -preview

Human Verification (required)

  • Verified scenarios: TypeScript compiles cleanly, forward-compat function expanded to cover both providers
  • Edge cases checked: Bare ID normalization with dot and dash variants; google-gemini-cli path unchanged; non-3.1 models unaffected
  • What I did not verify: Live Gemini API call with 3.1 models (requires API key)

Compatibility / Migration

  • Backward compatible? Yesgoogle-gemini-cli behavior unchanged
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert: Revert this commit; models fall back to Anthropic as before
  • Files/config to restore: None
  • Known bad symptoms: None expected

Risks and Mitigations

  • Template clone copies all properties from gemini-3-pro-preview/gemini-3-flash-preview, which should be compatible with 3.1 models since they share the same API surface
  • If 3.1 models require different API parameters, the template may need manual adjustment — but that would be a separate issue

The forward-compat path for gemini-3.1-pro-preview and
gemini-3.1-flash-lite-preview only covered the google-gemini-cli
provider.  Users configuring these models with the google provider
(Gemini API key auth) got "Unknown model" errors and silently fell
back to Anthropic.

Extend resolveGoogleGemini31ForwardCompatModel to accept both
google-gemini-cli and google providers by using a provider set.
Also add bare-ID normalization for gemini-3.1-pro, gemini-3.1-flash,
and gemini-3.1-flash-lite in normalizeGoogleModelId().

Closes openclaw#36134
Closes openclaw#36111
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 5, 2026

Greptile Summary

This PR extends the Gemini 3.1 forward-compatibility mechanism to the google provider (Gemini API key auth), preventing a silent and costly fallback to Anthropic when users request gemini-3.1-* models via sessions_spawn or fallback chains. It also adds bare-ID normalization for gemini-3.1-pro, gemini-3.1-flash, and gemini-3.1-flash-lite (dot and dash variants) in the google provider config path — consistent with the existing Gemini 3.0 pattern.

Key observations:

  • The normalizedProvider is correctly passed through to cloneFirstTemplateModel, so cloned models carry the right provider identity (google vs google-gemini-cli).
  • The forward compat relies on modelRegistry.find("google", "gemini-3-pro-preview") succeeding at runtime. There is good indirect evidence this works (config/defaults.ts uses google/gemini-3-pro-preview as a default alias and tests throughout the repo reference it), but no unit test explicitly exercises the new google provider path in resolveGoogleGemini31ForwardCompatModel.
  • No tests were added for the three new normalizeGoogleModelId branches (gemini-3.1-pro, gemini-3.1-flash, gemini-3.1-flash-lite and their dash equivalents). The existing normalization test file covers only the Gemini 3.0 variants.
  • gemini-3.1-flash-lite-* intentionally falls back to the gemini-3-flash-preview template (since no flash-lite template exists), which may carry slightly inaccurate cost/capacity metadata — an acceptable approximation given the alternative is an error.

Confidence Score: 4/5

  • Safe to merge — the logic is correct and backward-compatible, with the main gap being absent test coverage for the new google provider code paths.
  • The code change is small and well-scoped. The normalizedProvider threading fix is correct. The template-clone approach mirrors the existing google-gemini-cli path exactly. Indirect evidence (config/defaults.ts, kilocode catalog, wider test suite) strongly suggests the google provider has the required template models in its registry. The score is held back from 5 because no new tests were added for either the forward-compat google path or the three new normalizeGoogleModelId entries, leaving the fix unverified at the unit-test level.
  • src/agents/pi-embedded-runner/model.forward-compat.test.ts — the new google provider forward-compat path needs coverage; src/agents/models-config.normalizes-gemini-3-ids-preview-google-providers.test.ts — should be extended to cover the new gemini-3.1-* normalization entries.

Comments Outside Diff (1)

  1. General comment

    Missing tests for new google provider path

    The test file covers google-gemini-cli forward compat but no tests were added for the new google provider path introduced in this PR. The core correctness assumption — that modelRegistry.find("google", "gemini-3-pro-preview") succeeds — is never exercised.

    If the google provider's pi-ai built-in catalog doesn't contain gemini-3-pro-preview/gemini-3-flash-preview, cloneFirstTemplateModel silently returns undefined, resolveGoogleGemini31ForwardCompatModel returns undefined, and the silent Anthropic fallback this PR is meant to fix continues undetected.

    The test harness exposes mockDiscoveredModel and already has all the helpers needed. Two tests would be sufficient:

    it("builds a google forward-compat fallback for gemini-3.1-pro-preview", () => {
      mockDiscoveredModel({
        provider: "google",
        modelId: "gemini-3-pro-preview",
        templateModel: { ...GOOGLE_GEMINI_CLI_PRO_TEMPLATE_MODEL, provider: "google", api: "google-generative-ai" },
      });
    
      const result = resolveModel("google", "gemini-3.1-pro-preview", "/tmp/agent");
      expect(result.error).toBeUndefined();
      expect(result.model).toMatchObject({
        id: "gemini-3.1-pro-preview",
        name: "gemini-3.1-pro-preview",
        provider: "google",
        reasoning: true,
      });
    });
    
    it("builds a google forward-compat fallback for gemini-3.1-flash-lite-preview", () => {
      mockDiscoveredModel({
        provider: "google",
        modelId: "gemini-3-flash-preview",
        templateModel: { ...GOOGLE_GEMINI_CLI_FLASH_TEMPLATE_MODEL, provider: "google", api: "google-generative-ai" },
      });
    
      const result = resolveModel("google", "gemini-3.1-flash-lite-preview", "/tmp/agent");
      expect(result.error).toBeUndefined();
      expect(result.model).toMatchObject({
        id: "gemini-3.1-flash-lite-preview",
        name: "gemini-3.1-flash-lite-preview",
        provider: "google",
        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: 58-88
    
    Comment:
    **Missing tests for new `google` provider path**
    
    The test file covers `google-gemini-cli` forward compat but no tests were added for the new `google` provider path introduced in this PR. The core correctness assumption — that `modelRegistry.find("google", "gemini-3-pro-preview")` succeeds — is never exercised.
    
    If the `google` provider's pi-ai built-in catalog doesn't contain `gemini-3-pro-preview`/`gemini-3-flash-preview`, `cloneFirstTemplateModel` silently returns `undefined`, `resolveGoogleGemini31ForwardCompatModel` returns `undefined`, and the silent Anthropic fallback this PR is meant to fix continues undetected.
    
    The test harness exposes `mockDiscoveredModel` and already has all the helpers needed. Two tests would be sufficient:
    
    ```typescript
    it("builds a google forward-compat fallback for gemini-3.1-pro-preview", () => {
      mockDiscoveredModel({
        provider: "google",
        modelId: "gemini-3-pro-preview",
        templateModel: { ...GOOGLE_GEMINI_CLI_PRO_TEMPLATE_MODEL, provider: "google", api: "google-generative-ai" },
      });
    
      const result = resolveModel("google", "gemini-3.1-pro-preview", "/tmp/agent");
      expect(result.error).toBeUndefined();
      expect(result.model).toMatchObject({
        id: "gemini-3.1-pro-preview",
        name: "gemini-3.1-pro-preview",
        provider: "google",
        reasoning: true,
      });
    });
    
    it("builds a google forward-compat fallback for gemini-3.1-flash-lite-preview", () => {
      mockDiscoveredModel({
        provider: "google",
        modelId: "gemini-3-flash-preview",
        templateModel: { ...GOOGLE_GEMINI_CLI_FLASH_TEMPLATE_MODEL, provider: "google", api: "google-generative-ai" },
      });
    
      const result = resolveModel("google", "gemini-3.1-flash-lite-preview", "/tmp/agent");
      expect(result.error).toBeUndefined();
      expect(result.model).toMatchObject({
        id: "gemini-3.1-flash-lite-preview",
        name: "gemini-3.1-flash-lite-preview",
        provider: "google",
        reasoning: true,
      });
    });
    ```
    
    How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 281eee1

Comment on lines +447 to +455
if (id === "gemini-3.1-pro" || id === "gemini-3-1-pro") {
return "gemini-3.1-pro-preview";
}
if (id === "gemini-3.1-flash" || id === "gemini-3-1-flash") {
return "gemini-3.1-flash-preview";
}
if (id === "gemini-3.1-flash-lite" || id === "gemini-3-1-flash-lite") {
return "gemini-3.1-flash-lite-preview";
}
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.

No tests for new normalizeGoogleModelId entries

The existing test (models-config.normalizes-gemini-3-ids-preview-google-providers.test.ts) only covers gemini-3-pro and gemini-3-flash. The three new normalization mappings added here (gemini-3.1-pro, gemini-3-1-pro, gemini-3.1-flash, gemini-3-1-flash, gemini-3.1-flash-lite, gemini-3-1-flash-lite) are not exercised by any test. A regression in these branches would be invisible until it surfaces at runtime as an "Unknown model" error.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/models-config.providers.ts
Line: 447-455

Comment:
**No tests for new `normalizeGoogleModelId` entries**

The existing test (`models-config.normalizes-gemini-3-ids-preview-google-providers.test.ts`) only covers `gemini-3-pro` and `gemini-3-flash`. The three new normalization mappings added here (`gemini-3.1-pro`, `gemini-3-1-pro`, `gemini-3.1-flash`, `gemini-3-1-flash`, `gemini-3.1-flash-lite`, `gemini-3-1-flash-lite`) are not exercised by any test. A regression in these branches would be invisible until it surfaces at runtime as an "Unknown model" error.

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: XS

Projects

None yet

2 participants