From bc3fbdbb2a4dbe0f253affbb8dc049ae99982d73 Mon Sep 17 00:00:00 2001 From: octo-patch <266937838+octo-patch@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:47:53 +0800 Subject: [PATCH 1/2] docs(minimax): recommend M3.1 Flash and verify request contracts --- README.md | 2 +- opencode-mem.example.jsonc | 12 +-- src/config.ts | 12 +-- tests/minimax-provider.test.ts | 132 +++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a0320075..716e0a42 100644 --- a/README.md +++ b/README.md @@ -482,7 +482,7 @@ Manual `memoryProvider` modes: - `openai-chat`: OpenAI Chat Completions compatible API with tool/function calling. This can work with compatible proxies such as LiteLLM only when the selected upstream model and proxy preserve tool calls. - `openai-responses`: OpenAI Responses API with function-call output. - `anthropic`: Anthropic Messages API with tool use. -- `minimax`: MiniMax Anthropic Messages-compatible endpoint. Set `memoryApiUrl` to the global endpoint (`https://api.minimax.io`) or the China endpoint (`https://api.minimaxi.com`); the `/anthropic/v1/messages` path and `x-api-key` header are applied automatically. Current models include `MiniMax-M3` (1,000,000-token context; adaptive or disabled thinking) and `MiniMax-M2.7` (204,800-token context; always-on thinking). `MiniMax-M3` supports adaptive thinking through `memoryExtraParams`. +- `minimax`: MiniMax Anthropic Messages-compatible endpoint. Set `memoryApiUrl` to the global endpoint (`https://api.minimax.io`) or the [China endpoint](https://platform.minimaxi.com/docs/api-reference/text-anthropic-api.md) (`https://api.minimax.cn`); the `/anthropic/v1/messages` path and `x-api-key` header are applied automatically. Use `MiniMax-M3.1-Flash` (recommended) or `MiniMax-M3`, both with a 1,000,000-token context. Flash always thinks; optionally set `memoryExtraParams` to `{ "output_config": { "effort": "max" } }` with `low`, `medium`, `high`, `xhigh`, or `max` (default). Flash rejects disabled thinking and effort `none`, and does not support `service_tier`. M3 thinking is off by default on this endpoint; enable it with `{ "thinking": { "type": "adaptive" } }`. Model IDs remain explicitly configured; existing custom or legacy IDs are passed through unchanged. See the [MiniMax compatibility reference](https://platform.minimax.io/docs/api-reference/text-anthropic-api.md). - `orcarouter`: OpenAI-compatible model gateway with namespaced model IDs. `memoryApiUrl` and `memoryModel` are optional — they default to `https://api.orcarouter.ai/v1` and `orcarouter/auto` (a routing alias that selects a capable model per request). If you set `memoryModel`, use a namespaced ID such as `openai/gpt-5.5` or `deepseek/deepseek-v4-flash`; OrcaRouter rejects bare model names. Example: ```jsonc "memoryProvider": "orcarouter", diff --git a/opencode-mem.example.jsonc b/opencode-mem.example.jsonc index 50f6fb9c..21e36f39 100644 --- a/opencode-mem.example.jsonc +++ b/opencode-mem.example.jsonc @@ -228,14 +228,14 @@ // MiniMax (Anthropic Messages-compatible endpoint, with session support): // "memoryProvider": "minimax" - // "memoryModel": "MiniMax-M3" // 1,000,000-token context - // // Alternative: "MiniMax-M2.7" // 204,800-token context; thinking always on + // "memoryModel": "MiniMax-M3.1-Flash" // 1,000,000-token context; thinking always on + // // Alternative: "MiniMax-M3" // 1,000,000-token context; thinking off by default // "memoryApiUrl": "https://api.minimax.io" // global endpoint // "memoryApiKey": "" - // // China endpoint: "memoryApiUrl": "https://api.minimaxi.com" - // // MiniMax-M3 supports adaptive or disabled thinking; MiniMax-M2.7 thinking is always on. - // // Optional adaptive thinking for MiniMax-M3: - // "memoryExtraParams": { "thinking": { "type": "adaptive" } } + // // China endpoint: "memoryApiUrl": "https://api.minimax.cn" + // // Flash effort: low | medium | high | xhigh | max (default). Do not disable thinking. + // "memoryExtraParams": { "output_config": { "effort": "max" } } + // // For MiniMax-M3, optionally use { "thinking": { "type": "adaptive" } } instead. // OrcaRouter (OpenAI-compatible gateway, namespaced model IDs, with session support): // "memoryProvider": "orcarouter" diff --git a/src/config.ts b/src/config.ts index ac9ac210..dd1a2f2e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -533,14 +533,14 @@ const CONFIG_TEMPLATE = `{ // MiniMax (Anthropic Messages-compatible endpoint, with session support): // "memoryProvider": "minimax" - // "memoryModel": "MiniMax-M3" // 1,000,000-token context - // // Alternative: "MiniMax-M2.7" // 204,800-token context; thinking always on + // "memoryModel": "MiniMax-M3.1-Flash" // 1,000,000-token context; thinking always on + // // Alternative: "MiniMax-M3" // 1,000,000-token context; thinking off by default // "memoryApiUrl": "https://api.minimax.io" // global endpoint // "memoryApiKey": "" - // // China endpoint: "memoryApiUrl": "https://api.minimaxi.com" - // // MiniMax-M3 supports adaptive or disabled thinking; MiniMax-M2.7 thinking is always on. - // // Optional adaptive thinking for MiniMax-M3: - // "memoryExtraParams": { "thinking": { "type": "adaptive" } } + // // China endpoint: "memoryApiUrl": "https://api.minimax.cn" + // // Flash effort: low | medium | high | xhigh | max (default). Do not disable thinking. + // "memoryExtraParams": { "output_config": { "effort": "max" } } + // // For MiniMax-M3, optionally use { "thinking": { "type": "adaptive" } } instead. // OrcaRouter (OpenAI-compatible gateway, namespaced model IDs, with session support): // "memoryProvider": "orcarouter" diff --git a/tests/minimax-provider.test.ts b/tests/minimax-provider.test.ts index b9287063..8bfb9b37 100644 --- a/tests/minimax-provider.test.ts +++ b/tests/minimax-provider.test.ts @@ -2,6 +2,8 @@ import { afterEach, describe, expect, it } from "bun:test"; import { MiniMaxProvider } from "../src/services/ai/providers/minimax.js"; import { AIProviderFactory } from "../src/services/ai/ai-provider-factory.js"; import type { ChatCompletionTool } from "../src/services/ai/tools/tool-schema.js"; +import { readFileSync } from "node:fs"; +import { buildMemoryProviderConfig } from "../src/services/ai/provider-config.js"; const toolSchema: ChatCompletionTool = { type: "function", @@ -178,6 +180,136 @@ describe("MiniMaxProvider", () => { expect(Array.isArray(capturedBody?.tools)).toBe(true); }); + for (const apiUrl of [ + "https://api.minimax.io", + "https://api.minimax.cn", + "https://api.minimaxi.com", + ]) { + for (const effort of [undefined, "low", "medium", "high", "xhigh", "max"]) { + it(`sends the recommended Flash configuration to ${apiUrl} with effort ${effort ?? "default"}`, async () => { + const template = readFileSync(new URL("../src/config.ts", import.meta.url), "utf8"); + const example = readFileSync( + new URL("../opencode-mem.example.jsonc", import.meta.url), + "utf8" + ); + const modelPattern = /\/\/ MiniMax \(Anthropic[\s\S]*?"memoryModel": "([^"]+)"/; + const memoryModel = template.match(modelPattern)?.[1]; + expect(memoryModel).toBe("MiniMax-M3.1-Flash"); + expect(example.match(modelPattern)?.[1]).toBe(memoryModel); + const config = buildMemoryProviderConfig({ + memoryProvider: "minimax", + memoryModel, + memoryApiUrl: apiUrl, + memoryApiKey: "fixture-only-key", + memoryExtraParams: effort ? { output_config: { effort } } : undefined, + }); + const provider = new MiniMaxProvider(config, new FakeSessionManager() as any); + let body: any; + let url: string | undefined; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + url = String(input); + body = JSON.parse(String(init?.body)); + return Response.json({ + content: [ + { + type: "tool_use", + id: "tool_flash", + name: "save_memories", + input: { memory: "Flash fact" }, + }, + ], + stop_reason: "tool_use", + }); + }) as typeof fetch; + const result = await provider.executeToolCall("system", "user", toolSchema, "session-id"); + expect(result.success).toBe(true); + expect(url).toBe(`${apiUrl}/anthropic/v1/messages`); + expect(body.model).toBe("MiniMax-M3.1-Flash"); + expect(body.output_config).toEqual(effort ? { effort } : undefined); + expect(body.thinking).toBeUndefined(); + expect(body.service_tier).toBeUndefined(); + expect(body.tools[0].name).toBe("save_memories"); + }); + } + } + + for (const model of ["MiniMax-M3", "MiniMax-M2.7", "custom-model"]) { + it(`preserves the explicitly configured model ${model}`, async () => { + let body: any; + globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { + body = JSON.parse(String(init?.body)); + return Response.json({ content: [], stop_reason: "max_tokens" }); + }) as typeof fetch; + const config = buildMemoryProviderConfig({ + memoryProvider: "minimax", + memoryModel: model, + memoryApiUrl: "https://custom.invalid", + memoryApiKey: "fixture-only-key", + }); + const provider = new MiniMaxProvider(config, new FakeSessionManager() as any); + await provider.executeToolCall("system", "user", toolSchema, "session-id"); + expect(body.model).toBe(model); + expect(body.thinking).toBeUndefined(); + expect(body.output_config).toBeUndefined(); + }); + } + + it("keeps explicit M3 disabled thinking unchanged", async () => { + let body: any; + globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { + body = JSON.parse(String(init?.body)); + return Response.json({ content: [], stop_reason: "max_tokens" }); + }) as typeof fetch; + const { provider } = makeProvider({ extraParams: { thinking: { type: "disabled" } } }); + await provider.executeToolCall("system", "user", toolSchema, "session-id"); + expect(body.model).toBe("MiniMax-M3"); + expect(body.thinking).toEqual({ type: "disabled" }); + expect(body.output_config).toBeUndefined(); + }); + + it("preserves complete Flash reasoning, tool results, and media history at the HTTP boundary", async () => { + const sessionManager = new FakeSessionManager(); + const media = [ + { type: "image", source: { type: "url", url: "https://example.invalid/image.png" } }, + { type: "video", source: { type: "url", url: "https://example.invalid/video.mp4" } }, + ]; + const assistant = [ + { type: "thinking", thinking: "Keep this reasoning", signature: "fixture-signature" }, + { type: "text", text: "Remembering" }, + { + type: "tool_use", + id: "previous-tool", + name: "save_memories", + input: { memory: "prior fact" }, + }, + ]; + const toolResult = [{ type: "tool_result", tool_use_id: "previous-tool", content: "saved" }]; + sessionManager.addMessage({ role: "user", contentBlocks: media }); + sessionManager.addMessage({ role: "assistant", contentBlocks: assistant }); + sessionManager.addMessage({ role: "user", contentBlocks: toolResult }); + const responseContent = [ + { type: "thinking", thinking: "New reasoning", signature: "new-signature" }, + { type: "tool_use", id: "new-tool", name: "save_memories", input: { memory: "new fact" } }, + ]; + const bodies: any[] = []; + globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { + bodies.push(JSON.parse(String(init?.body))); + return Response.json({ content: responseContent, stop_reason: "tool_use" }); + }) as typeof fetch; + const { provider } = makeProvider({ model: "MiniMax-M3.1-Flash" }, sessionManager); + expect( + (await provider.executeToolCall("system", "user", toolSchema, "session-id")).success + ).toBe(true); + expect(sessionManager.getMessages().at(-1).contentBlocks).toEqual(responseContent); + await provider.executeToolCall("system", "next user", toolSchema, "session-id"); + expect(bodies[0].messages.slice(0, 3)).toEqual([ + { role: "user", content: media }, + { role: "assistant", content: assistant }, + { role: "user", content: toolResult }, + ]); + expect(bodies[1].messages).toContainEqual({ role: "assistant", content: responseContent }); + }); + it("extracts tool input from a MiniMax Anthropic-format response", async () => { let capturedBody: Record | undefined; globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { From 78a9d27788b47272d26939ae31f82fcd2a3a775e Mon Sep 17 00:00:00 2001 From: EyJunge1 <149941075+EyJunge1@users.noreply.github.com> Date: Wed, 21 Oct 2026 02:16:53 +0200 Subject: [PATCH 2/2] docs(minimax): sync i18n and China endpoint guidance Align translated READMEs and provider comments with the M3.1 Flash recommendation, and cover the current api.minimax.cn host in endpoint tests. --- i18n/README.ar.md | 2 +- i18n/README.de.md | 2 +- i18n/README.nl.md | 2 +- i18n/README.tr.md | 2 +- i18n/README.zh.md | 2 +- src/services/ai/providers/minimax.ts | 16 +++++++++------- tests/minimax-provider.test.ts | 27 ++++++++++++++++----------- 7 files changed, 30 insertions(+), 23 deletions(-) diff --git a/i18n/README.ar.md b/i18n/README.ar.md index c071fbcc..ea2d0b43 100644 --- a/i18n/README.ar.md +++ b/i18n/README.ar.md @@ -469,7 +469,7 @@ memory({ mode: "import", inputPath: "./memories.json" }); - `openai-chat`: API متوافق مع OpenAI Chat Completions مع استدعاء أدوات/دوال. يمكن أن يعمل مع وكلاء متوافقين مثل LiteLLM فقط عندما يحافظ النموذج العلوي والوكيل المحددان على استدعاءات الأدوات. - `openai-responses`: OpenAI Responses API مع مخرجات استدعاء دوال. - `anthropic`: Anthropic Messages API مع استخدام الأدوات. -- `minimax`: نقطة نهاية MiniMax متوافقة مع Anthropic Messages. عيّن `memoryApiUrl` إلى النقطة العالمية (`https://api.minimax.io`) أو نقطة الصين (`https://api.minimaxi.com`)؛ يُطبَّق مسار `/anthropic/v1/messages` وترويسة `x-api-key` تلقائيًا. النماذج الحالية تشمل `MiniMax-M3` (سياق 1,000,000 رمز؛ تفكير تكيفي أو معطّل) و`MiniMax-M2.7` (سياق 204,800 رمز؛ تفكير دائم التشغيل). يدعم `MiniMax-M3` التفكير التكيفي عبر `memoryExtraParams`. +- `minimax`: نقطة نهاية MiniMax متوافقة مع Anthropic Messages. عيّن `memoryApiUrl` إلى النقطة العالمية (`https://api.minimax.io`) أو [نقطة الصين](https://platform.minimaxi.com/docs/api-reference/text-anthropic-api.md) (`https://api.minimax.cn`)؛ يُطبَّق مسار `/anthropic/v1/messages` وترويسة `x-api-key` تلقائيًا. استخدم `MiniMax-M3.1-Flash` (موصى به) أو `MiniMax-M3`، وكلاهما بسياق 1,000,000 رمز. Flash يفكر دائمًا؛ ويمكن اختياريًا تعيين `memoryExtraParams` إلى `{ "output_config": { "effort": "max" } }` بالقيم `low` أو `medium` أو `high` أو `xhigh` أو `max` (الافتراضي). يرفض Flash تعطيل التفكير وeffort `none`، ولا يدعم `service_tier`. تفكير M3 معطّل افتراضيًا على هذه النقطة؛ فعّله بـ `{ "thinking": { "type": "adaptive" } }`. تبقى معرّفات النماذج مُعدّة صراحةً؛ وتُمرَّر المعرّفات المخصصة أو القديمة دون تغيير. راجع [مرجع توافق MiniMax](https://platform.minimax.io/docs/api-reference/text-anthropic-api.md). - `orcarouter`: بوابة نماذج متوافقة مع OpenAI بمعرّفات نماذج ذات مساحة أسماء. `memoryApiUrl` و`memoryModel` اختياريان — الافتراضي `https://api.orcarouter.ai/v1` و`orcarouter/auto` (اسم مستعار للتوجيه يختار نموذجًا قادرًا لكل طلب). إذا عيّنت `memoryModel`، استخدم معرّفًا ذا مساحة أسماء مثل `openai/gpt-5.5` أو `deepseek/deepseek-v4-flash`؛ يرفض OrcaRouter أسماء النماذج العارية. مثال: ```jsonc "memoryProvider": "orcarouter", diff --git a/i18n/README.de.md b/i18n/README.de.md index e75e4994..025cc161 100644 --- a/i18n/README.de.md +++ b/i18n/README.de.md @@ -469,7 +469,7 @@ Manuelle `memoryProvider`-Modi: - `openai-chat`: OpenAI-Chat-Completions-kompatible API mit Tool-/Function-Calling. Kann mit kompatiblen Proxies wie LiteLLM nur funktionieren, wenn das gewählte Upstream-Modell und der Proxy Tool-Calls erhalten. - `openai-responses`: OpenAI Responses API mit Function-Call-Ausgabe. - `anthropic`: Anthropic Messages API mit Tool Use. -- `minimax`: MiniMax Anthropic-Messages-kompatibler Endpoint. `memoryApiUrl` auf den globalen Endpoint (`https://api.minimax.io`) oder den China-Endpoint (`https://api.minimaxi.com`) setzen; der Pfad `/anthropic/v1/messages` und der Header `x-api-key` werden automatisch angewendet. Aktuelle Modelle umfassen `MiniMax-M3` (1.000.000-Token-Kontext; adaptives oder deaktiviertes Thinking) und `MiniMax-M2.7` (204.800-Token-Kontext; Thinking immer an). `MiniMax-M3` unterstützt adaptives Thinking über `memoryExtraParams`. +- `minimax`: MiniMax Anthropic-Messages-kompatibler Endpoint. `memoryApiUrl` auf den globalen Endpoint (`https://api.minimax.io`) oder den [China-Endpoint](https://platform.minimaxi.com/docs/api-reference/text-anthropic-api.md) (`https://api.minimax.cn`) setzen; der Pfad `/anthropic/v1/messages` und der Header `x-api-key` werden automatisch angewendet. `MiniMax-M3.1-Flash` (empfohlen) oder `MiniMax-M3` verwenden, beide mit 1.000.000-Token-Kontext. Flash denkt immer; optional `memoryExtraParams` auf `{ "output_config": { "effort": "max" } }` setzen mit `low`, `medium`, `high`, `xhigh` oder `max` (Standard). Flash lehnt deaktiviertes Thinking und Effort `none` ab und unterstützt kein `service_tier`. M3-Thinking ist auf diesem Endpoint standardmäßig aus; aktivieren mit `{ "thinking": { "type": "adaptive" } }`. Modell-IDs bleiben explizit konfiguriert; vorhandene Custom- oder Legacy-IDs werden unverändert durchgereicht. Siehe die [MiniMax-Kompatibilitätsreferenz](https://platform.minimax.io/docs/api-reference/text-anthropic-api.md). - `orcarouter`: OpenAI-kompatibles Model-Gateway mit namenspaced Model-IDs. `memoryApiUrl` und `memoryModel` sind optional — sie defaulten auf `https://api.orcarouter.ai/v1` und `orcarouter/auto` (ein Routing-Alias, der pro Request ein fähiges Modell wählt). Wenn du `memoryModel` setzt, eine namenspaced ID wie `openai/gpt-5.5` oder `deepseek/deepseek-v4-flash` verwenden; OrcaRouter lehnt bare Modellnamen ab. Beispiel: ```jsonc "memoryProvider": "orcarouter", diff --git a/i18n/README.nl.md b/i18n/README.nl.md index 66372f98..0e55a2af 100644 --- a/i18n/README.nl.md +++ b/i18n/README.nl.md @@ -470,7 +470,7 @@ Handmatige `memoryProvider`-modi: - `openai-chat`: OpenAI Chat Completions-compatibele API met tool/function calling. Dit kan werken met compatibele proxies zoals LiteLLM alleen wanneer het geselecteerde upstream-model en de proxy tool calls behouden. - `openai-responses`: OpenAI Responses API met function-call-output. - `anthropic`: Anthropic Messages API met tool use. -- `minimax`: MiniMax Anthropic Messages-compatibel endpoint. Stel `memoryApiUrl` in op het globale endpoint (`https://api.minimax.io`) of het China-endpoint (`https://api.minimaxi.com`); het pad `/anthropic/v1/messages` en de header `x-api-key` worden automatisch toegepast. Huidige modellen zijn onder meer `MiniMax-M3` (1.000.000-token context; adaptief of uitgeschakeld thinking) en `MiniMax-M2.7` (204.800-token context; altijd-aan thinking). `MiniMax-M3` ondersteunt adaptief thinking via `memoryExtraParams`. +- `minimax`: MiniMax Anthropic Messages-compatibel endpoint. Stel `memoryApiUrl` in op het globale endpoint (`https://api.minimax.io`) of het [China-endpoint](https://platform.minimaxi.com/docs/api-reference/text-anthropic-api.md) (`https://api.minimax.cn`); het pad `/anthropic/v1/messages` en de header `x-api-key` worden automatisch toegepast. Gebruik `MiniMax-M3.1-Flash` (aanbevolen) of `MiniMax-M3`, beide met een 1.000.000-token context. Flash denkt altijd; stel optioneel `memoryExtraParams` in op `{ "output_config": { "effort": "max" } }` met `low`, `medium`, `high`, `xhigh` of `max` (standaard). Flash weigert uitgeschakeld thinking en effort `none`, en ondersteunt geen `service_tier`. M3-thinking staat op dit endpoint standaard uit; zet het aan met `{ "thinking": { "type": "adaptive" } }`. Model-ID’s blijven expliciet geconfigureerd; bestaande custom of legacy-ID’s worden ongewijzigd doorgestuurd. Zie de [MiniMax-compatibiliteitsreferentie](https://platform.minimax.io/docs/api-reference/text-anthropic-api.md). - `orcarouter`: OpenAI-compatibele modelgateway met namespaced model-ID’s. `memoryApiUrl` en `memoryModel` zijn optioneel — ze defaulten naar `https://api.orcarouter.ai/v1` en `orcarouter/auto` (een routingalias die per verzoek een capabel model kiest). Als je `memoryModel` instelt, gebruik een namespaced ID zoals `openai/gpt-5.5` of `deepseek/deepseek-v4-flash`; OrcaRouter weigert bare modelnamen. Voorbeeld: ```jsonc "memoryProvider": "orcarouter", diff --git a/i18n/README.tr.md b/i18n/README.tr.md index 82db1ba4..018f6d9d 100644 --- a/i18n/README.tr.md +++ b/i18n/README.tr.md @@ -471,7 +471,7 @@ Manuel `memoryProvider` modları: - `openai-chat`: Araç/fonksiyon çağrısıyla OpenAI Chat Completions uyumlu API. Seçilen üst akış modeli ve proxy araç çağrılarını koruduğunda LiteLLM gibi uyumlu proxy’lerle çalışabilir. - `openai-responses`: Fonksiyon çağrısı çıktısıyla OpenAI Responses API. - `anthropic`: Araç kullanımıyla Anthropic Messages API. -- `minimax`: MiniMax Anthropic Messages uyumlu uç noktası. `memoryApiUrl`’yi küresel uç noktaya (`https://api.minimax.io`) veya Çin uç noktasına (`https://api.minimaxi.com`) ayarlayın; `/anthropic/v1/messages` yolu ve `x-api-key` başlığı otomatik uygulanır. Güncel modeller arasında `MiniMax-M3` (1.000.000 jeton bağlam; uyarlanabilir veya devre dışı düşünme) ve `MiniMax-M2.7` (204.800 jeton bağlam; her zaman açık düşünme) vardır. `MiniMax-M3`, `memoryExtraParams` üzerinden uyarlanabilir düşünmeyi destekler. +- `minimax`: MiniMax Anthropic Messages uyumlu uç noktası. `memoryApiUrl`’yi küresel uç noktaya (`https://api.minimax.io`) veya [Çin uç noktasına](https://platform.minimaxi.com/docs/api-reference/text-anthropic-api.md) (`https://api.minimax.cn`) ayarlayın; `/anthropic/v1/messages` yolu ve `x-api-key` başlığı otomatik uygulanır. `MiniMax-M3.1-Flash` (önerilen) veya `MiniMax-M3` kullanın; her ikisi de 1.000.000 jeton bağlamına sahiptir. Flash her zaman düşünür; isteğe bağlı olarak `memoryExtraParams`’ı `{ "output_config": { "effort": "max" } }` olarak `low`, `medium`, `high`, `xhigh` veya `max` (varsayılan) ile ayarlayın. Flash, devre dışı düşünmeyi ve effort `none` değerini reddeder ve `service_tier` desteklemez. Bu uç noktada M3 düşünmesi varsayılan olarak kapalıdır; `{ "thinking": { "type": "adaptive" } }` ile etkinleştirin. Model kimlikleri açıkça yapılandırılmaya devam eder; mevcut özel veya eski kimlikler değiştirilmeden iletilir. Bkz. [MiniMax uyumluluk referansı](https://platform.minimax.io/docs/api-reference/text-anthropic-api.md). - `orcarouter`: Ad alanlı model kimlikleriyle OpenAI uyumlu model ağ geçidi. `memoryApiUrl` ve `memoryModel` isteğe bağlıdır — varsayılanları `https://api.orcarouter.ai/v1` ve `orcarouter/auto`’dur (istek başına yetenekli bir model seçen bir yönlendirme takma adı). `memoryModel` ayarlarsanız `openai/gpt-5.5` veya `deepseek/deepseek-v4-flash` gibi ad alanlı bir kimlik kullanın; OrcaRouter çıplak model adlarını reddeder. Örnek: ```jsonc "memoryProvider": "orcarouter", diff --git a/i18n/README.zh.md b/i18n/README.zh.md index d8da38fe..b6c92451 100644 --- a/i18n/README.zh.md +++ b/i18n/README.zh.md @@ -466,7 +466,7 @@ memory({ mode: "import", inputPath: "./memories.json" }); - `openai-chat`:兼容 OpenAI Chat Completions、带工具/函数调用的 API。仅当所选上游模型与代理保留工具调用时,这可与兼容代理(如 LiteLLM)一起工作。 - `openai-responses`:带函数调用输出的 OpenAI Responses API。 - `anthropic`:带工具使用的 Anthropic Messages API。 -- `minimax`:MiniMax Anthropic Messages 兼容端点。将 `memoryApiUrl` 设置为全球端点(`https://api.minimax.io`)或中国端点(`https://api.minimaxi.com`);`/anthropic/v1/messages` 路径与 `x-api-key` 标头会自动应用。当前模型包括 `MiniMax-M3`(1,000,000-token 上下文;自适应或禁用思考)与 `MiniMax-M2.7`(204,800-token 上下文;始终开启思考)。`MiniMax-M3` 通过 `memoryExtraParams` 支持自适应思考。 +- `minimax`:MiniMax Anthropic Messages 兼容端点。将 `memoryApiUrl` 设置为全球端点(`https://api.minimax.io`)或[中国端点](https://platform.minimaxi.com/docs/api-reference/text-anthropic-api.md)(`https://api.minimax.cn`);`/anthropic/v1/messages` 路径与 `x-api-key` 标头会自动应用。使用 `MiniMax-M3.1-Flash`(推荐)或 `MiniMax-M3`,二者均为 1,000,000-token 上下文。Flash 始终开启思考;可选将 `memoryExtraParams` 设为 `{ "output_config": { "effort": "max" } }`,取值为 `low`、`medium`、`high`、`xhigh` 或 `max`(默认)。Flash 会拒绝禁用思考与 effort `none`,且不支持 `service_tier`。在此端点上 M3 思考默认关闭;可通过 `{ "thinking": { "type": "adaptive" } }` 启用。模型 ID 仍需显式配置;已有自定义或旧版 ID 会原样透传。参见 [MiniMax 兼容性参考](https://platform.minimax.io/docs/api-reference/text-anthropic-api.md)。 - `orcarouter`:带命名空间模型 ID 的 OpenAI 兼容模型网关。`memoryApiUrl` 与 `memoryModel` 可选 — 它们默认为 `https://api.orcarouter.ai/v1` 与 `orcarouter/auto`(按请求选择有能力模型的路由别名)。若设置 `memoryModel`,请使用命名空间 ID,例如 `openai/gpt-5.5` 或 `deepseek/deepseek-v4-flash`;OrcaRouter 拒绝裸模型名。示例: ```jsonc "memoryProvider": "orcarouter", diff --git a/src/services/ai/providers/minimax.ts b/src/services/ai/providers/minimax.ts index afe5711d..2b66cea0 100644 --- a/src/services/ai/providers/minimax.ts +++ b/src/services/ai/providers/minimax.ts @@ -7,16 +7,18 @@ import type { AIProviderType } from "../session/session-types.js"; * MiniMax provider. * * MiniMax exposes an Anthropic Messages-compatible endpoint for its text - * models. The global endpoint (https://api.minimax.io) and the China endpoint - * (https://api.minimaxi.com) both expose the same `/anthropic/v1/messages` - * path and authenticate with the `x-api-key` header. This provider reuses the - * Anthropic Messages request/response handling and only overrides the resolved - * request endpoint URL and the session provider tag, so MiniMax is - * distinguishable from Anthropic in the session store and diagnostics. + * models. The global endpoint (https://api.minimax.io) and the current China + * endpoint (https://api.minimax.cn) both expose the same + * `/anthropic/v1/messages` path and authenticate with the `x-api-key` header. + * Configured legacy China hosts such as https://api.minimaxi.com are still + * resolved without remapping. This provider reuses the Anthropic Messages + * request/response handling and only overrides the resolved request endpoint + * URL and the session provider tag, so MiniMax is distinguishable from + * Anthropic in the session store and diagnostics. * * Users configure the base URL as `memoryApiUrl`: * - global endpoint: "https://api.minimax.io" - * - China endpoint: "https://api.minimaxi.com" + * - China endpoint: "https://api.minimax.cn" */ export class MiniMaxProvider extends AnthropicMessagesProvider { constructor(config: ProviderConfig, aiSessionManager: AISessionManager) { diff --git a/tests/minimax-provider.test.ts b/tests/minimax-provider.test.ts index 8bfb9b37..32a487aa 100644 --- a/tests/minimax-provider.test.ts +++ b/tests/minimax-provider.test.ts @@ -83,7 +83,12 @@ describe("MiniMaxProvider", () => { expect(provider.resolveEndpoint()).toBe("https://api.minimax.io/anthropic/v1/messages"); }); - it("resolves the China endpoint at api.minimaxi.com", () => { + it("resolves the current China endpoint at api.minimax.cn", () => { + const { provider } = makeProvider({ apiUrl: "https://api.minimax.cn" }); + expect(provider.resolveEndpoint()).toBe("https://api.minimax.cn/anthropic/v1/messages"); + }); + + it("resolves a legacy China endpoint at api.minimaxi.com", () => { const { provider } = makeProvider({ apiUrl: "https://api.minimaxi.com" }); expect(provider.resolveEndpoint()).toBe("https://api.minimaxi.com/anthropic/v1/messages"); }); @@ -180,6 +185,15 @@ describe("MiniMaxProvider", () => { expect(Array.isArray(capturedBody?.tools)).toBe(true); }); + it("keeps the recommended Flash model aligned in config templates", () => { + const template = readFileSync(new URL("../src/config.ts", import.meta.url), "utf8"); + const example = readFileSync(new URL("../opencode-mem.example.jsonc", import.meta.url), "utf8"); + const modelPattern = /\/\/ MiniMax \(Anthropic[\s\S]*?"memoryModel": "([^"]+)"/; + const memoryModel = template.match(modelPattern)?.[1]; + expect(memoryModel).toBe("MiniMax-M3.1-Flash"); + expect(example.match(modelPattern)?.[1]).toBe(memoryModel); + }); + for (const apiUrl of [ "https://api.minimax.io", "https://api.minimax.cn", @@ -187,18 +201,9 @@ describe("MiniMaxProvider", () => { ]) { for (const effort of [undefined, "low", "medium", "high", "xhigh", "max"]) { it(`sends the recommended Flash configuration to ${apiUrl} with effort ${effort ?? "default"}`, async () => { - const template = readFileSync(new URL("../src/config.ts", import.meta.url), "utf8"); - const example = readFileSync( - new URL("../opencode-mem.example.jsonc", import.meta.url), - "utf8" - ); - const modelPattern = /\/\/ MiniMax \(Anthropic[\s\S]*?"memoryModel": "([^"]+)"/; - const memoryModel = template.match(modelPattern)?.[1]; - expect(memoryModel).toBe("MiniMax-M3.1-Flash"); - expect(example.match(modelPattern)?.[1]).toBe(memoryModel); const config = buildMemoryProviderConfig({ memoryProvider: "minimax", - memoryModel, + memoryModel: "MiniMax-M3.1-Flash", memoryApiUrl: apiUrl, memoryApiKey: "fixture-only-key", memoryExtraParams: effort ? { output_config: { effort } } : undefined,