From 71875a8c857e09656b4fc08646a92fbaa8aeb87f Mon Sep 17 00:00:00 2001 From: Maho Pan Date: Tue, 24 Mar 2026 10:57:14 -0400 Subject: [PATCH] fix(doctor): add missing baseUrl and models when migrating nano-banana apiKey to google provider The legacy nano-banana-pro skill migration moves the Gemini API key to models.providers.google.apiKey but does not populate the required baseUrl and models fields on the provider entry. When the google provider object is freshly created (no pre-existing config), the resulting config fails Zod validation on write: Config validation failed: models.providers.google.baseUrl: Invalid input: expected string, received undefined Fix: default baseUrl to 'https://generativelanguage.googleapis.com' and models to [] when they are not already set, matching the defaults used elsewhere in the codebase (embeddings-gemini, pdf-native-providers). Fixes the 'doctor --fix' crash for users who only have a legacy nano-banana-pro skill entry and no existing models.providers.google. --- src/commands/doctor-legacy-config.migrations.test.ts | 8 ++++++++ src/commands/doctor-legacy-config.ts | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/commands/doctor-legacy-config.migrations.test.ts b/src/commands/doctor-legacy-config.migrations.test.ts index cca0cb21d93..cec5f767456 100644 --- a/src/commands/doctor-legacy-config.migrations.test.ts +++ b/src/commands/doctor-legacy-config.migrations.test.ts @@ -318,6 +318,10 @@ describe("normalizeCompatibilityConfigValues", () => { provider: "default", id: "GEMINI_API_KEY", }); + expect(res.config.models?.providers?.google?.baseUrl).toBe( + "https://generativelanguage.googleapis.com", + ); + expect(res.config.models?.providers?.google?.models).toEqual([]); expect(res.config.skills?.entries).toBeUndefined(); expect(res.changes).toEqual([ "Moved skills.entries.nano-banana-pro → agents.defaults.imageGenerationModel.primary (google/gemini-3-pro-image-preview).", @@ -341,6 +345,10 @@ describe("normalizeCompatibilityConfigValues", () => { }); expect(res.config.models?.providers?.google?.apiKey).toBe("env-gemini-key"); + expect(res.config.models?.providers?.google?.baseUrl).toBe( + "https://generativelanguage.googleapis.com", + ); + expect(res.config.models?.providers?.google?.models).toEqual([]); expect(res.changes).toContain( "Moved skills.entries.nano-banana-pro.env.GEMINI_API_KEY → models.providers.google.apiKey.", ); diff --git a/src/commands/doctor-legacy-config.ts b/src/commands/doctor-legacy-config.ts index f3a8a01e2b1..61b738bf3ef 100644 --- a/src/commands/doctor-legacy-config.ts +++ b/src/commands/doctor-legacy-config.ts @@ -579,6 +579,12 @@ export function normalizeCompatibilityConfigValues(cfg: OpenClawConfig): { const hasGoogleApiKey = rawGoogle.apiKey !== undefined; if (!hasGoogleApiKey && legacyApiKey) { rawGoogle.apiKey = legacyApiKey; + if (!rawGoogle.baseUrl) { + rawGoogle.baseUrl = "https://generativelanguage.googleapis.com"; + } + if (!Array.isArray(rawGoogle.models)) { + rawGoogle.models = []; + } rawProviders.google = rawGoogle; rawModels.providers = rawProviders as NonNullable["providers"]; next = {