diff --git a/CHANGELOG.md b/CHANGELOG.md index 042ef485058..69788a0c2e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Docs: https://docs.openclaw.ai - Channels: add Yuanbao channel docs entrance so the Tencent Yuanbao bot appears in the channel listing and sidebar navigation. (#73443) Thanks @loongfay. +### Fixes + +- Plugins/media: auto-enable provider plugins referenced by `agents.defaults.imageGenerationModel`, `videoGenerationModel`, and `musicGenerationModel` primary/fallback refs, so configured Google and MiniMax media providers do not stay disabled behind a restrictive plugin allowlist. Thanks @vincentkoc. + ## 2026.4.27 ### Changes diff --git a/src/config/plugin-auto-enable.core.test.ts b/src/config/plugin-auto-enable.core.test.ts index 606fc5f421c..ac75fef8ed9 100644 --- a/src/config/plugin-auto-enable.core.test.ts +++ b/src/config/plugin-auto-enable.core.test.ts @@ -306,6 +306,49 @@ describe("applyPluginAutoEnable core", () => { expect(result.changes).toContain("codex/gpt-5.4 model configured, enabled automatically."); }); + it("auto-enables provider plugins referenced by media generation model fallbacks", () => { + const result = applyPluginAutoEnable({ + config: { + agents: { + defaults: { + imageGenerationModel: { + primary: "openai/gpt-image-1", + fallbacks: ["google/gemini-3-pro-image-preview"], + }, + videoGenerationModel: { + primary: "openai/sora-2", + fallbacks: ["google/veo-3.1-fast-generate-preview", "minimax/MiniMax-Hailuo-2.3"], + }, + musicGenerationModel: { + primary: "minimax/music-2.6", + fallbacks: ["google/lyria-3-clip-preview"], + }, + }, + }, + plugins: { + allow: ["openai"], + entries: { + openai: { enabled: true }, + }, + }, + }, + env, + manifestRegistry: makeRegistry([ + { id: "openai", channels: [], providers: ["openai"] }, + { id: "google", channels: [], providers: ["google"] }, + { id: "minimax", channels: [], providers: ["minimax"] }, + ]), + }); + + expect(result.config.plugins?.entries?.google?.enabled).toBe(true); + expect(result.config.plugins?.entries?.minimax?.enabled).toBe(true); + expect(result.config.plugins?.allow).toEqual(["openai", "google", "minimax"]); + expect(result.changes).toEqual([ + "google/gemini-3-pro-image-preview model configured, enabled automatically.", + "minimax/MiniMax-Hailuo-2.3 model configured, enabled automatically.", + ]); + }); + it("does not auto-enable Codex when only the OpenAI plugin is explicitly enabled", () => { const result = applyPluginAutoEnable({ config: { diff --git a/src/config/plugin-auto-enable.shared.ts b/src/config/plugin-auto-enable.shared.ts index 1caf536a915..6c7ae9e15d9 100644 --- a/src/config/plugin-auto-enable.shared.ts +++ b/src/config/plugin-auto-enable.shared.ts @@ -54,21 +54,33 @@ function collectModelRefs(cfg: OpenClawConfig): string[] { refs.push(value.trim()); } }; + const collectModelConfig = (value: unknown) => { + if (typeof value === "string") { + pushModelRef(value); + return; + } + if (!isRecord(value)) { + return; + } + pushModelRef(value.primary); + const fallbacks = value.fallbacks; + if (Array.isArray(fallbacks)) { + for (const entry of fallbacks) { + pushModelRef(entry); + } + } + }; const collectFromAgent = (agent: Record | null | undefined) => { if (!agent) { return; } - const model = agent.model; - if (typeof model === "string") { - pushModelRef(model); - } else if (isRecord(model)) { - pushModelRef(model.primary); - const fallbacks = model.fallbacks; - if (Array.isArray(fallbacks)) { - for (const entry of fallbacks) { - pushModelRef(entry); - } - } + for (const key of [ + "model", + "imageGenerationModel", + "videoGenerationModel", + "musicGenerationModel", + ]) { + collectModelConfig(agent[key]); } const models = agent.models; if (isRecord(models)) {