From f643fc3c9776c3a88da71b3efb8f2c70e7dfe2af Mon Sep 17 00:00:00 2001 From: sunlit-deng Date: Thu, 16 Jul 2026 20:26:33 +0800 Subject: [PATCH] fix(minimax): ignore blank environment API key (#108777) * fix(minimax): ignore blank environment API key * fix(minimax): centralize TTS API key resolution --------- Co-authored-by: Peter Steinberger --- extensions/minimax/speech-provider.test.ts | 21 +++++++++++++ extensions/minimax/speech-provider.ts | 34 ++++++++++++---------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/extensions/minimax/speech-provider.test.ts b/extensions/minimax/speech-provider.test.ts index 9990aefbdfd3..5597501fcb51 100644 --- a/extensions/minimax/speech-provider.test.ts +++ b/extensions/minimax/speech-provider.test.ts @@ -147,6 +147,11 @@ describe("buildMinimaxSpeechProvider", () => { expect(provider.isConfigured({ providerConfig: {}, timeoutMs: 30000 })).toBe(true); }); + it("returns false when MINIMAX_API_KEY env var is blank", () => { + process.env.MINIMAX_API_KEY = " "; + expect(provider.isConfigured({ providerConfig: {}, timeoutMs: 30000 })).toBe(false); + }); + it("returns true when a MiniMax Token Plan env var is set", () => { expect(tokenPlanEnvConfigured).toBe(true); }); @@ -606,6 +611,22 @@ describe("buildMinimaxSpeechProvider", () => { timeoutMs: 30000, }), ).rejects.toThrow("MiniMax TTS auth missing"); + expect(globalThis.fetch).not.toHaveBeenCalled(); + }); + + it("does not send a request for a blank environment API key", async () => { + process.env.MINIMAX_API_KEY = " "; + + await expect( + provider.synthesize({ + text: "Test", + cfg: {} as never, + providerConfig: {}, + target: "audio-file", + timeoutMs: 30000, + }), + ).rejects.toThrow("MiniMax TTS auth missing"); + expect(globalThis.fetch).not.toHaveBeenCalled(); }); it("throws on API error with response body", async () => { diff --git a/extensions/minimax/speech-provider.ts b/extensions/minimax/speech-provider.ts index f32471b2bc45..2e3dc514ee50 100644 --- a/extensions/minimax/speech-provider.ts +++ b/extensions/minimax/speech-provider.ts @@ -15,6 +15,7 @@ import type { import { asObject, parseSpeechDirectiveNumberOverride, + resolveSpeechProviderApiKey, trimToUndefined, } from "openclaw/plugin-sdk/speech-core"; import { asFiniteNumberInRange } from "openclaw/plugin-sdk/string-coerce-runtime"; @@ -59,13 +60,9 @@ function resolveConfiguredPortalTtsBaseUrl(cfg: OpenClawConfig | undefined): str } function resolveMinimaxTokenPlanEnvKey(): string | undefined { - for (const envVar of MINIMAX_TOKEN_PLAN_ENV_VARS) { - const value = trimToUndefined(process.env[envVar]); - if (value) { - return value; - } - } - return undefined; + return resolveSpeechProviderApiKey( + ...MINIMAX_TOKEN_PLAN_ENV_VARS.map((envVar) => process.env[envVar]), + ); } async function resolveMinimaxPortalProfileToken( @@ -81,11 +78,18 @@ async function resolveMinimaxTtsApiKey(params: { cfg: OpenClawConfig | undefined; configApiKey?: string; }): Promise { - return ( - params.configApiKey ?? - (await resolveMinimaxPortalProfileToken(params.cfg)) ?? - resolveMinimaxTokenPlanEnvKey() ?? - trimToUndefined(process.env.MINIMAX_API_KEY) + return resolveSpeechProviderApiKey( + params.configApiKey, + await resolveMinimaxPortalProfileToken(params.cfg), + resolveMinimaxDirectTtsApiKey(), + ); +} + +function resolveMinimaxDirectTtsApiKey(configApiKey?: string): string | undefined { + return resolveSpeechProviderApiKey( + configApiKey, + resolveMinimaxTokenPlanEnvKey(), + process.env.MINIMAX_API_KEY, ); } @@ -279,10 +283,8 @@ export function buildMinimaxSpeechProvider(): SpeechProviderPlugin { listVoices: async () => MINIMAX_TTS_VOICES.map((voice) => ({ id: voice, name: voice })), isConfigured: ({ cfg, providerConfig }) => Boolean( - readMinimaxProviderConfig(providerConfig, cfg).apiKey || - isProviderAuthProfileConfigured({ cfg, provider: MINIMAX_PORTAL_PROVIDER_ID }) || - resolveMinimaxTokenPlanEnvKey() || - process.env.MINIMAX_API_KEY, + resolveMinimaxDirectTtsApiKey(readMinimaxProviderConfig(providerConfig, cfg).apiKey) || + isProviderAuthProfileConfigured({ cfg, provider: MINIMAX_PORTAL_PROVIDER_ID }), ), synthesize: async (req) => { const config = readMinimaxProviderConfig(req.providerConfig, req.cfg);