diff --git a/src/channels/plugins/legacy-config.test.ts b/src/commands/doctor/shared/channel-legacy-config-migrate.test.ts similarity index 92% rename from src/channels/plugins/legacy-config.test.ts rename to src/commands/doctor/shared/channel-legacy-config-migrate.test.ts index 9e7cc07e8df..54d1c62e0bf 100644 --- a/src/channels/plugins/legacy-config.test.ts +++ b/src/commands/doctor/shared/channel-legacy-config-migrate.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { applyChannelDoctorCompatibilityMigrations } from "./legacy-config.js"; +import { applyChannelDoctorCompatibilityMigrations } from "./channel-legacy-config-migrate.js"; describe("bundled channel legacy config migrations", () => { it("normalizes legacy private-network aliases exposed through bundled contract surfaces", () => { diff --git a/src/config/config-misc.test.ts b/src/config/config-misc.test.ts index eceda64367a..669434f5547 100644 --- a/src/config/config-misc.test.ts +++ b/src/config/config-misc.test.ts @@ -497,7 +497,7 @@ describe("config strict validation", () => { } }); - it("accepts top-level memorySearch via auto-migration and reports legacyIssues", async () => { + it("rejects top-level memorySearch until doctor repairs it and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { memorySearch: { @@ -509,18 +509,17 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "memorySearch")).toBe(true); - expect(snap.sourceConfig.agents?.defaults?.memorySearch).toMatchObject({ + expect((snap.sourceConfig as { memorySearch?: unknown }).memorySearch).toMatchObject({ provider: "local", fallback: "none", query: { maxResults: 7 }, }); - expect((snap.sourceConfig as { memorySearch?: unknown }).memorySearch).toBeUndefined(); }); }); - it("accepts top-level heartbeat agent settings via auto-migration and reports legacyIssues", async () => { + it("rejects top-level heartbeat agent settings until doctor repairs them and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { heartbeat: { @@ -531,17 +530,16 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "heartbeat")).toBe(true); - expect(snap.sourceConfig.agents?.defaults?.heartbeat).toMatchObject({ + expect((snap.sourceConfig as { heartbeat?: unknown }).heartbeat).toMatchObject({ every: "30m", model: "anthropic/claude-3-5-haiku-20241022", }); - expect((snap.sourceConfig as { heartbeat?: unknown }).heartbeat).toBeUndefined(); }); }); - it("accepts top-level heartbeat visibility via auto-migration and reports legacyIssues", async () => { + it("rejects top-level heartbeat visibility until doctor repairs it and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { heartbeat: { @@ -553,18 +551,17 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "heartbeat")).toBe(true); - expect(snap.sourceConfig.channels?.defaults?.heartbeat).toMatchObject({ + expect((snap.sourceConfig as { heartbeat?: unknown }).heartbeat).toMatchObject({ showOk: true, showAlerts: false, useIndicator: true, }); - expect((snap.sourceConfig as { heartbeat?: unknown }).heartbeat).toBeUndefined(); }); }); - it("accepts legacy messages.tts provider keys via auto-migration and reports legacyIssues", async () => { + it("rejects legacy messages.tts provider keys until doctor repairs them and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { messages: { @@ -580,15 +577,15 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "messages.tts")).toBe(true); - expect(snap.sourceConfig.messages?.tts?.providers?.elevenlabs).toEqual({ - apiKey: "test-key", - voiceId: "voice-1", + expect(snap.sourceConfig.messages?.tts).toEqual({ + provider: "elevenlabs", + elevenlabs: { + apiKey: "test-key", + voiceId: "voice-1", + }, }); - expect( - (snap.sourceConfig.messages?.tts as Record | undefined)?.elevenlabs, - ).toBeUndefined(); }); }); @@ -614,7 +611,7 @@ describe("config strict validation", () => { }); }); - it("accepts legacy sandbox perSession via auto-migration and reports legacyIssues", async () => { + it("rejects legacy sandbox perSession until doctor repairs it and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { agents: { @@ -636,21 +633,17 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "agents.defaults.sandbox")).toBe( true, ); expect(snap.legacyIssues.some((issue) => issue.path === "agents.list")).toBe(true); - expect(snap.sourceConfig.agents?.defaults?.sandbox).toEqual({ - scope: "session", - }); - expect(snap.sourceConfig.agents?.list?.[0]?.sandbox).toEqual({ - scope: "shared", - }); + expect(snap.sourceConfig.agents?.defaults?.sandbox).toEqual({ perSession: true }); + expect(snap.sourceConfig.agents?.list?.[0]?.sandbox).toEqual({ perSession: false }); }); }); - it("accepts legacy x_search auth via auto-migration and reports legacyIssues", async () => { + it("rejects legacy x_search auth until doctor repairs it and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { tools: { @@ -664,20 +657,17 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "tools.web.x_search.apiKey")).toBe( true, ); - expect(snap.sourceConfig.plugins?.entries?.xai?.config?.webSearch).toMatchObject({ - apiKey: "test-key", - }); expect( (snap.sourceConfig.tools?.web?.x_search as Record | undefined)?.apiKey, - ).toBeUndefined(); + ).toBe("test-key"); }); }); - it("accepts legacy thread binding ttlHours via auto-migration and reports legacyIssues", async () => { + it("rejects legacy thread binding ttlHours until doctor repairs it and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { session: { @@ -703,37 +693,18 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "session.threadBindings")).toBe(true); expect(snap.legacyIssues.some((issue) => issue.path === "channels")).toBe(true); - expect(snap.sourceConfig.session?.threadBindings).toMatchObject({ - idleHours: 24, - }); - expect(snap.sourceConfig.channels?.discord?.threadBindings).toMatchObject({ - idleHours: 12, - }); + expect(snap.sourceConfig.session?.threadBindings).toMatchObject({ ttlHours: 24 }); + expect(snap.sourceConfig.channels?.discord?.threadBindings).toMatchObject({ ttlHours: 12 }); expect(snap.sourceConfig.channels?.discord?.accounts?.alpha?.threadBindings).toMatchObject({ - idleHours: 6, + ttlHours: 6, }); - expect( - (snap.sourceConfig.session?.threadBindings as Record | undefined) - ?.ttlHours, - ).toBeUndefined(); - expect( - (snap.sourceConfig.channels?.discord?.threadBindings as Record | undefined) - ?.ttlHours, - ).toBeUndefined(); - expect( - ( - snap.sourceConfig.channels?.discord?.accounts?.alpha?.threadBindings as - | Record - | undefined - )?.ttlHours, - ).toBeUndefined(); }); }); - it("accepts legacy channel streaming aliases via auto-migration and reports legacyIssues", async () => { + it("rejects legacy channel streaming aliases until doctor repairs them and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { channels: { @@ -764,7 +735,7 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "channels.telegram")).toBe(true); expect(snap.legacyIssues.some((issue) => issue.path === "channels.discord")).toBe(true); expect(snap.legacyIssues.some((issue) => issue.path === "channels.discord.accounts")).toBe( @@ -775,36 +746,20 @@ describe("config strict validation", () => { true, ); expect(snap.legacyIssues.some((issue) => issue.path === "channels.slack")).toBe(true); - expect(snap.sourceConfig.channels?.telegram).toMatchObject({ - streaming: "block", - }); - expect( - (snap.sourceConfig.channels?.telegram as Record | undefined)?.streamMode, - ).toBeUndefined(); - expect(snap.sourceConfig.channels?.discord).toMatchObject({ - streaming: "off", - }); + expect(snap.sourceConfig.channels?.telegram).toMatchObject({ streamMode: "block" }); + expect(snap.sourceConfig.channels?.discord).toMatchObject({ streaming: false }); expect(snap.sourceConfig.channels?.discord?.accounts?.work).toMatchObject({ - streaming: "block", + streamMode: "block", }); - expect( - (snap.sourceConfig.channels?.googlechat as Record | undefined)?.streamMode, - ).toBeUndefined(); - expect( - ( - snap.sourceConfig.channels?.googlechat?.accounts?.work as - | Record - | undefined - )?.streamMode, - ).toBeUndefined(); - expect(snap.sourceConfig.channels?.slack).toMatchObject({ - streaming: "partial", - nativeStreaming: true, + expect(snap.sourceConfig.channels?.googlechat).toMatchObject({ streamMode: "append" }); + expect(snap.sourceConfig.channels?.googlechat?.accounts?.work).toMatchObject({ + streamMode: "replace", }); + expect(snap.sourceConfig.channels?.slack).toMatchObject({ streaming: true }); }); }); - it("accepts legacy nested channel allow aliases via auto-migration and reports legacyIssues", async () => { + it("rejects legacy nested channel allow aliases until doctor repairs them and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { channels: { @@ -869,7 +824,7 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "channels.slack")).toBe(true); expect(snap.legacyIssues.some((issue) => issue.path === "channels.slack.accounts")).toBe( true, @@ -882,39 +837,17 @@ describe("config strict validation", () => { expect(snap.legacyIssues.some((issue) => issue.path === "channels.discord.accounts")).toBe( true, ); - expect(snap.sourceConfig.channels?.slack?.channels?.ops).toMatchObject({ - enabled: false, - }); + expect(snap.sourceConfig.channels?.slack?.channels?.ops).toMatchObject({ allow: false }); expect(snap.sourceConfig.channels?.googlechat?.groups?.["spaces/aaa"]).toMatchObject({ - enabled: false, + allow: false, }); expect(snap.sourceConfig.channels?.discord?.guilds?.["100"]?.channels?.general).toMatchObject( - { - enabled: false, - }, + { allow: false }, ); - expect( - (snap.sourceConfig.channels?.slack?.channels?.ops as Record | undefined) - ?.allow, - ).toBeUndefined(); - expect( - ( - snap.sourceConfig.channels?.googlechat?.groups?.["spaces/aaa"] as - | Record - | undefined - )?.allow, - ).toBeUndefined(); - expect( - ( - snap.sourceConfig.channels?.discord?.guilds?.["100"]?.channels?.general as - | Record - | undefined - )?.allow, - ).toBeUndefined(); }); }); - it("accepts telegram groupMentionsOnly via auto-migration and reports legacyIssues", async () => { + it("rejects telegram groupMentionsOnly until doctor repairs it and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { channels: { @@ -926,21 +859,15 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect( snap.legacyIssues.some((issue) => issue.path === "channels.telegram.groupMentionsOnly"), ).toBe(true); - expect(snap.sourceConfig.channels?.telegram?.groups?.["*"]).toMatchObject({ - requireMention: true, - }); - expect( - (snap.sourceConfig.channels?.telegram as Record | undefined) - ?.groupMentionsOnly, - ).toBeUndefined(); + expect(snap.sourceConfig.channels?.telegram).toMatchObject({ groupMentionsOnly: true }); }); }); - it("accepts legacy plugins.entries.*.config.tts provider keys via auto-migration", async () => { + it("rejects legacy plugins.entries.*.config.tts provider keys until doctor repairs them", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { plugins: { @@ -962,7 +889,7 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "plugins.entries")).toBe(true); const voiceCallTts = ( snap.sourceConfig.plugins?.entries as @@ -979,15 +906,17 @@ describe("config strict validation", () => { > | undefined )?.["voice-call"]?.config?.tts; - expect(voiceCallTts?.providers?.openai).toEqual({ - model: "gpt-4o-mini-tts", - voice: "alloy", + expect(voiceCallTts).toEqual({ + provider: "openai", + openai: { + model: "gpt-4o-mini-tts", + voice: "alloy", + }, }); - expect(voiceCallTts?.openai).toBeUndefined(); }); }); - it("accepts legacy discord voice tts provider keys via auto-migration and reports legacyIssues", async () => { + it("rejects legacy discord voice tts provider keys until doctor repairs them and reports legacyIssues", async () => { await withTempHome(async (home) => { await writeOpenClawConfig(home, { channels: { @@ -1017,32 +946,24 @@ describe("config strict validation", () => { const snap = await readConfigFileSnapshot(); - expect(snap.valid).toBe(true); + expect(snap.valid).toBe(false); expect(snap.legacyIssues.some((issue) => issue.path === "channels.discord.voice.tts")).toBe( true, ); expect(snap.legacyIssues.some((issue) => issue.path === "channels.discord.accounts")).toBe( true, ); - expect(snap.sourceConfig.channels?.discord?.voice?.tts?.providers?.elevenlabs).toEqual({ - voiceId: "voice-1", + expect(snap.sourceConfig.channels?.discord?.voice?.tts).toEqual({ + provider: "elevenlabs", + elevenlabs: { + voiceId: "voice-1", + }, }); - expect( - snap.sourceConfig.channels?.discord?.accounts?.main?.voice?.tts?.providers?.microsoft, - ).toEqual({ - voice: "en-US-AvaNeural", + expect(snap.sourceConfig.channels?.discord?.accounts?.main?.voice?.tts).toEqual({ + edge: { + voice: "en-US-AvaNeural", + }, }); - expect( - (snap.sourceConfig.channels?.discord?.voice?.tts as Record | undefined) - ?.elevenlabs, - ).toBeUndefined(); - expect( - ( - snap.sourceConfig.channels?.discord?.accounts?.main?.voice?.tts as - | Record - | undefined - )?.edge, - ).toBeUndefined(); }); }); diff --git a/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts b/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts index 488660453f7..9adc119bd5b 100644 --- a/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts +++ b/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts @@ -2,10 +2,15 @@ import fs from "node:fs/promises"; import path from "node:path"; import { describe, expect, it, vi } from "vitest"; -const { loadConfig, migrateLegacyConfig, readConfigFileSnapshot, validateConfigObject } = +const { loadConfig, readConfigFileSnapshot, validateConfigObject } = await vi.importActual("./config.js"); +const { migrateLegacyConfig: migrateLegacyConfigFromDoctor } = await vi.importActual< + typeof import("../commands/doctor/shared/legacy-config-migrate.js") +>("../commands/doctor/shared/legacy-config-migrate.js"); import { withTempHome } from "./test-helpers.js"; +const migrateLegacyConfig = migrateLegacyConfigFromDoctor; + async function expectLoadRejectionPreservesField(params: { config: unknown; readValue: (parsed: unknown) => unknown; @@ -219,7 +224,7 @@ describe("legacy config detection", () => { await withSnapshotForConfig( { channels: { telegram: { groupMentionsOnly: true } } }, async (ctx) => { - expect(ctx.snapshot.valid).toBe(true); + expect(ctx.snapshot.valid).toBe(false); expect( ctx.snapshot.legacyIssues.some( (issue) => issue.path === "channels.telegram.groupMentionsOnly", @@ -263,7 +268,7 @@ describe("legacy config detection", () => { await withSnapshotForConfig( { memorySearch: { provider: "local", fallback: "none" } }, async (ctx) => { - expect(ctx.snapshot.valid).toBe(true); + expect(ctx.snapshot.valid).toBe(false); expect(ctx.snapshot.legacyIssues.some((issue) => issue.path === "memorySearch")).toBe(true); }, ); @@ -272,7 +277,7 @@ describe("legacy config detection", () => { await withSnapshotForConfig( { heartbeat: { model: "anthropic/claude-3-5-haiku-20241022", every: "30m" } }, async (ctx) => { - expect(ctx.snapshot.valid).toBe(true); + expect(ctx.snapshot.valid).toBe(false); expect(ctx.snapshot.legacyIssues.some((issue) => issue.path === "heartbeat")).toBe(true); }, ); @@ -316,7 +321,7 @@ describe("legacy config detection", () => { await withSnapshotForConfig( { memorySearch: { provider: "local", fallback: "none" } }, async (ctx) => { - expect(ctx.snapshot.valid).toBe(true); + expect(ctx.snapshot.valid).toBe(false); expect(ctx.snapshot.legacyIssues.some((issue) => issue.path === "memorySearch")).toBe(true); }, ); diff --git a/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts b/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts index b1450d375ae..f1e4781c031 100644 --- a/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts +++ b/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { migrateLegacyConfig } from "./legacy-migrate.js"; +import { migrateLegacyConfig } from "../commands/doctor/shared/legacy-config-migrate.js"; import type { OpenClawConfig } from "./types.js"; import { validateConfigObject } from "./validation.js"; diff --git a/src/config/config.web-search-provider.test.ts b/src/config/config.web-search-provider.test.ts index 9852939055c..803cf302386 100644 --- a/src/config/config.web-search-provider.test.ts +++ b/src/config/config.web-search-provider.test.ts @@ -389,7 +389,7 @@ describe("web search provider config", () => { expect(res.ok).toBe(false); }); - it("accepts legacy scoped provider config for bundled providers via auto-migration", () => { + it("rejects legacy scoped provider config for bundled providers until doctor repairs it", () => { const res = validateConfigObjectWithPlugins({ tools: { web: { @@ -403,21 +403,7 @@ describe("web search provider config", () => { }, }); - expect(res.ok).toBe(true); - if (!res.ok) { - return; - } - expect(res.config.tools?.web?.search).toEqual({ - provider: "gemini", - }); - expect(res.config.plugins?.entries?.google).toEqual({ - enabled: true, - config: { - webSearch: { - apiKey: "legacy-key", - }, - }, - }); + expect(res.ok).toBe(false); }); it("accepts gemini provider with no extra config", () => { diff --git a/src/config/legacy-migrate.test.ts b/src/config/legacy-migrate.test.ts index 8bc9d1fa587..1bc7f75004e 100644 --- a/src/config/legacy-migrate.test.ts +++ b/src/config/legacy-migrate.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { migrateLegacyConfig } from "./legacy-migrate.js"; +import { migrateLegacyConfig } from "../commands/doctor/shared/legacy-config-migrate.js"; import { validateConfigObjectRawWithPlugins, validateConfigObjectWithPlugins, diff --git a/src/config/legacy-web-search.test.ts b/src/config/legacy-web-search.test.ts index abb1c3d5554..5fe047abc3b 100644 --- a/src/config/legacy-web-search.test.ts +++ b/src/config/legacy-web-search.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; +import { migrateLegacyConfig } from "../commands/doctor/shared/legacy-config-migrate.js"; import type { OpenClawConfig } from "./config.js"; -import { migrateLegacyConfig } from "./legacy-migrate.js"; import { listLegacyWebSearchConfigPaths, migrateLegacyWebSearchConfig, @@ -108,7 +108,7 @@ describe("legacy web search config", () => { { path: "tools.web.search", message: - "tools.web.search provider-owned config moved to plugins.entries..config.webSearch (auto-migrated on load).", + 'tools.web.search provider-owned config moved to plugins.entries..config.webSearch. Run "openclaw doctor --fix".', }, ]); diff --git a/src/config/thread-bindings-config-keys.test.ts b/src/config/thread-bindings-config-keys.test.ts index d454636acc8..c872fa66fc4 100644 --- a/src/config/thread-bindings-config-keys.test.ts +++ b/src/config/thread-bindings-config-keys.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { migrateLegacyConfig } from "./legacy-migrate.js"; +import { migrateLegacyConfig } from "../commands/doctor/shared/legacy-config-migrate.js"; import { validateConfigObjectRaw } from "./validation.js"; describe("thread binding config keys", () => { diff --git a/src/secrets/runtime.test.ts b/src/secrets/runtime.test.ts index bc4fc543e89..ca673f19ce8 100644 --- a/src/secrets/runtime.test.ts +++ b/src/secrets/runtime.test.ts @@ -3117,7 +3117,7 @@ describe("secrets runtime snapshot", () => { } }); - it("migrates legacy x_search SecretRefs into the xai plugin webSearch auth at runtime", async () => { + it("keeps legacy x_search SecretRefs in place until doctor repairs them", async () => { const snapshot = await prepareSecretsRuntimeSnapshot({ config: asConfig({ tools: { @@ -3138,17 +3138,14 @@ describe("secrets runtime snapshot", () => { }); expect((snapshot.config.tools?.web as Record | undefined)?.x_search).toEqual({ + apiKey: "xai-runtime-key", enabled: true, model: "grok-4-1-fast", }); - expect(snapshot.config.plugins?.entries?.xai?.config).toEqual({ - webSearch: { - apiKey: "xai-runtime-key", - }, - }); + expect(snapshot.config.plugins?.entries?.xai).toBeUndefined(); }); - it("still migrates legacy x_search auth when general legacy migration returns an invalid config", async () => { + it("still resolves legacy x_search auth in place even when unrelated legacy config is present", async () => { const snapshot = await prepareSecretsRuntimeSnapshot({ config: asConfig({ tools: { @@ -3174,13 +3171,10 @@ describe("secrets runtime snapshot", () => { }); expect((snapshot.config.tools?.web as Record | undefined)?.x_search).toEqual({ + apiKey: "xai-runtime-key-invalid-config", enabled: true, }); - expect(snapshot.config.plugins?.entries?.xai?.config).toEqual({ - webSearch: { - apiKey: "xai-runtime-key-invalid-config", - }, - }); + expect(snapshot.config.plugins?.entries?.xai).toBeUndefined(); }); it("does not force-enable xai at runtime for knob-only x_search config", async () => { diff --git a/test/helpers/plugins/plugin-api.ts b/test/helpers/plugins/plugin-api.ts index 88ca60b8921..ae2abccc62c 100644 --- a/test/helpers/plugins/plugin-api.ts +++ b/test/helpers/plugins/plugin-api.ts @@ -19,7 +19,6 @@ export function createTestPluginApi(api: TestPluginApiInput): OpenClawPluginApi registerService() {}, registerCliBackend() {}, registerConfigMigration() {}, - registerLegacyConfigMigration() {}, registerAutoEnableProbe() {}, registerProvider() {}, registerSpeechProvider() {},