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, createExitThrowingRuntime, createWizardPrompter, readAuthProfilesForAgent, 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", "OPENCLAW_AGENT_DIR", "PI_CODING_AGENT_DIR", "MINIMAX_API_KEY", "MINIMAX_OAUTH_TOKEN", ]); async function setupTempState() { const env = await setupAuthTestEnv("openclaw-minimax-"); lifecycle.setStateDir(env.stateDir); return env.agentDir; } async function readAuthProfiles(agentDir: string) { return await readAuthProfilesForAgent<{ profiles?: Record; }>(agentDir); } function resetMiniMaxEnv(): void { delete process.env.MINIMAX_API_KEY; delete process.env.MINIMAX_OAUTH_TOKEN; } async function runMiniMaxChoice(params: { authChoice: Parameters[0]["authChoice"]; opts?: Parameters[0]["opts"]; env?: { apiKey?: string; oauthToken?: string }; prompter?: Parameters[0]; }) { 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, confirm, ...params.prompter, }), runtime: createExitThrowingRuntime(), setDefaultModel: true, ...(params.opts ? { opts: params.opts } : {}), }); return { agentDir, result, text, confirm }; } afterEach(async () => { await lifecycle.cleanup(); }); it("returns null for unrelated authChoice", async () => { const result = await applyAuthChoiceMiniMax({ authChoice: "openrouter-api-key", config: {}, prompter: createMinimaxPrompter(), runtime: createExitThrowingRuntime(), setDefaultModel: true, }); expect(result).toBeNull(); }); it.each([ { caseName: "uses opts token for minimax-api without prompt", authChoice: "minimax-api" as const, tokenProvider: "minimax", token: "mm-opts-token", profileId: "minimax:default", provider: "minimax", 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 ", token: "mm-cn-opts-token", profileId: "minimax-cn:default", provider: "minimax-cn", expectedModel: "minimax-cn/MiniMax-M2.5", }, ])( "$caseName", async ({ authChoice, tokenProvider, token, profileId, provider, 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(); 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", opts: undefined, expectKey: "mm-env-token", expectKeyRef: undefined, expectConfirmCalls: 1, }, { name: "uses env token for minimax-api-key-cn as keyRef in ref mode", opts: { secretInputMode: "ref" as const }, // pragma: allowlist secret expectKey: undefined, expectKeyRef: { source: "env", provider: "default", id: "MINIMAX_API_KEY", }, expectConfirmCalls: 0, }, ])("$name", async ({ opts, expectKey, expectKeyRef, expectConfirmCalls }) => { const { agentDir, result, text, confirm } = await runMiniMaxChoice({ authChoice: "minimax-api-key-cn", 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", mode: "api_key", }); expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe( "minimax-cn/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); if (expectKeyRef) { expect(parsed.profiles?.["minimax-cn:default"]?.keyRef).toEqual(expectKeyRef); } else { expect(parsed.profiles?.["minimax-cn:default"]?.keyRef).toBeUndefined(); } }); it("uses minimax-api-lightning default model", async () => { const { agentDir, result, text, confirm } = await runMiniMaxChoice({ authChoice: "minimax-api-lightning", opts: { tokenProvider: "minimax", token: "mm-lightning-token", }, }); expect(result).not.toBeNull(); expect(result?.config.auth?.profiles?.["minimax:default"]).toMatchObject({ provider: "minimax", mode: "api_key", }); expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe( "minimax/MiniMax-M2.5-highspeed", ); expect(text).not.toHaveBeenCalled(); expect(confirm).not.toHaveBeenCalled(); const parsed = await readAuthProfiles(agentDir); expect(parsed.profiles?.["minimax:default"]?.key).toBe("mm-lightning-token"); }); });