From ab993904d790a7b896d98d3ac498eb5d728aa4d1 Mon Sep 17 00:00:00 2001 From: Shadow Date: Mon, 12 Jan 2026 21:32:53 -0600 Subject: [PATCH] Models: normalize Gemini 3 ids in runtime selection Closes #795 --- CHANGELOG.md | 1 + src/agents/model-selection.test.ts | 18 ++++++++++++++++++ src/agents/model-selection.ts | 13 +++++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d19531364..f9b84b1a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm) ### Fixes +- Models/Google: normalize Gemini 3 model ids to preview variants before runtime selection. (#795 — thanks @thewilloftheshadow) - TUI: keep the last streamed response instead of replacing it with “(no output)”. (#747 — thanks @thewilloftheshadow) - Slack: accept slash commands with or without leading `/` for custom command configs. (#798 — thanks @thewilloftheshadow) - Onboarding/Configure: refuse to proceed with invalid configs; run `clawdbot doctor` first to avoid wiping custom fields. (#764 — thanks @mukhtharcm) diff --git a/src/agents/model-selection.test.ts b/src/agents/model-selection.test.ts index d3ba3aea1..c054d64b8 100644 --- a/src/agents/model-selection.test.ts +++ b/src/agents/model-selection.test.ts @@ -107,6 +107,24 @@ describe("parseModelRef", () => { model: "claude-opus-4-5", }); }); + + it("normalizes google gemini 3 models to preview ids", () => { + expect(parseModelRef("google/gemini-3-pro", "anthropic")).toEqual({ + provider: "google", + model: "gemini-3-pro-preview", + }); + expect(parseModelRef("google/gemini-3-flash", "anthropic")).toEqual({ + provider: "google", + model: "gemini-3-flash-preview", + }); + }); + + it("normalizes default-provider google models", () => { + expect(parseModelRef("gemini-3-pro", "google")).toEqual({ + provider: "google", + model: "gemini-3-pro-preview", + }); + }); }); describe("resolveHooksGmailModel", () => { diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index a66ef7dab..d98260583 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -1,5 +1,6 @@ import type { ClawdbotConfig } from "../config/config.js"; import type { ModelCatalogEntry } from "./model-catalog.js"; +import { normalizeGoogleModelId } from "./models-config.providers.js"; export type ModelRef = { provider: string; @@ -47,6 +48,12 @@ function normalizeAnthropicModelId(model: string): string { return trimmed; } +function normalizeProviderModelId(provider: string, model: string): string { + if (provider === "anthropic") return normalizeAnthropicModelId(model); + if (provider === "google") return normalizeGoogleModelId(model); + return model; +} + export function parseModelRef( raw: string, defaultProvider: string, @@ -56,16 +63,14 @@ export function parseModelRef( const slash = trimmed.indexOf("/"); if (slash === -1) { const provider = normalizeProviderId(defaultProvider); - const model = - provider === "anthropic" ? normalizeAnthropicModelId(trimmed) : trimmed; + const model = normalizeProviderModelId(provider, trimmed); return { provider, model }; } const providerRaw = trimmed.slice(0, slash).trim(); const provider = normalizeProviderId(providerRaw); const model = trimmed.slice(slash + 1).trim(); if (!provider || !model) return null; - const normalizedModel = - provider === "anthropic" ? normalizeAnthropicModelId(model) : model; + const normalizedModel = normalizeProviderModelId(provider, model); return { provider, model: normalizedModel }; }