From 2f238b5d7d41d2701e409c560d2a5d21953698b7 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 = {