fix(web-search): allow MiniMax OAuth search credentials

Co-authored-by: 周鹤0668001310 <zhou.he3@xydigit.com>
This commit is contained in:
Peter Steinberger
2026-05-02 05:42:43 +01:00
parent 40c8ce844c
commit f2370b769c
12 changed files with 68 additions and 35 deletions

View File

@@ -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.

View File

@@ -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.
</Card>
<Card title="MiniMax Search" href="/tools/minimax-search" icon="magnifying-glass">
Web search configuration via MiniMax Coding Plan.
Web search configuration via MiniMax Token Plan.
</Card>
<Card title="Troubleshooting" href="/help/troubleshooting" icon="wrench">
General troubleshooting and FAQ.

View File

@@ -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
<Steps>
<Step title="Create a key">
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.
</Step>
<Step title="Store the key">
Set `MINIMAX_CODE_PLAN_KEY` in the Gateway environment, or configure via:
@@ -28,8 +29,9 @@ snippets, and related queries.
</Step>
</Steps>
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

View File

@@ -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.
</Card>
<Card title="MiniMax Search" icon="globe" href="/tools/minimax-search">
Structured results via the MiniMax Coding Plan search API.
Structured results via the MiniMax Token Plan search API.
</Card>
<Card title="Ollama Web Search" icon="globe" href="/tools/ollama-search">
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)

View File

@@ -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"],
});
});

View File

@@ -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 =

View File

@@ -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-..."
},

View File

@@ -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",
};
}

View File

@@ -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", () => {

View File

@@ -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",

View File

@@ -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",

View File

@@ -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");