diff --git a/CHANGELOG.md b/CHANGELOG.md index cc51b08e184..253e71a58d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Docs: https://docs.openclaw.ai ### Fixes - Telegram: inherit the process DNS result order for Bot API transport and downgrade recovered sticky IPv4 fallback promotions to debug logs, while keeping pinned-IP escalation warnings visible. Fixes #75904. Thanks @highfly-hi and @neeravmakwana. +- Web search/MiniMax: allow `MINIMAX_OAUTH_TOKEN` to satisfy MiniMax Search credentials, so OAuth-authorized MiniMax Token Plan setups do not need a separate web-search key. Fixes #65768. Thanks @kikibrian and @zhouhe-xydt. - Subagents: honor `sessions_spawn` with `expectsCompletionMessage: false` by skipping parent completion handoff delivery while still running child cleanup. Fixes #75848. Thanks @alfredjbclaw. - Gateway/logging: keep deferred channel startup logs on the subsystem logger, so Slack, Discord, Telegram, and voice-call startup messages keep timestamped prefixes. Thanks @vincentkoc. - ACP/Discord: suppress completion announce delivery for inline thread-bound ACP session runs, so Discord thread-bound ACP replies are not delivered twice. Fixes #60780. Thanks @solavrc. diff --git a/docs/providers/minimax.md b/docs/providers/minimax.md index 5e9e10d8954..67f6257ddd3 100644 --- a/docs/providers/minimax.md +++ b/docs/providers/minimax.md @@ -13,7 +13,7 @@ MiniMax also provides: - Bundled speech synthesis via T2A v2 - Bundled image understanding via `MiniMax-VL-01` - Bundled music generation via `music-2.6` -- Bundled `web_search` through the MiniMax Coding Plan search API +- Bundled `web_search` through the MiniMax Token Plan search API Provider split: @@ -357,16 +357,16 @@ when the bundled text-provider catalog still shows text-only M2.7 chat refs. ### Web search -The MiniMax plugin also registers `web_search` through the MiniMax Coding Plan +The MiniMax plugin also registers `web_search` through the MiniMax Token Plan search API. - Provider id: `minimax` - Structured results: titles, URLs, snippets, related queries - Preferred env var: `MINIMAX_CODE_PLAN_KEY` -- Accepted env alias: `MINIMAX_CODING_API_KEY` -- Compatibility fallback: `MINIMAX_API_KEY` when it already points at a coding-plan token +- Accepted env aliases: `MINIMAX_CODING_API_KEY`, `MINIMAX_OAUTH_TOKEN` +- Compatibility fallback: `MINIMAX_API_KEY` when it already points at a token-plan credential - Region reuse: `plugins.entries.minimax.config.webSearch.region`, then `MINIMAX_API_HOST`, then MiniMax provider base URLs -- Search stays on provider id `minimax`; OAuth CN/global setup can still steer region indirectly through `models.providers.minimax-portal.baseUrl` +- Search stays on provider id `minimax`; OAuth CN/global setup can steer region indirectly through `models.providers.minimax-portal.baseUrl` and can provide bearer auth through `MINIMAX_OAUTH_TOKEN` Config lives under `plugins.entries.minimax.config.webSearch.*`. @@ -496,7 +496,7 @@ More help: [Troubleshooting](/help/troubleshooting) and [FAQ](/help/faq). Shared video tool parameters and provider selection. - Web search configuration via MiniMax Coding Plan. + Web search configuration via MiniMax Token Plan. General troubleshooting and FAQ. diff --git a/docs/tools/minimax-search.md b/docs/tools/minimax-search.md index 87d976e2f2d..d2b4f83b2aa 100644 --- a/docs/tools/minimax-search.md +++ b/docs/tools/minimax-search.md @@ -1,22 +1,23 @@ --- -summary: "MiniMax Search via the Coding Plan search API" +summary: "MiniMax Search via the Token Plan search API" read_when: - You want to use MiniMax for web_search - - You need a MiniMax Coding Plan key + - You need a MiniMax Token Plan key or OAuth token - You want MiniMax CN/global search host guidance title: "MiniMax search" --- OpenClaw supports MiniMax as a `web_search` provider through the MiniMax -Coding Plan search API. It returns structured search results with titles, URLs, +Token Plan search API. It returns structured search results with titles, URLs, snippets, and related queries. -## Get a Coding Plan key +## Get a Token Plan credential - Create or copy a MiniMax Coding Plan key from + Create or copy a MiniMax Token Plan key from [MiniMax Platform](https://platform.minimax.io/user-center/basic-information/interface-key). + OAuth setups can reuse `MINIMAX_OAUTH_TOKEN` instead. Set `MINIMAX_CODE_PLAN_KEY` in the Gateway environment, or configure via: @@ -28,8 +29,9 @@ snippets, and related queries. -OpenClaw also accepts `MINIMAX_CODING_API_KEY` as an env alias. `MINIMAX_API_KEY` -is still read as a compatibility fallback when it already points at a coding-plan token. +OpenClaw also accepts `MINIMAX_CODING_API_KEY` and `MINIMAX_OAUTH_TOKEN` as env +aliases. `MINIMAX_API_KEY` is still read as a compatibility fallback when it +already points at a token-plan credential. ## Config @@ -40,7 +42,7 @@ is still read as a compatibility fallback when it already points at a coding-pla minimax: { config: { webSearch: { - apiKey: "sk-cp-...", // optional if MINIMAX_CODE_PLAN_KEY is set + apiKey: "sk-cp-...", // optional if a MiniMax Token Plan env var is set region: "global", // or "cn" }, }, @@ -57,7 +59,8 @@ is still read as a compatibility fallback when it already points at a coding-pla } ``` -**Environment alternative:** set `MINIMAX_CODE_PLAN_KEY` in the Gateway environment. +**Environment alternative:** set `MINIMAX_CODE_PLAN_KEY` or `MINIMAX_OAUTH_TOKEN` +in the Gateway environment. For a gateway install, put it in `~/.openclaw/.env`. ## Region selection @@ -80,7 +83,8 @@ automatically keeps MiniMax Search on the CN host too. Even when you authenticated MiniMax through the OAuth `minimax-portal` path, web search still registers as provider id `minimax`; the OAuth provider base URL -is only used as a region hint for CN/global host selection. +is used as a region hint for CN/global host selection, and `MINIMAX_OAUTH_TOKEN` +can satisfy the MiniMax Search bearer credential. ## Supported parameters diff --git a/docs/tools/web.md b/docs/tools/web.md index 17c83006e71..ad45c0dc40d 100644 --- a/docs/tools/web.md +++ b/docs/tools/web.md @@ -79,7 +79,7 @@ local while `web_search` and `x_search` can use xAI Responses under the hood. AI-synthesized answers with citations via Moonshot web search. - Structured results via the MiniMax Coding Plan search API. + Structured results via the MiniMax Token Plan search API. Search via a signed-in local Ollama host or the hosted Ollama API. @@ -106,7 +106,7 @@ local while `web_search` and `x_search` can use xAI Responses under the hood. | [Gemini](/tools/gemini-search) | AI-synthesized + citations | -- | `GEMINI_API_KEY` | | [Grok](/tools/grok-search) | AI-synthesized + citations | -- | `XAI_API_KEY` | | [Kimi](/tools/kimi-search) | AI-synthesized + citations | -- | `KIMI_API_KEY` / `MOONSHOT_API_KEY` | -| [MiniMax Search](/tools/minimax-search) | Structured snippets | Region (`global` / `cn`) | `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` | +| [MiniMax Search](/tools/minimax-search) | Structured snippets | Region (`global` / `cn`) | `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` / `MINIMAX_OAUTH_TOKEN` | | [Ollama Web Search](/tools/ollama-search) | Structured snippets | -- | None for signed-in local hosts; `OLLAMA_API_KEY` for direct `https://ollama.com` search | | [Perplexity](/tools/perplexity-search) | Structured snippets | Country, language, time, domains, content limits | `PERPLEXITY_API_KEY` / `OPENROUTER_API_KEY` | | [SearXNG](/tools/searxng-search) | Structured snippets | Categories, language | None (self-hosted) | @@ -164,7 +164,7 @@ first one that is ready: API-backed providers first: 1. **Brave** -- `BRAVE_API_KEY` or `plugins.entries.brave.config.webSearch.apiKey` (order 10) -2. **MiniMax Search** -- `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` or `plugins.entries.minimax.config.webSearch.apiKey` (order 15) +2. **MiniMax Search** -- `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` / `MINIMAX_OAUTH_TOKEN` or `plugins.entries.minimax.config.webSearch.apiKey` (order 15) 3. **Gemini** -- `plugins.entries.google.config.webSearch.apiKey`, `GEMINI_API_KEY`, or `models.providers.google.apiKey` (order 20) 4. **Grok** -- `XAI_API_KEY` or `plugins.entries.xai.config.webSearch.apiKey` (order 30) 5. **Kimi** -- `KIMI_API_KEY` / `MOONSHOT_API_KEY` or `plugins.entries.moonshot.config.webSearch.apiKey` (order 40) diff --git a/extensions/minimax/index.test.ts b/extensions/minimax/index.test.ts index 4fd4c53b5c8..ca4f075688c 100644 --- a/extensions/minimax/index.test.ts +++ b/extensions/minimax/index.test.ts @@ -246,7 +246,7 @@ describe("minimax provider hooks", () => { expect(webSearchProviders[0]).toMatchObject({ id: "minimax", label: "MiniMax Search", - envVars: ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY"], + envVars: ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY", "MINIMAX_OAUTH_TOKEN"], }); }); diff --git a/extensions/minimax/minimax.live.test.ts b/extensions/minimax/minimax.live.test.ts index 996a58e4d68..cb82c465349 100644 --- a/extensions/minimax/minimax.live.test.ts +++ b/extensions/minimax/minimax.live.test.ts @@ -12,6 +12,7 @@ const MINIMAX_API_KEY = process.env.MINIMAX_API_KEY?.trim() ?? ""; const MINIMAX_SEARCH_KEY = process.env.MINIMAX_CODE_PLAN_KEY?.trim() || process.env.MINIMAX_CODING_API_KEY?.trim() || + process.env.MINIMAX_OAUTH_TOKEN?.trim() || MINIMAX_API_KEY || ""; const MINIMAX_TTS_TOKEN_PLAN_KEY = diff --git a/extensions/minimax/openclaw.plugin.json b/extensions/minimax/openclaw.plugin.json index 038b27c755f..7b62ca49a13 100644 --- a/extensions/minimax/openclaw.plugin.json +++ b/extensions/minimax/openclaw.plugin.json @@ -97,8 +97,8 @@ }, "uiHints": { "webSearch.apiKey": { - "label": "MiniMax Coding Plan key", - "help": "MiniMax Coding Plan key (fallback: MINIMAX_CODE_PLAN_KEY, MINIMAX_CODING_API_KEY, or MINIMAX_API_KEY if it already points at a coding-plan token).", + "label": "MiniMax Token Plan key", + "help": "MiniMax Token Plan key or OAuth token (fallback: MINIMAX_CODE_PLAN_KEY, MINIMAX_CODING_API_KEY, MINIMAX_OAUTH_TOKEN, or MINIMAX_API_KEY if it already points at a token-plan credential).", "sensitive": true, "placeholder": "sk-cp-..." }, diff --git a/extensions/minimax/src/minimax-web-search-provider.runtime.ts b/extensions/minimax/src/minimax-web-search-provider.runtime.ts index 45c3c026b0e..964d592350a 100644 --- a/extensions/minimax/src/minimax-web-search-provider.runtime.ts +++ b/extensions/minimax/src/minimax-web-search-provider.runtime.ts @@ -26,7 +26,11 @@ import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; const MINIMAX_SEARCH_ENDPOINT_GLOBAL = "https://api.minimax.io/v1/coding_plan/search"; const MINIMAX_SEARCH_ENDPOINT_CN = "https://api.minimaxi.com/v1/coding_plan/search"; -const MINIMAX_CODING_PLAN_ENV_VARS = ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY"] as const; +const MINIMAX_TOKEN_PLAN_ENV_VARS = [ + "MINIMAX_CODE_PLAN_KEY", + "MINIMAX_CODING_API_KEY", + "MINIMAX_OAUTH_TOKEN", +] as const; type MiniMaxSearchResult = { title?: string; @@ -51,7 +55,7 @@ type MiniMaxSearchResponse = { function resolveMiniMaxApiKey(searchConfig?: SearchConfigRecord): string | undefined { return ( readConfiguredSecretString(searchConfig?.apiKey, "tools.web.search.apiKey") ?? - readProviderEnvValue([...MINIMAX_CODING_PLAN_ENV_VARS, "MINIMAX_API_KEY"]) + readProviderEnvValue([...MINIMAX_TOKEN_PLAN_ENV_VARS, "MINIMAX_API_KEY"]) ); } @@ -182,7 +186,7 @@ async function runMiniMaxSearch(params: { function missingMiniMaxKeyPayload() { return { error: "missing_minimax_api_key", - message: `web_search (minimax) needs a MiniMax Coding Plan key. Run \`${formatCliCommand("openclaw configure --section web")}\` to store it, or set MINIMAX_CODE_PLAN_KEY, MINIMAX_CODING_API_KEY, or MINIMAX_API_KEY in the Gateway environment.`, + message: `web_search (minimax) needs a MiniMax Token Plan key or OAuth token. Run \`${formatCliCommand("openclaw configure --section web")}\` to store it, or set MINIMAX_CODE_PLAN_KEY, MINIMAX_CODING_API_KEY, MINIMAX_OAUTH_TOKEN, or MINIMAX_API_KEY in the Gateway environment.`, docs: "https://docs.openclaw.ai/tools/web", }; } diff --git a/extensions/minimax/src/minimax-web-search-provider.test.ts b/extensions/minimax/src/minimax-web-search-provider.test.ts index 03d7e0fa48a..d35b0910aff 100644 --- a/extensions/minimax/src/minimax-web-search-provider.test.ts +++ b/extensions/minimax/src/minimax-web-search-provider.test.ts @@ -13,12 +13,14 @@ describe("minimax web search provider", () => { const originalApiHost = process.env.MINIMAX_API_HOST; const originalCodePlanKey = process.env.MINIMAX_CODE_PLAN_KEY; const originalCodingApiKey = process.env.MINIMAX_CODING_API_KEY; + const originalOauthToken = process.env.MINIMAX_OAUTH_TOKEN; const originalApiKey = process.env.MINIMAX_API_KEY; beforeEach(() => { delete process.env.MINIMAX_API_HOST; delete process.env.MINIMAX_CODE_PLAN_KEY; delete process.env.MINIMAX_CODING_API_KEY; + delete process.env.MINIMAX_OAUTH_TOKEN; delete process.env.MINIMAX_API_KEY; }); @@ -26,6 +28,7 @@ describe("minimax web search provider", () => { process.env.MINIMAX_API_HOST = originalApiHost; process.env.MINIMAX_CODE_PLAN_KEY = originalCodePlanKey; process.env.MINIMAX_CODING_API_KEY = originalCodingApiKey; + process.env.MINIMAX_OAUTH_TOKEN = originalOauthToken; process.env.MINIMAX_API_KEY = originalApiKey; }); @@ -130,7 +133,7 @@ describe("minimax web search provider", () => { expect(resolveMiniMaxApiKey({ apiKey: "configured-key" })).toBe("configured-key"); }); - it("accepts MINIMAX_CODING_API_KEY as a coding-plan alias", () => { + it("accepts MINIMAX_CODING_API_KEY as a token-plan alias", () => { process.env.MINIMAX_CODING_API_KEY = "coding-key"; expect(resolveMiniMaxApiKey()).toBe("coding-key"); }); @@ -139,6 +142,12 @@ describe("minimax web search provider", () => { process.env.MINIMAX_API_KEY = "plain-key"; expect(resolveMiniMaxApiKey()).toBe("plain-key"); }); + + it("accepts MINIMAX_OAUTH_TOKEN before the legacy API-key fallback", () => { + process.env.MINIMAX_OAUTH_TOKEN = "oauth-token"; + process.env.MINIMAX_API_KEY = "plain-key"; + expect(resolveMiniMaxApiKey()).toBe("oauth-token"); + }); }); describe("endpoint constants", () => { diff --git a/extensions/minimax/src/minimax-web-search-provider.ts b/extensions/minimax/src/minimax-web-search-provider.ts index c3f0100e5e0..7ebe983d76c 100644 --- a/extensions/minimax/src/minimax-web-search-provider.ts +++ b/extensions/minimax/src/minimax-web-search-provider.ts @@ -4,7 +4,11 @@ import { } from "openclaw/plugin-sdk/provider-web-search-config-contract"; const MINIMAX_CREDENTIAL_PATH = "plugins.entries.minimax.config.webSearch.apiKey"; -const MINIMAX_CODING_PLAN_ENV_VARS = ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY"] as const; +const MINIMAX_TOKEN_PLAN_ENV_VARS = [ + "MINIMAX_CODE_PLAN_KEY", + "MINIMAX_CODING_API_KEY", + "MINIMAX_OAUTH_TOKEN", +] as const; type MiniMaxWebSearchRuntime = typeof import("./minimax-web-search-provider.runtime.js"); @@ -32,9 +36,9 @@ export function createMiniMaxWebSearchProvider(): WebSearchProviderPlugin { return { id: "minimax", label: "MiniMax Search", - hint: "Structured results via MiniMax Coding Plan search API", - credentialLabel: "MiniMax Coding Plan key", - envVars: [...MINIMAX_CODING_PLAN_ENV_VARS], + hint: "Structured results via MiniMax Token Plan search API", + credentialLabel: "MiniMax Token Plan key or OAuth token", + envVars: [...MINIMAX_TOKEN_PLAN_ENV_VARS], placeholder: "sk-cp-...", signupUrl: "https://platform.minimax.io/user-center/basic-information/interface-key", docsUrl: "https://docs.openclaw.ai/tools/minimax-search", diff --git a/extensions/minimax/web-search-contract-api.ts b/extensions/minimax/web-search-contract-api.ts index be60c605caf..15d0b5749a7 100644 --- a/extensions/minimax/web-search-contract-api.ts +++ b/extensions/minimax/web-search-contract-api.ts @@ -3,7 +3,11 @@ import { type WebSearchProviderPlugin, } from "openclaw/plugin-sdk/provider-web-search-config-contract"; -const MINIMAX_CODING_PLAN_ENV_VARS = ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY"] as const; +const MINIMAX_TOKEN_PLAN_ENV_VARS = [ + "MINIMAX_CODE_PLAN_KEY", + "MINIMAX_CODING_API_KEY", + "MINIMAX_OAUTH_TOKEN", +] as const; export function createMiniMaxWebSearchProvider(): WebSearchProviderPlugin { const credentialPath = "plugins.entries.minimax.config.webSearch.apiKey"; @@ -11,9 +15,9 @@ export function createMiniMaxWebSearchProvider(): WebSearchProviderPlugin { return { id: "minimax", label: "MiniMax Search", - hint: "Structured results via MiniMax Coding Plan search API", - credentialLabel: "MiniMax Coding Plan key", - envVars: [...MINIMAX_CODING_PLAN_ENV_VARS], + hint: "Structured results via MiniMax Token Plan search API", + credentialLabel: "MiniMax Token Plan key or OAuth token", + envVars: [...MINIMAX_TOKEN_PLAN_ENV_VARS], placeholder: "sk-cp-...", signupUrl: "https://platform.minimax.io/user-center/basic-information/interface-key", docsUrl: "https://docs.openclaw.ai/tools/minimax-search", diff --git a/src/config/config.web-search-provider.test.ts b/src/config/config.web-search-provider.test.ts index 7858089e6d8..082eaf3eea3 100644 --- a/src/config/config.web-search-provider.test.ts +++ b/src/config/config.web-search-provider.test.ts @@ -76,7 +76,7 @@ const mockWebSearchProviders = [ { id: "minimax", pluginId: "minimax", - envVars: ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY"], + envVars: ["MINIMAX_CODE_PLAN_KEY", "MINIMAX_CODING_API_KEY", "MINIMAX_OAUTH_TOKEN"], credentialPath: "plugins.entries.minimax.config.webSearch.apiKey", getCredentialValue: getScopedWebSearchCredential("minimax"), getConfiguredCredentialValue: getConfiguredPluginWebSearchCredential("minimax"), @@ -421,6 +421,7 @@ describe("web search provider auto-detection", () => { delete process.env.MINIMAX_API_KEY; delete process.env.MINIMAX_CODE_PLAN_KEY; delete process.env.MINIMAX_CODING_API_KEY; + delete process.env.MINIMAX_OAUTH_TOKEN; delete process.env.MOONSHOT_API_KEY; delete process.env.PERPLEXITY_API_KEY; delete process.env.OPENROUTER_API_KEY; @@ -475,6 +476,11 @@ describe("web search provider auto-detection", () => { expect(resolveSearchProvider({})).toBe("minimax"); }); + it("auto-detects minimax when only MINIMAX_OAUTH_TOKEN is set", () => { + process.env.MINIMAX_OAUTH_TOKEN = "oauth-test-token"; // pragma: allowlist secret + expect(resolveSearchProvider({})).toBe("minimax"); + }); + it("auto-detects perplexity when only PERPLEXITY_API_KEY is set", () => { process.env.PERPLEXITY_API_KEY = "test-perplexity-key"; // pragma: allowlist secret expect(resolveSearchProvider({})).toBe("perplexity");