mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-14 03:20:49 +00:00
onboard(minimax): flatten auth to 4 direct choices, unify CN/Global under single provider (#44284)
Replace the multi-step MiniMax onboarding wizard with 4 flat options: - MiniMax Global — OAuth (minimax.io) - MiniMax Global — API Key (minimax.io) - MiniMax CN — OAuth (minimaxi.com) - MiniMax CN — API Key (minimaxi.com) Storage changes: - Unify CN and Global under provider "minimax" (baseUrl distinguishes region) - Profiles: minimax:global / minimax:cn (both regions can coexist) - Model ref: minimax/MiniMax-M2.5 (no more minimax-cn/ prefix) - Remove LM Studio local mode and Lightning/Highspeed choice Backward compatibility: - Keep minimax-cn in provider-env-vars for existing configs - Accept minimax-cn as legacy tokenProvider in CI pipelines - Error with migration hint for removed auth choices in non-interactive mode - Warn when dual-profile overwrites shared provider baseUrl Made-with: Cursor
This commit is contained in:
@@ -2198,7 +2198,7 @@ Anthropic-compatible, built-in provider. Shortcut: `openclaw onboard --auth-choi
|
||||
{
|
||||
id: "hf:MiniMaxAI/MiniMax-M2.5",
|
||||
name: "MiniMax M2.5",
|
||||
reasoning: false,
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 192000,
|
||||
@@ -2238,7 +2238,7 @@ Base URL should omit `/v1` (Anthropic client appends it). Shortcut: `openclaw on
|
||||
{
|
||||
id: "MiniMax-M2.5",
|
||||
name: "MiniMax M2.5",
|
||||
reasoning: false,
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 15, output: 60, cacheRead: 2, cacheWrite: 10 },
|
||||
contextWindow: 200000,
|
||||
|
||||
@@ -151,7 +151,7 @@ Configure manually via `openclaw.json`:
|
||||
{
|
||||
id: "minimax-m2.5-gs32",
|
||||
name: "MiniMax M2.5 GS32",
|
||||
reasoning: false,
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 196608,
|
||||
|
||||
@@ -9,20 +9,6 @@ import type { ProviderConfig } from "./models-config.providers.js";
|
||||
|
||||
describe("models-config merge helpers", () => {
|
||||
const preservedApiKey = "AGENT_KEY"; // pragma: allowlist secret
|
||||
const kimiModel: ProviderConfig["models"][number] = {
|
||||
id: "k2p5",
|
||||
name: "Kimi for Coding",
|
||||
input: ["text", "image"],
|
||||
reasoning: true,
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128_000,
|
||||
maxTokens: 8_000,
|
||||
};
|
||||
|
||||
it("refreshes implicit model metadata while preserving explicit reasoning overrides", () => {
|
||||
const merged = mergeProviderModels(
|
||||
@@ -83,17 +69,31 @@ describe("models-config merge helpers", () => {
|
||||
it("preserves implicit provider headers when explicit config adds extra headers", () => {
|
||||
const merged = mergeProviderModels(
|
||||
{
|
||||
baseUrl: "https://api.example.com",
|
||||
api: "anthropic-messages",
|
||||
baseUrl: "https://api.anthropic.com",
|
||||
headers: { "User-Agent": "claude-code/0.1.0" },
|
||||
models: [kimiModel],
|
||||
} as ProviderConfig,
|
||||
models: [
|
||||
{
|
||||
id: "k2p5",
|
||||
name: "Kimi for Coding",
|
||||
input: ["text", "image"],
|
||||
reasoning: true,
|
||||
},
|
||||
],
|
||||
} as unknown as ProviderConfig,
|
||||
{
|
||||
baseUrl: "https://api.example.com",
|
||||
api: "anthropic-messages",
|
||||
baseUrl: "https://api.anthropic.com",
|
||||
headers: { "X-Kimi-Tenant": "tenant-a" },
|
||||
models: [kimiModel],
|
||||
} as ProviderConfig,
|
||||
models: [
|
||||
{
|
||||
id: "k2p5",
|
||||
name: "Kimi for Coding",
|
||||
input: ["text", "image"],
|
||||
reasoning: true,
|
||||
},
|
||||
],
|
||||
} as unknown as ProviderConfig,
|
||||
);
|
||||
|
||||
expect(merged.headers).toEqual({
|
||||
|
||||
@@ -187,7 +187,7 @@ const MODELSTUDIO_MODEL_CATALOG: ReadonlyArray<ProviderModelConfig> = [
|
||||
{
|
||||
id: "MiniMax-M2.5",
|
||||
name: "MiniMax-M2.5",
|
||||
reasoning: false,
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: MODELSTUDIO_DEFAULT_COST,
|
||||
contextWindow: 1_000_000,
|
||||
|
||||
@@ -5,8 +5,6 @@ export const AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI: ReadonlyArray<AuthChoice> = [
|
||||
"oauth",
|
||||
"claude-cli",
|
||||
"codex-cli",
|
||||
"minimax-cloud",
|
||||
"minimax",
|
||||
];
|
||||
|
||||
export function normalizeLegacyOnboardAuthChoice(
|
||||
|
||||
@@ -57,7 +57,7 @@ const AUTH_CHOICE_GROUP_DEFS: {
|
||||
value: "minimax",
|
||||
label: "MiniMax",
|
||||
hint: "M2.5 (recommended)",
|
||||
choices: ["minimax-portal", "minimax-api", "minimax-api-key-cn", "minimax-api-lightning"],
|
||||
choices: ["minimax-global-oauth", "minimax-global-api", "minimax-cn-oauth", "minimax-cn-api"],
|
||||
},
|
||||
{
|
||||
value: "moonshot",
|
||||
@@ -291,9 +291,24 @@ const BASE_AUTH_CHOICE_OPTIONS: ReadonlyArray<AuthChoiceOption> = [
|
||||
label: "Xiaomi API key",
|
||||
},
|
||||
{
|
||||
value: "minimax-portal",
|
||||
label: "MiniMax OAuth",
|
||||
hint: "Oauth plugin for MiniMax",
|
||||
value: "minimax-global-oauth",
|
||||
label: "MiniMax Global — OAuth (minimax.io)",
|
||||
hint: "Only supports OAuth for the coding plan",
|
||||
},
|
||||
{
|
||||
value: "minimax-global-api",
|
||||
label: "MiniMax Global — API Key (minimax.io)",
|
||||
hint: "sk-api- or sk-cp- keys supported",
|
||||
},
|
||||
{
|
||||
value: "minimax-cn-oauth",
|
||||
label: "MiniMax CN — OAuth (minimaxi.com)",
|
||||
hint: "Only supports OAuth for the coding plan",
|
||||
},
|
||||
{
|
||||
value: "minimax-cn-api",
|
||||
label: "MiniMax CN — API Key (minimaxi.com)",
|
||||
hint: "sk-api- or sk-cp- keys supported",
|
||||
},
|
||||
{ value: "qwen-portal", label: "Qwen OAuth" },
|
||||
{
|
||||
@@ -307,17 +322,6 @@ const BASE_AUTH_CHOICE_OPTIONS: ReadonlyArray<AuthChoiceOption> = [
|
||||
label: "OpenCode Zen catalog",
|
||||
hint: "Claude, GPT, Gemini via opencode.ai/zen",
|
||||
},
|
||||
{ value: "minimax-api", label: "MiniMax M2.5" },
|
||||
{
|
||||
value: "minimax-api-key-cn",
|
||||
label: "MiniMax M2.5 (CN)",
|
||||
hint: "China endpoint (api.minimaxi.com)",
|
||||
},
|
||||
{
|
||||
value: "minimax-api-lightning",
|
||||
label: "MiniMax M2.5 Highspeed",
|
||||
hint: "Official fast tier (legacy: Lightning)",
|
||||
},
|
||||
{ value: "qianfan-api-key", label: "Qianfan API key" },
|
||||
{
|
||||
value: "modelstudio-api-key-cn",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import { applyAuthChoiceMiniMax } from "./auth-choice.apply.minimax.js";
|
||||
import {
|
||||
createAuthTestLifecycle,
|
||||
@@ -10,23 +9,6 @@ import {
|
||||
setupAuthTestEnv,
|
||||
} from "./test-wizard-helpers.js";
|
||||
|
||||
function createMinimaxPrompter(
|
||||
params: {
|
||||
text?: WizardPrompter["text"];
|
||||
confirm?: WizardPrompter["confirm"];
|
||||
select?: WizardPrompter["select"];
|
||||
} = {},
|
||||
): WizardPrompter {
|
||||
return createWizardPrompter(
|
||||
{
|
||||
text: params.text,
|
||||
confirm: params.confirm,
|
||||
select: params.select,
|
||||
},
|
||||
{ defaultSelect: "oauth" },
|
||||
);
|
||||
}
|
||||
|
||||
describe("applyAuthChoiceMiniMax", () => {
|
||||
const lifecycle = createAuthTestLifecycle([
|
||||
"OPENCLAW_STATE_DIR",
|
||||
@@ -56,27 +38,25 @@ describe("applyAuthChoiceMiniMax", () => {
|
||||
async function runMiniMaxChoice(params: {
|
||||
authChoice: Parameters<typeof applyAuthChoiceMiniMax>[0]["authChoice"];
|
||||
opts?: Parameters<typeof applyAuthChoiceMiniMax>[0]["opts"];
|
||||
env?: { apiKey?: string; oauthToken?: string };
|
||||
prompter?: Parameters<typeof createMinimaxPrompter>[0];
|
||||
env?: { apiKey?: string };
|
||||
prompterText?: () => Promise<string>;
|
||||
}) {
|
||||
const agentDir = await setupTempState();
|
||||
resetMiniMaxEnv();
|
||||
if (params.env?.apiKey !== undefined) {
|
||||
process.env.MINIMAX_API_KEY = params.env.apiKey;
|
||||
}
|
||||
if (params.env?.oauthToken !== undefined) {
|
||||
process.env.MINIMAX_OAUTH_TOKEN = params.env.oauthToken;
|
||||
}
|
||||
|
||||
const text = vi.fn(async () => "should-not-be-used");
|
||||
const confirm = vi.fn(async () => true);
|
||||
const result = await applyAuthChoiceMiniMax({
|
||||
authChoice: params.authChoice,
|
||||
config: {},
|
||||
prompter: createMinimaxPrompter({
|
||||
text,
|
||||
// Pass select: undefined so ref-mode uses the non-interactive fallback (same as old test behavior).
|
||||
prompter: createWizardPrompter({
|
||||
text: params.prompterText ?? text,
|
||||
confirm,
|
||||
...params.prompter,
|
||||
select: undefined,
|
||||
}),
|
||||
runtime: createExitThrowingRuntime(),
|
||||
setDefaultModel: true,
|
||||
@@ -94,7 +74,7 @@ describe("applyAuthChoiceMiniMax", () => {
|
||||
const result = await applyAuthChoiceMiniMax({
|
||||
authChoice: "openrouter-api-key",
|
||||
config: {},
|
||||
prompter: createMinimaxPrompter(),
|
||||
prompter: createWizardPrompter({}),
|
||||
runtime: createExitThrowingRuntime(),
|
||||
setDefaultModel: true,
|
||||
});
|
||||
@@ -104,61 +84,52 @@ describe("applyAuthChoiceMiniMax", () => {
|
||||
|
||||
it.each([
|
||||
{
|
||||
caseName: "uses opts token for minimax-api without prompt",
|
||||
authChoice: "minimax-api" as const,
|
||||
caseName: "uses opts token for minimax-global-api without prompt",
|
||||
authChoice: "minimax-global-api" as const,
|
||||
tokenProvider: "minimax",
|
||||
token: "mm-opts-token",
|
||||
profileId: "minimax:default",
|
||||
provider: "minimax",
|
||||
profileId: "minimax:global",
|
||||
expectedModel: "minimax/MiniMax-M2.5",
|
||||
},
|
||||
{
|
||||
caseName:
|
||||
"uses opts token for minimax-api-key-cn with trimmed/case-insensitive tokenProvider",
|
||||
authChoice: "minimax-api-key-cn" as const,
|
||||
tokenProvider: " MINIMAX-CN ",
|
||||
caseName: "uses opts token for minimax-cn-api with trimmed/case-insensitive tokenProvider",
|
||||
authChoice: "minimax-cn-api" as const,
|
||||
tokenProvider: " MINIMAX ",
|
||||
token: "mm-cn-opts-token",
|
||||
profileId: "minimax-cn:default",
|
||||
provider: "minimax-cn",
|
||||
expectedModel: "minimax-cn/MiniMax-M2.5",
|
||||
profileId: "minimax:cn",
|
||||
expectedModel: "minimax/MiniMax-M2.5",
|
||||
},
|
||||
])(
|
||||
"$caseName",
|
||||
async ({ authChoice, tokenProvider, token, profileId, provider, expectedModel }) => {
|
||||
const { agentDir, result, text, confirm } = await runMiniMaxChoice({
|
||||
authChoice,
|
||||
opts: {
|
||||
tokenProvider,
|
||||
token,
|
||||
},
|
||||
});
|
||||
])("$caseName", async ({ authChoice, tokenProvider, token, profileId, expectedModel }) => {
|
||||
const { agentDir, result, text, confirm } = await runMiniMaxChoice({
|
||||
authChoice,
|
||||
opts: { tokenProvider, token },
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.config.auth?.profiles?.[profileId]).toMatchObject({
|
||||
provider,
|
||||
mode: "api_key",
|
||||
});
|
||||
expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
|
||||
expectedModel,
|
||||
);
|
||||
expect(text).not.toHaveBeenCalled();
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.config.auth?.profiles?.[profileId]).toMatchObject({
|
||||
provider: "minimax",
|
||||
mode: "api_key",
|
||||
});
|
||||
expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
|
||||
expectedModel,
|
||||
);
|
||||
expect(text).not.toHaveBeenCalled();
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
|
||||
const parsed = await readAuthProfiles(agentDir);
|
||||
expect(parsed.profiles?.[profileId]?.key).toBe(token);
|
||||
},
|
||||
);
|
||||
const parsed = await readAuthProfiles(agentDir);
|
||||
expect(parsed.profiles?.[profileId]?.key).toBe(token);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "uses env token for minimax-api-key-cn as plaintext by default",
|
||||
name: "uses env token for minimax-cn-api as plaintext by default",
|
||||
opts: undefined,
|
||||
expectKey: "mm-env-token",
|
||||
expectKeyRef: undefined,
|
||||
expectConfirmCalls: 1,
|
||||
},
|
||||
{
|
||||
name: "uses env token for minimax-api-key-cn as keyRef in ref mode",
|
||||
name: "uses env token for minimax-cn-api as keyRef in ref mode",
|
||||
opts: { secretInputMode: "ref" as const }, // pragma: allowlist secret
|
||||
expectKey: undefined,
|
||||
expectKeyRef: {
|
||||
@@ -170,54 +141,68 @@ describe("applyAuthChoiceMiniMax", () => {
|
||||
},
|
||||
])("$name", async ({ opts, expectKey, expectKeyRef, expectConfirmCalls }) => {
|
||||
const { agentDir, result, text, confirm } = await runMiniMaxChoice({
|
||||
authChoice: "minimax-api-key-cn",
|
||||
authChoice: "minimax-cn-api",
|
||||
opts,
|
||||
env: { apiKey: "mm-env-token" }, // pragma: allowlist secret
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
if (!opts) {
|
||||
expect(result?.config.auth?.profiles?.["minimax-cn:default"]).toMatchObject({
|
||||
provider: "minimax-cn",
|
||||
expect(result?.config.auth?.profiles?.["minimax:cn"]).toMatchObject({
|
||||
provider: "minimax",
|
||||
mode: "api_key",
|
||||
});
|
||||
expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
|
||||
"minimax-cn/MiniMax-M2.5",
|
||||
"minimax/MiniMax-M2.5",
|
||||
);
|
||||
}
|
||||
expect(text).not.toHaveBeenCalled();
|
||||
expect(confirm).toHaveBeenCalledTimes(expectConfirmCalls);
|
||||
|
||||
const parsed = await readAuthProfiles(agentDir);
|
||||
expect(parsed.profiles?.["minimax-cn:default"]?.key).toBe(expectKey);
|
||||
expect(parsed.profiles?.["minimax:cn"]?.key).toBe(expectKey);
|
||||
if (expectKeyRef) {
|
||||
expect(parsed.profiles?.["minimax-cn:default"]?.keyRef).toEqual(expectKeyRef);
|
||||
expect(parsed.profiles?.["minimax:cn"]?.keyRef).toEqual(expectKeyRef);
|
||||
} else {
|
||||
expect(parsed.profiles?.["minimax-cn:default"]?.keyRef).toBeUndefined();
|
||||
expect(parsed.profiles?.["minimax:cn"]?.keyRef).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("uses minimax-api-lightning default model", async () => {
|
||||
it("minimax-global-api uses minimax:global profile and minimax/MiniMax-M2.5 model", async () => {
|
||||
const { agentDir, result, text, confirm } = await runMiniMaxChoice({
|
||||
authChoice: "minimax-api-lightning",
|
||||
authChoice: "minimax-global-api",
|
||||
opts: {
|
||||
tokenProvider: "minimax",
|
||||
token: "mm-lightning-token",
|
||||
token: "mm-global-token",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.config.auth?.profiles?.["minimax:default"]).toMatchObject({
|
||||
expect(result?.config.auth?.profiles?.["minimax:global"]).toMatchObject({
|
||||
provider: "minimax",
|
||||
mode: "api_key",
|
||||
});
|
||||
expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
|
||||
"minimax/MiniMax-M2.5-highspeed",
|
||||
"minimax/MiniMax-M2.5",
|
||||
);
|
||||
expect(result?.config.models?.providers?.minimax?.baseUrl).toContain("minimax.io");
|
||||
expect(text).not.toHaveBeenCalled();
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
|
||||
const parsed = await readAuthProfiles(agentDir);
|
||||
expect(parsed.profiles?.["minimax:default"]?.key).toBe("mm-lightning-token");
|
||||
expect(parsed.profiles?.["minimax:global"]?.key).toBe("mm-global-token");
|
||||
});
|
||||
|
||||
it("minimax-cn-api sets CN baseUrl", async () => {
|
||||
const { result } = await runMiniMaxChoice({
|
||||
authChoice: "minimax-cn-api",
|
||||
opts: {
|
||||
tokenProvider: "minimax",
|
||||
token: "mm-cn-token",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.config.models?.providers?.minimax?.baseUrl).toContain("minimaxi.com");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,130 +12,93 @@ import {
|
||||
applyMinimaxApiConfigCn,
|
||||
applyMinimaxApiProviderConfig,
|
||||
applyMinimaxApiProviderConfigCn,
|
||||
applyMinimaxConfig,
|
||||
applyMinimaxProviderConfig,
|
||||
setMinimaxApiKey,
|
||||
} from "./onboard-auth.js";
|
||||
|
||||
export async function applyAuthChoiceMiniMax(
|
||||
params: ApplyAuthChoiceParams,
|
||||
): Promise<ApplyAuthChoiceResult | null> {
|
||||
let nextConfig = params.config;
|
||||
let agentModelOverride: string | undefined;
|
||||
const applyProviderDefaultModel = createAuthChoiceDefaultModelApplierForMutableState(
|
||||
params,
|
||||
() => nextConfig,
|
||||
(config) => (nextConfig = config),
|
||||
() => agentModelOverride,
|
||||
(model) => (agentModelOverride = model),
|
||||
);
|
||||
const requestedSecretInputMode = normalizeSecretInputModeInput(params.opts?.secretInputMode);
|
||||
const ensureMinimaxApiKey = async (opts: {
|
||||
profileId: string;
|
||||
promptMessage: string;
|
||||
}): Promise<void> => {
|
||||
// OAuth paths — delegate to plugin, no API key needed
|
||||
if (params.authChoice === "minimax-global-oauth") {
|
||||
return await applyAuthChoicePluginProvider(params, {
|
||||
authChoice: "minimax-global-oauth",
|
||||
pluginId: "minimax-portal-auth",
|
||||
providerId: "minimax-portal",
|
||||
methodId: "oauth",
|
||||
label: "MiniMax",
|
||||
});
|
||||
}
|
||||
|
||||
if (params.authChoice === "minimax-cn-oauth") {
|
||||
return await applyAuthChoicePluginProvider(params, {
|
||||
authChoice: "minimax-cn-oauth",
|
||||
pluginId: "minimax-portal-auth",
|
||||
providerId: "minimax-portal",
|
||||
methodId: "oauth-cn",
|
||||
label: "MiniMax CN",
|
||||
});
|
||||
}
|
||||
|
||||
// API key paths
|
||||
if (params.authChoice === "minimax-global-api" || params.authChoice === "minimax-cn-api") {
|
||||
const isCn = params.authChoice === "minimax-cn-api";
|
||||
const profileId = isCn ? "minimax:cn" : "minimax:global";
|
||||
const keyLink = isCn
|
||||
? "https://platform.minimaxi.com/user-center/basic-information/interface-key"
|
||||
: "https://platform.minimax.io/user-center/basic-information/interface-key";
|
||||
const promptMessage = `Enter MiniMax ${isCn ? "CN " : ""}API key (sk-api- or sk-cp-)\n${keyLink}`;
|
||||
|
||||
let nextConfig = params.config;
|
||||
let agentModelOverride: string | undefined;
|
||||
const applyProviderDefaultModel = createAuthChoiceDefaultModelApplierForMutableState(
|
||||
params,
|
||||
() => nextConfig,
|
||||
(config) => (nextConfig = config),
|
||||
() => agentModelOverride,
|
||||
(model) => (agentModelOverride = model),
|
||||
);
|
||||
const requestedSecretInputMode = normalizeSecretInputModeInput(params.opts?.secretInputMode);
|
||||
|
||||
// Warn when both Global and CN share the same `minimax` provider entry — configuring one
|
||||
// overwrites the other's baseUrl. Only show when the other profile is already present.
|
||||
const otherProfileId = isCn ? "minimax:global" : "minimax:cn";
|
||||
const hasOtherProfile = Boolean(nextConfig.auth?.profiles?.[otherProfileId]);
|
||||
const noteMessage = hasOtherProfile
|
||||
? `Note: Global and CN both use the "minimax" provider entry. Saving this key will overwrite the existing ${isCn ? "Global" : "CN"} endpoint (${otherProfileId}).`
|
||||
: undefined;
|
||||
|
||||
await ensureApiKeyFromOptionEnvOrPrompt({
|
||||
token: params.opts?.token,
|
||||
tokenProvider: params.opts?.tokenProvider,
|
||||
secretInputMode: requestedSecretInputMode,
|
||||
config: nextConfig,
|
||||
expectedProviders: ["minimax", "minimax-cn"],
|
||||
// Accept "minimax-cn" as a legacy tokenProvider alias for the CN path.
|
||||
expectedProviders: isCn ? ["minimax", "minimax-cn"] : ["minimax"],
|
||||
provider: "minimax",
|
||||
envLabel: "MINIMAX_API_KEY",
|
||||
promptMessage: opts.promptMessage,
|
||||
promptMessage,
|
||||
normalize: normalizeApiKeyInput,
|
||||
validate: validateApiKeyInput,
|
||||
prompter: params.prompter,
|
||||
noteMessage,
|
||||
setCredential: async (apiKey, mode) =>
|
||||
setMinimaxApiKey(apiKey, params.agentDir, opts.profileId, { secretInputMode: mode }),
|
||||
});
|
||||
};
|
||||
const applyMinimaxApiVariant = async (opts: {
|
||||
profileId: string;
|
||||
provider: "minimax" | "minimax-cn";
|
||||
promptMessage: string;
|
||||
modelRefPrefix: "minimax" | "minimax-cn";
|
||||
modelId: string;
|
||||
applyDefaultConfig: (
|
||||
config: ApplyAuthChoiceParams["config"],
|
||||
modelId: string,
|
||||
) => ApplyAuthChoiceParams["config"];
|
||||
applyProviderConfig: (
|
||||
config: ApplyAuthChoiceParams["config"],
|
||||
modelId: string,
|
||||
) => ApplyAuthChoiceParams["config"];
|
||||
}): Promise<ApplyAuthChoiceResult> => {
|
||||
await ensureMinimaxApiKey({
|
||||
profileId: opts.profileId,
|
||||
promptMessage: opts.promptMessage,
|
||||
setMinimaxApiKey(apiKey, params.agentDir, profileId, { secretInputMode: mode }),
|
||||
});
|
||||
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId: opts.profileId,
|
||||
provider: opts.provider,
|
||||
profileId,
|
||||
provider: "minimax",
|
||||
mode: "api_key",
|
||||
});
|
||||
const modelRef = `${opts.modelRefPrefix}/${opts.modelId}`;
|
||||
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel: modelRef,
|
||||
applyDefaultConfig: (config) => opts.applyDefaultConfig(config, opts.modelId),
|
||||
applyProviderConfig: (config) => opts.applyProviderConfig(config, opts.modelId),
|
||||
});
|
||||
return { config: nextConfig, agentModelOverride };
|
||||
};
|
||||
if (params.authChoice === "minimax-portal") {
|
||||
// Let user choose between Global/CN endpoints
|
||||
const endpoint = await params.prompter.select({
|
||||
message: "Select MiniMax endpoint",
|
||||
options: [
|
||||
{ value: "oauth", label: "Global", hint: "OAuth for international users" },
|
||||
{ value: "oauth-cn", label: "CN", hint: "OAuth for users in China" },
|
||||
],
|
||||
defaultModel: "minimax/MiniMax-M2.5",
|
||||
applyDefaultConfig: (config) =>
|
||||
isCn ? applyMinimaxApiConfigCn(config) : applyMinimaxApiConfig(config),
|
||||
applyProviderConfig: (config) =>
|
||||
isCn ? applyMinimaxApiProviderConfigCn(config) : applyMinimaxApiProviderConfig(config),
|
||||
});
|
||||
|
||||
return await applyAuthChoicePluginProvider(params, {
|
||||
authChoice: "minimax-portal",
|
||||
pluginId: "minimax-portal-auth",
|
||||
providerId: "minimax-portal",
|
||||
methodId: endpoint,
|
||||
label: "MiniMax",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
params.authChoice === "minimax-cloud" ||
|
||||
params.authChoice === "minimax-api" ||
|
||||
params.authChoice === "minimax-api-lightning"
|
||||
) {
|
||||
return await applyMinimaxApiVariant({
|
||||
profileId: "minimax:default",
|
||||
provider: "minimax",
|
||||
promptMessage: "Enter MiniMax API key",
|
||||
modelRefPrefix: "minimax",
|
||||
modelId:
|
||||
params.authChoice === "minimax-api-lightning" ? "MiniMax-M2.5-highspeed" : "MiniMax-M2.5",
|
||||
applyDefaultConfig: applyMinimaxApiConfig,
|
||||
applyProviderConfig: applyMinimaxApiProviderConfig,
|
||||
});
|
||||
}
|
||||
|
||||
if (params.authChoice === "minimax-api-key-cn") {
|
||||
return await applyMinimaxApiVariant({
|
||||
profileId: "minimax-cn:default",
|
||||
provider: "minimax-cn",
|
||||
promptMessage: "Enter MiniMax China API key",
|
||||
modelRefPrefix: "minimax-cn",
|
||||
modelId: "MiniMax-M2.5",
|
||||
applyDefaultConfig: applyMinimaxApiConfigCn,
|
||||
applyProviderConfig: applyMinimaxApiProviderConfigCn,
|
||||
});
|
||||
}
|
||||
|
||||
if (params.authChoice === "minimax") {
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel: "lmstudio/minimax-m2.5-gs32",
|
||||
applyDefaultConfig: applyMinimaxConfig,
|
||||
applyProviderConfig: applyMinimaxProviderConfig,
|
||||
});
|
||||
return { config: nextConfig, agentModelOverride };
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,10 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
|
||||
"huggingface-api-key": "huggingface",
|
||||
"github-copilot": "github-copilot",
|
||||
"copilot-proxy": "copilot-proxy",
|
||||
"minimax-cloud": "minimax",
|
||||
"minimax-api": "minimax",
|
||||
"minimax-api-key-cn": "minimax-cn",
|
||||
"minimax-api-lightning": "minimax",
|
||||
minimax: "lmstudio",
|
||||
"minimax-global-oauth": "minimax-portal",
|
||||
"minimax-global-api": "minimax",
|
||||
"minimax-cn-oauth": "minimax-portal",
|
||||
"minimax-cn-api": "minimax",
|
||||
"opencode-zen": "opencode",
|
||||
"opencode-go": "opencode-go",
|
||||
"xai-api-key": "xai",
|
||||
@@ -46,7 +45,6 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
|
||||
"qwen-portal": "qwen-portal",
|
||||
"volcengine-api-key": "volcengine",
|
||||
"byteplus-api-key": "byteplus",
|
||||
"minimax-portal": "minimax-portal",
|
||||
"qianfan-api-key": "qianfan",
|
||||
"custom-api-key": "custom",
|
||||
};
|
||||
|
||||
@@ -208,8 +208,8 @@ describe("applyAuthChoice", () => {
|
||||
it("prompts and writes provider API key for common providers", async () => {
|
||||
const scenarios: Array<{
|
||||
authChoice:
|
||||
| "minimax-api"
|
||||
| "minimax-api-key-cn"
|
||||
| "minimax-global-api"
|
||||
| "minimax-cn-api"
|
||||
| "synthetic-api-key"
|
||||
| "huggingface-api-key";
|
||||
promptContains: string;
|
||||
@@ -220,17 +220,17 @@ describe("applyAuthChoice", () => {
|
||||
expectedModelPrefix?: string;
|
||||
}> = [
|
||||
{
|
||||
authChoice: "minimax-api" as const,
|
||||
authChoice: "minimax-global-api" as const,
|
||||
promptContains: "Enter MiniMax API key",
|
||||
profileId: "minimax:default",
|
||||
profileId: "minimax:global",
|
||||
provider: "minimax",
|
||||
token: "sk-minimax-test",
|
||||
},
|
||||
{
|
||||
authChoice: "minimax-api-key-cn" as const,
|
||||
promptContains: "Enter MiniMax China API key",
|
||||
profileId: "minimax-cn:default",
|
||||
provider: "minimax-cn",
|
||||
authChoice: "minimax-cn-api" as const,
|
||||
promptContains: "Enter MiniMax CN API key",
|
||||
profileId: "minimax:cn",
|
||||
provider: "minimax",
|
||||
token: "sk-minimax-test",
|
||||
expectedBaseUrl: MINIMAX_CN_API_BASE_URL,
|
||||
},
|
||||
@@ -1243,7 +1243,7 @@ describe("applyAuthChoice", () => {
|
||||
|
||||
it("writes portal OAuth credentials for plugin providers", async () => {
|
||||
const scenarios: Array<{
|
||||
authChoice: "qwen-portal" | "minimax-portal";
|
||||
authChoice: "qwen-portal" | "minimax-global-oauth";
|
||||
label: string;
|
||||
authId: string;
|
||||
authLabel: string;
|
||||
@@ -1268,7 +1268,7 @@ describe("applyAuthChoice", () => {
|
||||
apiKey: "qwen-oauth", // pragma: allowlist secret
|
||||
},
|
||||
{
|
||||
authChoice: "minimax-portal",
|
||||
authChoice: "minimax-global-oauth",
|
||||
label: "MiniMax",
|
||||
authId: "oauth",
|
||||
authLabel: "MiniMax OAuth (Global)",
|
||||
@@ -1278,7 +1278,6 @@ describe("applyAuthChoice", () => {
|
||||
api: "anthropic-messages",
|
||||
defaultModel: "minimax-portal/MiniMax-M2.5",
|
||||
apiKey: "minimax-oauth", // pragma: allowlist secret
|
||||
selectValue: "oauth",
|
||||
},
|
||||
];
|
||||
for (const scenario of scenarios) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { toAgentModelListLike } from "../config/model-input.js";
|
||||
import type { ModelProviderConfig } from "../config/types.models.js";
|
||||
import {
|
||||
applyAgentDefaultModelPrimary,
|
||||
@@ -7,154 +6,10 @@ import {
|
||||
} from "./onboard-auth.config-shared.js";
|
||||
import {
|
||||
buildMinimaxApiModelDefinition,
|
||||
buildMinimaxModelDefinition,
|
||||
DEFAULT_MINIMAX_BASE_URL,
|
||||
DEFAULT_MINIMAX_CONTEXT_WINDOW,
|
||||
DEFAULT_MINIMAX_MAX_TOKENS,
|
||||
MINIMAX_API_BASE_URL,
|
||||
MINIMAX_CN_API_BASE_URL,
|
||||
MINIMAX_HOSTED_COST,
|
||||
MINIMAX_HOSTED_MODEL_ID,
|
||||
MINIMAX_HOSTED_MODEL_REF,
|
||||
MINIMAX_LM_STUDIO_COST,
|
||||
} from "./onboard-auth.models.js";
|
||||
|
||||
export function applyMinimaxProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const models = { ...cfg.agents?.defaults?.models };
|
||||
models["anthropic/claude-opus-4-6"] = {
|
||||
...models["anthropic/claude-opus-4-6"],
|
||||
alias: models["anthropic/claude-opus-4-6"]?.alias ?? "Opus",
|
||||
};
|
||||
models["lmstudio/minimax-m2.5-gs32"] = {
|
||||
...models["lmstudio/minimax-m2.5-gs32"],
|
||||
alias: models["lmstudio/minimax-m2.5-gs32"]?.alias ?? "Minimax",
|
||||
};
|
||||
|
||||
const providers = { ...cfg.models?.providers };
|
||||
if (!providers.lmstudio) {
|
||||
providers.lmstudio = {
|
||||
baseUrl: "http://127.0.0.1:1234/v1",
|
||||
apiKey: "lmstudio",
|
||||
api: "openai-responses",
|
||||
models: [
|
||||
buildMinimaxModelDefinition({
|
||||
id: "minimax-m2.5-gs32",
|
||||
name: "MiniMax M2.5 GS32",
|
||||
reasoning: false,
|
||||
cost: MINIMAX_LM_STUDIO_COST,
|
||||
contextWindow: 196608,
|
||||
maxTokens: 8192,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return applyOnboardAuthAgentModelsAndProviders(cfg, { agentModels: models, providers });
|
||||
}
|
||||
|
||||
export function applyMinimaxHostedProviderConfig(
|
||||
cfg: OpenClawConfig,
|
||||
params?: { baseUrl?: string },
|
||||
): OpenClawConfig {
|
||||
const models = { ...cfg.agents?.defaults?.models };
|
||||
models[MINIMAX_HOSTED_MODEL_REF] = {
|
||||
...models[MINIMAX_HOSTED_MODEL_REF],
|
||||
alias: models[MINIMAX_HOSTED_MODEL_REF]?.alias ?? "Minimax",
|
||||
};
|
||||
|
||||
const providers = { ...cfg.models?.providers };
|
||||
const hostedModel = buildMinimaxModelDefinition({
|
||||
id: MINIMAX_HOSTED_MODEL_ID,
|
||||
cost: MINIMAX_HOSTED_COST,
|
||||
contextWindow: DEFAULT_MINIMAX_CONTEXT_WINDOW,
|
||||
maxTokens: DEFAULT_MINIMAX_MAX_TOKENS,
|
||||
});
|
||||
const existingProvider = providers.minimax;
|
||||
const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : [];
|
||||
const hasHostedModel = existingModels.some((model) => model.id === MINIMAX_HOSTED_MODEL_ID);
|
||||
const mergedModels = hasHostedModel ? existingModels : [...existingModels, hostedModel];
|
||||
providers.minimax = {
|
||||
...existingProvider,
|
||||
baseUrl: params?.baseUrl?.trim() || DEFAULT_MINIMAX_BASE_URL,
|
||||
apiKey: "minimax",
|
||||
api: "openai-completions",
|
||||
models: mergedModels.length > 0 ? mergedModels : [hostedModel],
|
||||
};
|
||||
|
||||
return applyOnboardAuthAgentModelsAndProviders(cfg, { agentModels: models, providers });
|
||||
}
|
||||
|
||||
export function applyMinimaxConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const next = applyMinimaxProviderConfig(cfg);
|
||||
return applyAgentDefaultModelPrimary(next, "lmstudio/minimax-m2.5-gs32");
|
||||
}
|
||||
|
||||
export function applyMinimaxHostedConfig(
|
||||
cfg: OpenClawConfig,
|
||||
params?: { baseUrl?: string },
|
||||
): OpenClawConfig {
|
||||
const next = applyMinimaxHostedProviderConfig(cfg, params);
|
||||
return {
|
||||
...next,
|
||||
agents: {
|
||||
...next.agents,
|
||||
defaults: {
|
||||
...next.agents?.defaults,
|
||||
model: {
|
||||
...toAgentModelListLike(next.agents?.defaults?.model),
|
||||
primary: MINIMAX_HOSTED_MODEL_REF,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// MiniMax Anthropic-compatible API (platform.minimax.io/anthropic)
|
||||
export function applyMinimaxApiProviderConfig(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiProviderConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
export function applyMinimaxApiConfig(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
// MiniMax China API (api.minimaxi.com)
|
||||
export function applyMinimaxApiProviderConfigCn(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiProviderConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax-cn",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_CN_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
export function applyMinimaxApiConfigCn(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax-cn",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_CN_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
type MinimaxApiProviderConfigParams = {
|
||||
providerId: string;
|
||||
modelId: string;
|
||||
@@ -193,17 +48,7 @@ function applyMinimaxApiProviderConfigWithBaseUrl(
|
||||
alias: "Minimax",
|
||||
};
|
||||
|
||||
return {
|
||||
...cfg,
|
||||
agents: {
|
||||
...cfg.agents,
|
||||
defaults: {
|
||||
...cfg.agents?.defaults,
|
||||
models,
|
||||
},
|
||||
},
|
||||
models: { mode: cfg.models?.mode ?? "merge", providers },
|
||||
};
|
||||
return applyOnboardAuthAgentModelsAndProviders(cfg, { agentModels: models, providers });
|
||||
}
|
||||
|
||||
function applyMinimaxApiConfigWithBaseUrl(
|
||||
@@ -213,3 +58,49 @@ function applyMinimaxApiConfigWithBaseUrl(
|
||||
const next = applyMinimaxApiProviderConfigWithBaseUrl(cfg, params);
|
||||
return applyAgentDefaultModelPrimary(next, `${params.providerId}/${params.modelId}`);
|
||||
}
|
||||
|
||||
// MiniMax Global API (platform.minimax.io/anthropic)
|
||||
export function applyMinimaxApiProviderConfig(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiProviderConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
export function applyMinimaxApiConfig(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
// MiniMax CN API (api.minimaxi.com/anthropic) — same provider id, different baseUrl
|
||||
export function applyMinimaxApiProviderConfigCn(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiProviderConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_CN_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
export function applyMinimaxApiConfigCn(
|
||||
cfg: OpenClawConfig,
|
||||
modelId: string = "MiniMax-M2.5",
|
||||
): OpenClawConfig {
|
||||
return applyMinimaxApiConfigWithBaseUrl(cfg, {
|
||||
providerId: "minimax",
|
||||
modelId,
|
||||
baseUrl: MINIMAX_CN_API_BASE_URL,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,10 +50,6 @@ export {
|
||||
applyMinimaxApiConfigCn,
|
||||
applyMinimaxApiProviderConfig,
|
||||
applyMinimaxApiProviderConfigCn,
|
||||
applyMinimaxConfig,
|
||||
applyMinimaxHostedConfig,
|
||||
applyMinimaxHostedProviderConfig,
|
||||
applyMinimaxProviderConfig,
|
||||
} from "./onboard-auth.config-minimax.js";
|
||||
|
||||
export {
|
||||
|
||||
@@ -183,16 +183,16 @@ describe("onboard (non-interactive): provider auth", () => {
|
||||
it("stores MiniMax API key and uses global baseUrl by default", async () => {
|
||||
await withOnboardEnv("openclaw-onboard-minimax-", async (env) => {
|
||||
const cfg = await runOnboardingAndReadConfig(env, {
|
||||
authChoice: "minimax-api",
|
||||
authChoice: "minimax-global-api",
|
||||
minimaxApiKey: "sk-minimax-test", // pragma: allowlist secret
|
||||
});
|
||||
|
||||
expect(cfg.auth?.profiles?.["minimax:default"]?.provider).toBe("minimax");
|
||||
expect(cfg.auth?.profiles?.["minimax:default"]?.mode).toBe("api_key");
|
||||
expect(cfg.auth?.profiles?.["minimax:global"]?.provider).toBe("minimax");
|
||||
expect(cfg.auth?.profiles?.["minimax:global"]?.mode).toBe("api_key");
|
||||
expect(cfg.models?.providers?.minimax?.baseUrl).toBe(MINIMAX_API_BASE_URL);
|
||||
expect(cfg.agents?.defaults?.model?.primary).toBe("minimax/MiniMax-M2.5");
|
||||
await expectApiKeyProfile({
|
||||
profileId: "minimax:default",
|
||||
profileId: "minimax:global",
|
||||
provider: "minimax",
|
||||
key: "sk-minimax-test",
|
||||
});
|
||||
@@ -202,17 +202,17 @@ describe("onboard (non-interactive): provider auth", () => {
|
||||
it("supports MiniMax CN API endpoint auth choice", async () => {
|
||||
await withOnboardEnv("openclaw-onboard-minimax-cn-", async (env) => {
|
||||
const cfg = await runOnboardingAndReadConfig(env, {
|
||||
authChoice: "minimax-api-key-cn",
|
||||
authChoice: "minimax-cn-api",
|
||||
minimaxApiKey: "sk-minimax-test", // pragma: allowlist secret
|
||||
});
|
||||
|
||||
expect(cfg.auth?.profiles?.["minimax-cn:default"]?.provider).toBe("minimax-cn");
|
||||
expect(cfg.auth?.profiles?.["minimax-cn:default"]?.mode).toBe("api_key");
|
||||
expect(cfg.models?.providers?.["minimax-cn"]?.baseUrl).toBe(MINIMAX_CN_API_BASE_URL);
|
||||
expect(cfg.agents?.defaults?.model?.primary).toBe("minimax-cn/MiniMax-M2.5");
|
||||
expect(cfg.auth?.profiles?.["minimax:cn"]?.provider).toBe("minimax");
|
||||
expect(cfg.auth?.profiles?.["minimax:cn"]?.mode).toBe("api_key");
|
||||
expect(cfg.models?.providers?.minimax?.baseUrl).toBe(MINIMAX_CN_API_BASE_URL);
|
||||
expect(cfg.agents?.defaults?.model?.primary).toBe("minimax/MiniMax-M2.5");
|
||||
await expectApiKeyProfile({
|
||||
profileId: "minimax-cn:default",
|
||||
provider: "minimax-cn",
|
||||
profileId: "minimax:cn",
|
||||
provider: "minimax",
|
||||
key: "sk-minimax-test",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
applyKimiCodeConfig,
|
||||
applyMinimaxApiConfig,
|
||||
applyMinimaxApiConfigCn,
|
||||
applyMinimaxConfig,
|
||||
applyMoonshotConfig,
|
||||
applyMoonshotConfigCn,
|
||||
applyOpencodeGoConfig,
|
||||
@@ -863,22 +862,37 @@ export async function applyNonInteractiveAuthChoice(params: {
|
||||
return applyVeniceConfig(nextConfig);
|
||||
}
|
||||
|
||||
if (
|
||||
authChoice === "minimax-cloud" ||
|
||||
authChoice === "minimax-api" ||
|
||||
authChoice === "minimax-api-key-cn" ||
|
||||
authChoice === "minimax-api-lightning"
|
||||
) {
|
||||
const isCn = authChoice === "minimax-api-key-cn";
|
||||
const providerId = isCn ? "minimax-cn" : "minimax";
|
||||
const profileId = `${providerId}:default`;
|
||||
// Legacy aliases: these choice values were removed; fail with an actionable message so
|
||||
// existing CI automation gets a clear error instead of silently exiting 0 with no auth.
|
||||
const REMOVED_MINIMAX_CHOICES: Record<string, string> = {
|
||||
minimax: "minimax-global-api",
|
||||
"minimax-api": "minimax-global-api",
|
||||
"minimax-cloud": "minimax-global-api",
|
||||
"minimax-api-lightning": "minimax-global-api",
|
||||
"minimax-api-key-cn": "minimax-cn-api",
|
||||
};
|
||||
if (Object.prototype.hasOwnProperty.call(REMOVED_MINIMAX_CHOICES, authChoice as string)) {
|
||||
const replacement = REMOVED_MINIMAX_CHOICES[authChoice as string];
|
||||
runtime.error(
|
||||
`"${authChoice as string}" is no longer supported. Use --auth-choice ${replacement} instead.`,
|
||||
);
|
||||
runtime.exit(1);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (authChoice === "minimax-global-api" || authChoice === "minimax-cn-api") {
|
||||
const isCn = authChoice === "minimax-cn-api";
|
||||
const profileId = isCn ? "minimax:cn" : "minimax:global";
|
||||
const resolved = await resolveApiKey({
|
||||
provider: providerId,
|
||||
provider: "minimax",
|
||||
cfg: baseConfig,
|
||||
flagValue: opts.minimaxApiKey,
|
||||
flagName: "--minimax-api-key",
|
||||
envVar: "MINIMAX_API_KEY",
|
||||
runtime,
|
||||
// Disable profile fallback: both regions share provider "minimax", so an existing
|
||||
// Global profile key must not be silently reused when configuring CN (and vice versa).
|
||||
allowProfile: false,
|
||||
});
|
||||
if (!resolved) {
|
||||
return null;
|
||||
@@ -892,18 +906,10 @@ export async function applyNonInteractiveAuthChoice(params: {
|
||||
}
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId,
|
||||
provider: providerId,
|
||||
provider: "minimax",
|
||||
mode: "api_key",
|
||||
});
|
||||
const modelId =
|
||||
authChoice === "minimax-api-lightning" ? "MiniMax-M2.5-highspeed" : "MiniMax-M2.5";
|
||||
return isCn
|
||||
? applyMinimaxApiConfigCn(nextConfig, modelId)
|
||||
: applyMinimaxApiConfig(nextConfig, modelId);
|
||||
}
|
||||
|
||||
if (authChoice === "minimax") {
|
||||
return applyMinimaxConfig(nextConfig);
|
||||
return isCn ? applyMinimaxApiConfigCn(nextConfig) : applyMinimaxApiConfig(nextConfig);
|
||||
}
|
||||
|
||||
if (authChoice === "opencode-zen") {
|
||||
@@ -1091,7 +1097,8 @@ export async function applyNonInteractiveAuthChoice(params: {
|
||||
authChoice === "chutes" ||
|
||||
authChoice === "openai-codex" ||
|
||||
authChoice === "qwen-portal" ||
|
||||
authChoice === "minimax-portal"
|
||||
authChoice === "minimax-global-oauth" ||
|
||||
authChoice === "minimax-cn-oauth"
|
||||
) {
|
||||
runtime.error("OAuth requires interactive mode.");
|
||||
runtime.exit(1);
|
||||
|
||||
@@ -126,7 +126,7 @@ export const ONBOARD_PROVIDER_AUTH_FLAGS: ReadonlyArray<OnboardProviderAuthFlag>
|
||||
},
|
||||
{
|
||||
optionKey: "minimaxApiKey",
|
||||
authChoice: "minimax-api",
|
||||
authChoice: "minimax-global-api",
|
||||
cliFlag: "--minimax-api-key",
|
||||
cliOption: "--minimax-api-key <key>",
|
||||
description: "MiniMax API key",
|
||||
|
||||
@@ -35,12 +35,10 @@ export type AuthChoice =
|
||||
| "zai-global"
|
||||
| "zai-cn"
|
||||
| "xiaomi-api-key"
|
||||
| "minimax-cloud"
|
||||
| "minimax"
|
||||
| "minimax-api"
|
||||
| "minimax-api-key-cn"
|
||||
| "minimax-api-lightning"
|
||||
| "minimax-portal"
|
||||
| "minimax-global-oauth"
|
||||
| "minimax-global-api"
|
||||
| "minimax-cn-oauth"
|
||||
| "minimax-cn-api"
|
||||
| "opencode-zen"
|
||||
| "opencode-go"
|
||||
| "github-copilot"
|
||||
|
||||
Reference in New Issue
Block a user