diff --git a/.env.example b/.env.example index 77ca0f3a3..e8aa71633 100644 --- a/.env.example +++ b/.env.example @@ -41,7 +41,8 @@ # OPENROUTER_MODEL=anthropic/claude-sonnet-4-20250514 # MINIMAX_API_KEY=... -# MINIMAX_MODEL=MiniMax-M2.7 +# MINIMAX_MODEL=MiniMax-M3 +# MINIMAX_BASE_URL=https://api.minimax.io/anthropic # MAX_TOKENS=4096 # Cap LLM completion tokens for compression / summarise calls diff --git a/src/cli/onboarding.ts b/src/cli/onboarding.ts index 6d0493554..926cdbea9 100644 --- a/src/cli/onboarding.ts +++ b/src/cli/onboarding.ts @@ -53,7 +53,7 @@ const PROVIDERS: { value: string; label: string; envKey: string | null }[] = [ { value: "openai", label: "OpenAI — gpt", envKey: "OPENAI_API_KEY" }, { value: "gemini", label: "Google — gemini", envKey: "GEMINI_API_KEY" }, { value: "openrouter", label: "OpenRouter — multi-model", envKey: "OPENROUTER_API_KEY" }, - { value: "minimax", label: "MiniMax — minimax-m1", envKey: "MINIMAX_API_KEY" }, + { value: "minimax", label: "MiniMax — MiniMax-M3", envKey: "MINIMAX_API_KEY" }, { value: "skip", label: "Skip — BM25-only mode (no LLM key)", envKey: null }, ]; diff --git a/src/config.ts b/src/config.ts index 3348ac226..b9f3d2d2d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -67,7 +67,7 @@ function detectProvider(env: Record): ProviderConfig { if (hasRealValue(env["MINIMAX_API_KEY"])) { return { provider: "minimax", - model: env["MINIMAX_MODEL"] || "MiniMax-M2.7", + model: env["MINIMAX_MODEL"] || "MiniMax-M3", maxTokens, }; } diff --git a/src/providers/index.ts b/src/providers/index.ts index 0ec3feba0..35b2f3547 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -45,7 +45,7 @@ function defaultModelFor(providerType: ProviderConfig["provider"]): string { getEnvVar("OPENROUTER_MODEL") || "anthropic/claude-sonnet-4-20250514" ); case "minimax": - return getEnvVar("MINIMAX_MODEL") || "MiniMax-M2.7"; + return getEnvVar("MINIMAX_MODEL") || "MiniMax-M3"; case "agent-sdk": return "claude-sonnet-4-20250514"; case "noop": diff --git a/src/providers/minimax.ts b/src/providers/minimax.ts index 72fc9ec90..19c4ee021 100644 --- a/src/providers/minimax.ts +++ b/src/providers/minimax.ts @@ -10,11 +10,11 @@ import { fetchWithTimeout } from './_fetch.js' * * Required env vars (loaded from ~/.agentmemory/.env or process.env): * MINIMAX_API_KEY — your MiniMax API key - * MINIMAX_MODEL — model name (default: MiniMax-M2.7) - * MAX_TOKENS — max output tokens (default: 800; MiniMax-M2.7 needs ≤800) + * MINIMAX_MODEL — model name (default: MiniMax-M3) + * MAX_TOKENS — max output tokens (default: 4096) * * Optional: - * MINIMAX_BASE_URL — base URL without path (default: https://api.minimax.io/anthropic) + * MINIMAX_BASE_URL — Anthropic-compatible base URL (default: https://api.minimax.io/anthropic) */ export class MinimaxProvider implements MemoryProvider { name = 'minimax' @@ -31,6 +31,10 @@ export class MinimaxProvider implements MemoryProvider { getEnvVar('MINIMAX_BASE_URL') || 'https://api.minimax.io/anthropic' } + private messagesUrl(): string { + return `${this.baseUrl.replace(/\/+$/, '')}/v1/messages` + } + async compress(systemPrompt: string, userPrompt: string): Promise { return this.call(systemPrompt, userPrompt) } @@ -40,7 +44,7 @@ export class MinimaxProvider implements MemoryProvider { } private async call(systemPrompt: string, userPrompt: string): Promise { - const url = `${this.baseUrl}/v1/messages` + const url = this.messagesUrl() const response = await fetchWithTimeout(url, { method: 'POST', headers: { diff --git a/test/fallback-model-resolution.test.ts b/test/fallback-model-resolution.test.ts index 91a821161..79c731a48 100644 --- a/test/fallback-model-resolution.test.ts +++ b/test/fallback-model-resolution.test.ts @@ -155,7 +155,7 @@ describe("Fallback provider model resolution (#778)", () => { const openai = captured.find((c) => c.provider === "openai"); const minimax = captured.find((c) => c.provider === "minimax"); expect(openai?.model).toBe("gpt-5"); - expect(minimax?.model).toBe("MiniMax-M2.7"); + expect(minimax?.model).toBe("MiniMax-M3"); // Neither inherits the Anthropic model name. expect(openai?.model).not.toBe("claude-sonnet-4-20250514"); expect(minimax?.model).not.toBe("claude-sonnet-4-20250514"); diff --git a/test/fetch-timeout.test.ts b/test/fetch-timeout.test.ts index 5b2cd7c9c..7e9536de6 100644 --- a/test/fetch-timeout.test.ts +++ b/test/fetch-timeout.test.ts @@ -91,7 +91,7 @@ describe("Provider hang regression — MinimaxProvider", () => { }); it("compress() aborts after timeout when upstream hangs", async () => { - const provider = new MinimaxProvider("test-key", "MiniMax-M2.7", 800); + const provider = new MinimaxProvider("test-key", "MiniMax-M3", 800); await expect(provider.compress("system", "user")).rejects.toThrow(); }); }); diff --git a/test/minimax-provider.test.ts b/test/minimax-provider.test.ts index 4167d4b37..a11bd9794 100644 --- a/test/minimax-provider.test.ts +++ b/test/minimax-provider.test.ts @@ -12,17 +12,25 @@ describe("MinimaxProvider — base URL resolution (#285)", () => { } }); - it("defaults to https://api.minimax.io/anthropic (not the legacy minimaxi.com host)", () => { + it("defaults to MiniMax's Anthropic-compatible base URL", () => { delete process.env["MINIMAX_BASE_URL"]; - const provider = new MinimaxProvider("test-key", "MiniMax-M2.7", 800); + const provider = new MinimaxProvider("test-key", "MiniMax-M3", 800); expect((provider as unknown as { baseUrl: string }).baseUrl).toBe( "https://api.minimax.io/anthropic", ); }); + it("appends /v1/messages to MINIMAX_BASE_URL", () => { + process.env["MINIMAX_BASE_URL"] = "https://custom.example.com/anthropic/"; + const provider = new MinimaxProvider("test-key", "MiniMax-M3", 800); + expect((provider as unknown as { messagesUrl: () => string }).messagesUrl()).toBe( + "https://custom.example.com/anthropic/v1/messages", + ); + }); + it("honors MINIMAX_BASE_URL via getEnvVar (merged ~/.agentmemory/.env + process.env)", () => { process.env["MINIMAX_BASE_URL"] = "https://custom.example.com/anthropic"; - const provider = new MinimaxProvider("test-key", "MiniMax-M2.7", 800); + const provider = new MinimaxProvider("test-key", "MiniMax-M3", 800); expect((provider as unknown as { baseUrl: string }).baseUrl).toBe( "https://custom.example.com/anthropic", );