fix: normalize google gemini preview config

This commit is contained in:
Peter Steinberger
2026-05-12 03:36:50 +01:00
parent 7b9282323b
commit e87fd7aa30
4 changed files with 85 additions and 2 deletions

View File

@@ -69,6 +69,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Google/Gemini: normalize retired Gemini 3 Pro Preview refs left in Google API-key onboarding model allowlists and fallbacks, so setup-emitted config keeps testing `google/gemini-3.1-pro-preview` instead of `google/gemini-3-pro-preview`.
- Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids when resolving exact configured proxy-provider refs, so `kilocode/google/gemini-3-pro-preview` resolves to `kilocode/google/gemini-3.1-pro-preview` for Gemini 3.1 testing.
- CLI: strip generic OSC terminal escape payloads from sanitized output fields, preventing clipboard/title escape bodies from leaking into commitment tables and other terminal-safe text. Thanks @shakkernerd.
- Codex app-server: match connector-backed plugin approval elicitations by stable connector id so enabled destructive actions no longer fall through to display-name-only rejection.

View File

@@ -18,6 +18,56 @@ describe("google default model", () => {
expect(applied.next.agents?.defaults?.model).toEqual({ primary: GOOGLE_GEMINI_DEFAULT_MODEL });
});
it("normalizes retired Gemini model map keys when applying the default", () => {
const applied = applyGoogleGeminiModelDefault({
agents: {
defaults: {
model: {
primary: "google/gemini-3-pro-preview",
fallbacks: ["google/gemini-3-pro-preview"],
},
models: {
"google/gemini-3-pro-preview": { alias: "gemini" },
},
},
},
} as OpenClawConfig);
expect(applied.changed).toBe(true);
expect(applied.next.agents?.defaults?.model).toEqual({
primary: "google/gemini-3.1-pro-preview",
fallbacks: ["google/gemini-3.1-pro-preview"],
});
expect(applied.next.agents?.defaults?.models).toEqual({
"google/gemini-3.1-pro-preview": { alias: "gemini" },
});
});
it("normalizes retired Gemini model maps even when the primary is already current", () => {
const applied = applyGoogleGeminiModelDefault({
agents: {
defaults: {
model: {
primary: GOOGLE_GEMINI_DEFAULT_MODEL,
fallbacks: ["google/gemini-3-pro-preview"],
},
models: {
"google/gemini-3-pro-preview": { alias: "gemini" },
},
},
},
} as OpenClawConfig);
expect(applied.changed).toBe(true);
expect(applied.next.agents?.defaults?.model).toEqual({
primary: GOOGLE_GEMINI_DEFAULT_MODEL,
fallbacks: [GOOGLE_GEMINI_DEFAULT_MODEL],
});
expect(applied.next.agents?.defaults?.models).toEqual({
[GOOGLE_GEMINI_DEFAULT_MODEL]: { alias: "gemini" },
});
});
it("no-ops when already on the target default", () => {
const cfg = {
agents: { defaults: { model: { primary: GOOGLE_GEMINI_DEFAULT_MODEL } } },

View File

@@ -4,6 +4,34 @@ import {
} from "openclaw/plugin-sdk/provider-onboard";
export const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-3.1-pro-preview";
const RETIRED_GOOGLE_GEMINI_MODEL_REFS = new Set([
"google/gemini-3-pro",
"google/gemini-3-pro-preview",
]);
function hasRetiredGeminiDefaultModelRefs(cfg: OpenClawConfig): boolean {
const defaults = cfg.agents?.defaults;
const model = defaults?.model as unknown;
if (model && typeof model === "object") {
const fallbacks = (model as { fallbacks?: unknown }).fallbacks;
if (
Array.isArray(fallbacks) &&
fallbacks.some(
(fallback) =>
typeof fallback === "string" && RETIRED_GOOGLE_GEMINI_MODEL_REFS.has(fallback),
)
) {
return true;
}
}
const models = defaults?.models;
return Boolean(
models &&
typeof models === "object" &&
Object.keys(models).some((modelRef) => RETIRED_GOOGLE_GEMINI_MODEL_REFS.has(modelRef)),
);
}
export function applyGoogleGeminiModelDefault(cfg: OpenClawConfig): {
next: OpenClawConfig;
@@ -18,7 +46,7 @@ export function applyGoogleGeminiModelDefault(cfg: OpenClawConfig): {
typeof (current as { primary?: unknown }).primary === "string"
? ((current as { primary: string }).primary || "").trim() || undefined
: undefined;
if (currentPrimary === GOOGLE_GEMINI_DEFAULT_MODEL) {
if (currentPrimary === GOOGLE_GEMINI_DEFAULT_MODEL && !hasRetiredGeminiDefaultModelRefs(cfg)) {
return { next: cfg, changed: false };
}
return {

View File

@@ -254,20 +254,24 @@ export function applyAgentDefaultModelPrimary(
cfg: OpenClawConfig,
primary: string,
): OpenClawConfig {
const defaults = cfg.agents?.defaults;
const existingFallbacks = extractAgentDefaultModelFallbacks(cfg.agents?.defaults?.model);
const normalizedFallbacks = existingFallbacks?.map((fallback) =>
normalizeAgentModelRefForConfig(fallback),
);
const normalizedModels =
defaults?.models === undefined ? undefined : normalizeAgentModelMapForConfig(defaults.models);
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
...defaults,
model: {
...(normalizedFallbacks ? { fallbacks: normalizedFallbacks } : undefined),
primary: normalizeAgentModelRefForConfig(primary),
},
...(normalizedModels !== undefined ? { models: normalizedModels } : undefined),
},
},
};