From 6021e9595374d4b62d502e7e0d7cab49e4f4e392 Mon Sep 17 00:00:00 2001 From: octo-patch <266937838+octo-patch@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:24:18 +0800 Subject: [PATCH 1/2] Refresh MiniMax Flash model metadata --- scripts/model-metadata.source.json | 30 ++++++++++++++----- src/codex/catalog/model-hints.ts | 8 ++--- src/generated/model-metadata.ts | 2 +- src/providers/registry/entries-extended.ts | 16 +++++----- src/providers/registry/model-seeds.ts | 19 ++++++------ src/providers/stale-model-roster-migration.ts | 10 +++---- .../minimax-combo-image-input.test.ts | 6 ++-- .../providers/minimax-reasoning-split.test.ts | 4 +-- .../model-roster-seed-repair.test.ts | 2 +- .../provider-registry-parity.test.ts | 14 ++++----- 10 files changed, 62 insertions(+), 49 deletions(-) diff --git a/scripts/model-metadata.source.json b/scripts/model-metadata.source.json index 4c075688b60..9e6b6adc015 100644 --- a/scripts/model-metadata.source.json +++ b/scripts/model-metadata.source.json @@ -42160,9 +42160,9 @@ "maxLevel": "xhigh" } }, - "MiniMax-M3.1-Flash-Preview": { - "id": "MiniMax-M3.1-Flash-Preview", - "name": "MiniMax-M3.1-Flash-Preview", + "MiniMax-M3.1-Flash": { + "id": "MiniMax-M3.1-Flash", + "name": "MiniMax-M3.1-Flash", "api": "anthropic-messages", "provider": "minimax", "baseUrl": "https://api.minimax.io/anthropic", @@ -42172,7 +42172,14 @@ "image", "video" ], - "contextWindow": 1000000 + "contextWindow": 1000000, + "maxTokens": 524288, + "cost": { + "input": 0.15, + "output": 0.6, + "cacheRead": 0.015, + "cacheWrite": 0 + } } }, "minimax-cn": { @@ -42394,9 +42401,9 @@ "maxLevel": "xhigh" } }, - "MiniMax-M3.1-Flash-Preview": { - "id": "MiniMax-M3.1-Flash-Preview", - "name": "MiniMax-M3.1-Flash-Preview", + "MiniMax-M3.1-Flash": { + "id": "MiniMax-M3.1-Flash", + "name": "MiniMax-M3.1-Flash", "api": "anthropic-messages", "provider": "minimax-cn", "baseUrl": "https://api.minimaxi.com/anthropic", @@ -42406,7 +42413,14 @@ "image", "video" ], - "contextWindow": 1000000 + "contextWindow": 1000000, + "maxTokens": 524288, + "cost": { + "input": 0.15, + "output": 0.6, + "cacheRead": 0.015, + "cacheWrite": 0 + } } }, "minimax-code": { diff --git a/src/codex/catalog/model-hints.ts b/src/codex/catalog/model-hints.ts index 6d9a13d060f..67d515228c0 100644 --- a/src/codex/catalog/model-hints.ts +++ b/src/codex/catalog/model-hints.ts @@ -468,13 +468,13 @@ export const CALLABLE_CONFIGURED_COMPATIBILITY_MODELS: Readonly = { "cerebras": [["gemma-4-31b",131072,40960,"text,image",1,null,0.99,1.49,0,0],["gpt-oss-120b",131072,40960,"text",1,null,0.35,0.75,0,0],["llama3.1-8b",32000,8000,"text",0,null,0.1,0.1,0,0],["qwen-3-235b-a22b-instruct-2507",131000,32000,"text",0,null,0.6,1.2,0,0],["qwen-3-coder-480b",131072,32768,"text",0,null,0,0,0,0],["zai-glm-4.6",131072,32768,"text",0,null,0,0,0,0],["zai-glm-4.7",131072,40960,"text",1,null,2.25,2.75,2.25,0]], "deepseek": [["deepseek-v4-flash",1048576,384000,"text",1,null,0.14,0.28,0.0028,0],["deepseek-v4-pro",1048576,384000,"text",1,null,0.435,0.87,0.003625,0]], "google": [["deep-research-max-preview-04-2026",131072,65536,"text,image",1,null,2,12,0.2,0],["deep-research-preview-04-2026",131072,65536,"text,image",1,null,2,12,0.2,0],["gemini-1.5-flash",1000000,8192,"text,image",0,null,0.075,0.3,0.01875,0],["gemini-1.5-flash-8b",1000000,8192,"text,image",0,null,0.0375,0.15,0.01,0],["gemini-1.5-pro",1000000,8192,"text,image",0,null,1.25,5,0.3125,0],["gemini-2.0-flash",1048576,8192,"text,image",0,null,0.1,0.4,0.025,0],["gemini-2.0-flash-lite",1048576,8192,"text,image",0,null,0.075,0.3,0,0],["gemini-2.5-computer-use-preview-10-2025",131072,65536,"text,image",1,null,1.25,10,0,0],["gemini-2.5-flash",1048576,65536,"text,image",1,null,0.3,2.5,0.03,0],["gemini-2.5-flash-lite",1048576,65536,"text,image",1,null,0.1,0.4,0.01,0],["gemini-2.5-flash-lite-preview-06-17",1048576,65536,"text,image",1,null,0.1,0.4,0.025,0],["gemini-2.5-flash-lite-preview-09-2025",1048576,65536,"text,image",1,null,0.1,0.4,0.025,0],["gemini-2.5-flash-preview-04-17",1048576,65536,"text,image",1,null,0.15,0.6,0.0375,0],["gemini-2.5-flash-preview-05-20",1048576,65536,"text,image",1,null,0.15,0.6,0.0375,0],["gemini-2.5-flash-preview-09-2025",1048576,65536,"text,image",1,null,0.3,2.5,0.075,0],["gemini-2.5-pro",1048576,65536,"text,image",1,null,1.25,10,0.125,0],["gemini-2.5-pro-preview-05-06",1048576,65536,"text,image",1,null,1.25,10,0.31,0],["gemini-2.5-pro-preview-06-05",1048576,65536,"text,image",1,null,1.25,10,0.31,0],["gemini-3-flash-preview",1048576,65536,"text,image",1,null,0.5,3,0.05,0],["gemini-3-pro-preview",1048576,65536,"text,image",1,null,2,12,0.2,0],["gemini-3.1-flash-lite",1048576,65536,"text,image",1,null,0.25,1.5,0.025,0],["gemini-3.1-flash-lite-image",65536,65536,"text,image",1,null,0.25,30,0,0],["gemini-3.1-flash-lite-preview",1048576,65536,"text,image",1,null,0.25,1.5,0.025,0],["gemini-3.1-flash-live-preview",131072,65536,"text,image",1,null,0.75,4.5,0,0],["gemini-3.1-pro-preview",1048576,65536,"text,image",1,null,2,12,0.2,0],["gemini-3.1-pro-preview-customtools",1048576,65536,"text,image",1,null,2,12,0.2,0],["gemini-3.5-flash",1048576,65536,"text,image",1,null,1.5,9,0.15,0],["gemini-3.5-flash-lite",1048576,65536,"text,image",1,null,0.3,2.5,0.03,0],["gemini-3.6-flash",1048576,65536,"text,image",1,null,1.5,7.5,0.15,0],["gemini-3.7-flash",1048576,65536,"text,image",1],["gemini-3.8-flash",1048576,65536,"text,image",1],["gemini-4-argon",1048576,65536,"text,image",1],["gemini-flash-latest",1048576,65536,"text,image",1,null,1.5,9,0.15,0],["gemini-flash-lite-latest",1048576,65536,"text,image",1,null,0.25,1.5,0.025,0],["gemini-live-2.5-flash",128000,8000,"text,image",1,null,0.5,2,0,0],["gemini-live-2.5-flash-preview-native-audio",131072,65536,"text",1,null,0.5,2,0,0],["gemini-robotics-er-1.6-preview",131072,65536,"text,image",1,null,1,5,0,0],["gemma-3-27b-it",131072,8192,"text,image",0,null,0,0,0,0],["gemma-4-26b",256000,8192,"text,image",1,null,0,0,0,0],["gemma-4-26b-a4b-it",262144,32768,"text,image",1,null,0,0,0,0],["gemma-4-26b-it",256000,8192,"text,image",1,null,0,0,0,0],["gemma-4-31b",256000,8192,"text,image",1,null,0,0,0,0],["gemma-4-31b-it",262144,32768,"text,image",1,null,0,0,0,0],["gemma-4-E2B-it",131072,8192,"text,image",1,null,0,0,0,0],["gemma-4-E4B-it",131072,8192,"text,image",1,null,0,0,0,0]], - "minimax": [["MiniMax-M2",196608,128000,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.1",204800,131072,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.5",204800,131072,"text",1,null,0.3,1.2,0.03,0.375],["MiniMax-M2.5-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["MiniMax-M2.5-lightning",204800,32000,"text",1,null,0.3,2.4,0,0],["MiniMax-M2.7",204800,131072,"text",1,null,0.3,1.2,0.06,0.375],["MiniMax-M2.7-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["minimax-m3",512000,128000,"text,image",1,null,0.6,2.4,0.12,0],["MiniMax-M3",1000000,128000,"text,image,video",1,null,0.3,1.2,0.06,0],["MiniMax-M3.1-Flash-Preview",1000000,null,"text,image,video",1]], + "minimax": [["MiniMax-M2",196608,128000,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.1",204800,131072,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.5",204800,131072,"text",1,null,0.3,1.2,0.03,0.375],["MiniMax-M2.5-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["MiniMax-M2.5-lightning",204800,32000,"text",1,null,0.3,2.4,0,0],["MiniMax-M2.7",204800,131072,"text",1,null,0.3,1.2,0.06,0.375],["MiniMax-M2.7-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["minimax-m3",512000,128000,"text,image",1,null,0.6,2.4,0.12,0],["MiniMax-M3",1000000,128000,"text,image,video",1,null,0.3,1.2,0.06,0],["MiniMax-M3.1-Flash",1000000,524288,"text,image,video",1,null,0.15,0.6,0.015,0]], "mistral": [["codestral-latest",256000,4096,"text",0,null,0.3,0.9,0,0],["devstral-2512",262144,262144,"text",0,null,0.4,2,0,0],["devstral-latest",262144,262144,"text",0,null,0.4,2,0,0],["devstral-medium-2507",128000,128000,"text",0,null,0.4,2,0,0],["devstral-medium-latest",262144,262144,"text",0,null,0.4,2,0,0],["devstral-small-2505",128000,128000,"text",0,null,0.1,0.3,0,0],["devstral-small-2507",128000,128000,"text",0,null,0.1,0.3,0,0],["labs-devstral-small-2512",256000,256000,"text,image",0,null,0,0,0,0],["magistral-medium-latest",128000,16384,"text",1,null,2,5,0,0],["magistral-small",128000,128000,"text",1,null,0.5,1.5,0,0],["ministral-3b-latest",128000,128000,"text",0,null,0.04,0.04,0,0],["ministral-8b-latest",128000,128000,"text",0,null,0.1,0.1,0,0],["mistral-large-2411",131072,16384,"text",0,null,2,6,0,0],["mistral-large-2512",262144,262144,"text,image",0,null,0.5,1.5,0,0],["mistral-large-latest",262144,262144,"text,image",0,null,0.5,1.5,0,0],["mistral-medium-2505",131072,131072,"text,image",0,null,0.4,2,0,0],["mistral-medium-2508",262144,262144,"text,image",0,null,0.4,2,0,0],["mistral-medium-2604",262144,262144,"text,image",1,null,1.5,7.5,0,0],["mistral-medium-latest",262144,262144,"text,image",1,null,1.5,7.5,0,0],["mistral-nemo",128000,128000,"text",0,null,0.15,0.15,0,0],["mistral-small-2506",128000,16384,"text,image",0,null,0.1,0.3,0,0],["mistral-small-2603",256000,256000,"text,image",1,null,0.15,0.6,0,0],["mistral-small-latest",256000,256000,"text,image",1,null,0.15,0.6,0,0],["open-mistral-7b",8000,8000,"text",0,null,0.25,0.25,0,0],["open-mistral-nemo",128000,128000,"text",0,null,0.15,0.15,0,0],["open-mixtral-8x22b",64000,64000,"text",0,null,2,6,0,0],["open-mixtral-8x7b",32000,32000,"text",0,null,0.7,0.7,0,0],["pixtral-12b",128000,128000,"text,image",0,null,0.15,0.15,0,0],["pixtral-large-latest",128000,128000,"text,image",0,null,2,6,0,0]], "moonshot": [["kimi-k2.5",262144,65536,"text,image",1,null,0,0,0,0]], "openai": [["codex-mini-latest",200000,100000,"text",1,null,1.5,6,0.375,0],["gpt-4",8192,8192,"text",0,null,30,60,0,0],["gpt-4-turbo",128000,4096,"text,image",0,null,10,30,0,0],["gpt-4.1",1047576,32768,"text,image",0,null,2,8,0.5,0],["gpt-4.1-mini",1047576,32768,"text,image",0,null,0.4,1.6,0.1,0],["gpt-4.1-nano",1047576,32768,"text,image",0,null,0.1,0.4,0.025,0],["gpt-4o",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-2024-05-13",128000,4096,"text,image",0,null,5,15,0,0],["gpt-4o-2024-08-06",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-2024-11-20",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-mini",128000,16384,"text,image",0,null,0.15,0.6,0.075,0],["gpt-5",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-chat-latest",128000,16384,"text,image",0,null,1.25,10,0.125,0],["gpt-5-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-mini",400000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5-nano",400000,128000,"text,image",1,null,0.05,0.4,0.005,0],["gpt-5-pro",400000,272000,"text,image",1,null,15,120,0,0],["gpt-5.1",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-chat-latest",128000,16384,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-max",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-mini",272000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5.2",400000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-chat-latest",128000,16384,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-pro",400000,128000,"text,image",1,null,21,168,0,0],["gpt-5.3-chat-latest",128000,16384,"text,image",0,null,1.75,14,0.175,0],["gpt-5.3-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.3-codex-spark",128000,32000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.4",1050000,128000,"text,image",1,null,2.5,15,0.25,0],["gpt-5.4-mini",400000,128000,"text,image",1,null,0.75,4.5,0.075,0],["gpt-5.4-nano",400000,128000,"text,image",1,null,0.2,1.25,0.02,0],["gpt-5.4-pro",1050000,128000,"text,image",1,null,30,180,0,0],["gpt-5.5",1050000,128000,"text,image",1,null,5,30,0.5,0],["gpt-5.5-pro",1050000,128000,"text,image",1,null,30,180,0,0],["gpt-5.6",1050000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-luna",1050000,128000,"text,image",1,null,0.2,1.2,0.02,0.25],["gpt-5.6-sol",1050000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-terra",1050000,128000,"text,image",1,null,2,12,0.2,2.5],["gpt-6-astra",1050000,128000,"text,image",1,null,10,50,1,12.5],["gpt-6-luna",1050000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["gpt-6-sol",1050000,128000,"text,image",1,null,2,10,0.2,2.5],["gpt-6.1-sol",1050000,128000,"text,image",1,null,2,10,0.1,2.5],["gpt-realtime-2.1",128000,32000,"text,image",1,null,4,24,0.4,0],["o1",200000,100000,"text,image",1,null,15,60,7.5,0],["o1-pro",200000,100000,"text,image",1,null,150,600,0,0],["o3",200000,100000,"text,image",1,null,2,8,0.5,0],["o3-deep-research",200000,100000,"text,image",1,null,10,40,2.5,0],["o3-mini",200000,100000,"text",1,null,1.1,4.4,0.55,0],["o3-pro",200000,100000,"text,image",1,null,20,80,0,0],["o4-mini",200000,100000,"text,image",1,null,1.1,4.4,0.275,0],["o4-mini-deep-research",200000,100000,"text,image",1,null,2,8,0.5,0]], diff --git a/src/providers/registry/entries-extended.ts b/src/providers/registry/entries-extended.ts index 2d28b7f0756..211b94fe5e7 100644 --- a/src/providers/registry/entries-extended.ts +++ b/src/providers/registry/entries-extended.ts @@ -38,7 +38,7 @@ import { MINIMAX_MODEL_INPUT_MODALITIES, MINIMAX_M3_REASONING_EFFORTS, MINIMAX_M3_REASONING_EFFORT_MAP, - MINIMAX_M31_FLASH_PREVIEW, + MINIMAX_M31_FLASH, MINIMAX_M31_REASONING_EFFORTS, MINIMAX_M31_DEFAULT_REASONING_EFFORT, MINIMAX_REASONING_SPLIT_MODELS, @@ -1044,18 +1044,18 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [ }, { id: "minimax", label: "MiniMax — Coding Plan", baseUrl: "https://api.minimax.io/v1", adapter: "openai-chat", authKind: "key", - dashboardUrl: "https://platform.minimax.io", defaultModel: "MiniMax-M3", models: MINIMAX_MODELS, + dashboardUrl: "https://platform.minimax.io", defaultModel: MINIMAX_M31_FLASH, models: MINIMAX_MODELS, modelContextWindows: MINIMAX_MODEL_CONTEXT_WINDOWS, modelInputModalities: MINIMAX_MODEL_INPUT_MODALITIES, - modelReasoningEfforts: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORTS, [MINIMAX_M31_FLASH_PREVIEW]: MINIMAX_M31_REASONING_EFFORTS }, - modelDefaultReasoningEfforts: { "MiniMax-M3": "medium", [MINIMAX_M31_FLASH_PREVIEW]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, + modelReasoningEfforts: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORTS, [MINIMAX_M31_FLASH]: MINIMAX_M31_REASONING_EFFORTS }, + modelDefaultReasoningEfforts: { "MiniMax-M3": "medium", [MINIMAX_M31_FLASH]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, modelReasoningEffortMap: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORT_MAP }, preserveReasoningContentModels: MINIMAX_MODELS, // MiniMax-M3 low effort maps to thinking disabled, so a legitimate tool // round can carry no reasoning at all; only replay real recorded text, // never a fabricated placeholder (chatgpt-codex-connector P2 on #1205). requiresReasoningPlaceholderModels: [], - // M3.1-Flash-Preview ignores reasoning_split and always answers with reasoning_content, + // M3.1-Flash ignores reasoning_split and always answers with reasoning_content, // so it stays off the split/details lists and replays as a reasoning_content string. reasoningSplitModels: MINIMAX_REASONING_SPLIT_MODELS, // With reasoning_split the upstream returns thinking as a structured @@ -1070,11 +1070,11 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [ }, { id: "minimax-cn", label: "MiniMax — Coding Plan (CN)", baseUrl: "https://api.minimaxi.com/v1", adapter: "openai-chat", authKind: "key", - dashboardUrl: "https://platform.minimaxi.com", defaultModel: "MiniMax-M3", models: MINIMAX_MODELS, + dashboardUrl: "https://platform.minimaxi.com", defaultModel: MINIMAX_M31_FLASH, models: MINIMAX_MODELS, modelContextWindows: MINIMAX_MODEL_CONTEXT_WINDOWS, modelInputModalities: MINIMAX_MODEL_INPUT_MODALITIES, - modelReasoningEfforts: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORTS, [MINIMAX_M31_FLASH_PREVIEW]: MINIMAX_M31_REASONING_EFFORTS }, - modelDefaultReasoningEfforts: { "MiniMax-M3": "medium", [MINIMAX_M31_FLASH_PREVIEW]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, + modelReasoningEfforts: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORTS, [MINIMAX_M31_FLASH]: MINIMAX_M31_REASONING_EFFORTS }, + modelDefaultReasoningEfforts: { "MiniMax-M3": "medium", [MINIMAX_M31_FLASH]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, modelReasoningEffortMap: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORT_MAP }, preserveReasoningContentModels: MINIMAX_MODELS, requiresReasoningPlaceholderModels: [], diff --git a/src/providers/registry/model-seeds.ts b/src/providers/registry/model-seeds.ts index ac1088df1c9..1a1d2261248 100644 --- a/src/providers/registry/model-seeds.ts +++ b/src/providers/registry/model-seeds.ts @@ -155,30 +155,29 @@ export const ZAI_GLM_5X_REASONING_EFFORTS: Record = { }; // 260710 MiniMax models and context windows: Tier-2 evidence in // devlog/_plan/260710_provider_hardening/002_research_cn.md. -// 260930 MiniMax-M3.1-Flash-Preview: Token Plan / MiniMax Code only, 1M context, thinking -// always on (effort none or thinking disabled answers 400 code 2013), omitted effort = max. -// It returns thinking as reasoning_content and ignores reasoning_split. The live /v1/models -// roster does not list it yet. Evidence: devlog/_fin/260930_minimax_m31_flash_preview/. -export const MINIMAX_M31_FLASH_PREVIEW = "MiniMax-M3.1-Flash-Preview"; +// 261021 MiniMax-M3.1-Flash: current global/CN text route, 1M context, thinking always on +// (effort none or thinking disabled answers 400), omitted effort = max. It returns thinking as +// reasoning_content and ignores reasoning_split. The live /v1/models roster may omit it. +export const MINIMAX_M31_FLASH = "MiniMax-M3.1-Flash"; export const MINIMAX_MODELS = [ - MINIMAX_M31_FLASH_PREVIEW, + MINIMAX_M31_FLASH, "MiniMax-M3", "MiniMax-M2.7", "MiniMax-M2.7-highspeed", "MiniMax-M2.5", "MiniMax-M2.5-highspeed", "MiniMax-M2.1", "MiniMax-M2.1-highspeed", "MiniMax-M2", ]; -/** The eight-id roster every MiniMax preset seeded from 2026-07-10 until the preview landed. */ -export const MINIMAX_MODELS_BEFORE_M31 = MINIMAX_MODELS.filter(id => id !== MINIMAX_M31_FLASH_PREVIEW); +/** The eight-id roster every MiniMax preset seeded before Flash landed. */ +export const MINIMAX_MODELS_BEFORE_M31 = MINIMAX_MODELS.filter(id => id !== MINIMAX_M31_FLASH); /** Models that honour reasoning_split and answer with structured reasoning_details. */ export const MINIMAX_REASONING_SPLIT_MODELS = MINIMAX_MODELS_BEFORE_M31; export const MINIMAX_MODEL_CONTEXT_WINDOWS: Record = Object.fromEntries( - MINIMAX_MODELS.map(id => [id, id === "MiniMax-M3" || id === MINIMAX_M31_FLASH_PREVIEW ? 1_000_000 : 204_800]), + MINIMAX_MODELS.map(id => [id, id === "MiniMax-M3" || id === MINIMAX_M31_FLASH ? 1_000_000 : 204_800]), ); /** MiniMax's OpenAI-compatible M3 endpoints accept image_url; keep video off Codex's input enum. */ export const MINIMAX_MODEL_INPUT_MODALITIES: Record = { "MiniMax-M3": ["text", "image"], - [MINIMAX_M31_FLASH_PREVIEW]: ["text", "image"], + [MINIMAX_M31_FLASH]: ["text", "image", "video"], }; export const MINIMAX_M3_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"]; /** Identity efforts on the wire; no map, so none omits the field instead of disabling thinking. */ diff --git a/src/providers/stale-model-roster-migration.ts b/src/providers/stale-model-roster-migration.ts index 6b627cd5840..db15480841e 100644 --- a/src/providers/stale-model-roster-migration.ts +++ b/src/providers/stale-model-roster-migration.ts @@ -31,7 +31,7 @@ import { META_MUSE_MODELS, META_MUSE_WONDER_MODEL, MINIMAX_M31_DEFAULT_REASONING_EFFORT, - MINIMAX_M31_FLASH_PREVIEW, + MINIMAX_M31_FLASH, MINIMAX_MODELS, MINIMAX_MODELS_BEFORE_M31, MINIMAX_MODEL_CONTEXT_WINDOWS, @@ -79,8 +79,8 @@ const ALIBABA_INTL_TOKEN_PLAN_MODELS_BEFORE_1017 = [ ]; /** - * MiniMax-M3.1-Flash-Preview (2026-09-30). MiniMax's /v1/models roster does not list the - * preview, so live discovery cannot add it; the catalog keeps it only when it is configured. + * MiniMax-M3.1-Flash (2026-10-21). MiniMax's /v1/models roster does not list the + * Flash, so live discovery cannot add it; the catalog keeps it only when it is configured. */ export const STALE_MODEL_ROSTERS: readonly StaleModelRoster[] = [ { @@ -96,8 +96,8 @@ export const STALE_MODEL_ROSTERS: readonly StaleModelRoster[] = [ provider, from: MINIMAX_MODELS_BEFORE_M31, to: MINIMAX_MODELS, - contextWindows: { [MINIMAX_M31_FLASH_PREVIEW]: MINIMAX_MODEL_CONTEXT_WINDOWS[MINIMAX_M31_FLASH_PREVIEW]! }, - defaultReasoningEfforts: { [MINIMAX_M31_FLASH_PREVIEW]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, + contextWindows: { [MINIMAX_M31_FLASH]: MINIMAX_MODEL_CONTEXT_WINDOWS[MINIMAX_M31_FLASH]! }, + defaultReasoningEfforts: { [MINIMAX_M31_FLASH]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, })), ...[ { provider: "alibaba-token-plan", from: ALIBABA_TOKEN_PLAN_MODELS_BEFORE_1017, to: ALIBABA_TOKEN_PLAN_MODELS }, diff --git a/tests/providers/minimax-combo-image-input.test.ts b/tests/providers/minimax-combo-image-input.test.ts index 4ae06470c62..7b0e9c247cf 100644 --- a/tests/providers/minimax-combo-image-input.test.ts +++ b/tests/providers/minimax-combo-image-input.test.ts @@ -9,7 +9,7 @@ import { isModelVisionSidecarConsumer } from "../../src/vision/eligibility"; import type { CatalogModel, OcxConfig, OcxProviderConfig } from "../../src/types"; const M3 = "MiniMax-M3"; -const PREVIEW = "MiniMax-M3.1-Flash-Preview"; +const PREVIEW = "MiniMax-M3.1-Flash"; const REGIONS = ["minimax", "minimax-cn"] as const; const originalFetch = globalThis.fetch; @@ -33,7 +33,7 @@ describe("MiniMax Coding Plan Combo image input", () => { for (const region of REGIONS) { const fresh = seeded(region); expect(fresh.modelInputModalities?.[M3]).toEqual(["text", "image"]); - expect(fresh.modelInputModalities?.[PREVIEW]).toEqual(["text", "image"]); + expect(fresh.modelInputModalities?.[PREVIEW]).toEqual(["text", "image", "video"]); expect(fresh.modelInputModalities?.["MiniMax-M2.7"]).toBeUndefined(); const saved: OcxProviderConfig = { @@ -43,7 +43,7 @@ describe("MiniMax Coding Plan Combo image input", () => { }; enrichProviderFromRegistry(region, saved); expect(saved.modelInputModalities).toMatchObject({ - [M3]: ["text", "image"], [PREVIEW]: ["text", "image"], "MiniMax-M2.7": ["text"], + [M3]: ["text", "image"], [PREVIEW]: ["text", "image", "video"], "MiniMax-M2.7": ["text"], }); expect(saved.modelCapabilities?.[M3]?.inputModalities).toEqual(["text"]); expect(isModelVisionSidecarConsumer(saved, M3)).toBe(true); diff --git a/tests/providers/minimax-reasoning-split.test.ts b/tests/providers/minimax-reasoning-split.test.ts index c2decc342b1..62287b58d84 100644 --- a/tests/providers/minimax-reasoning-split.test.ts +++ b/tests/providers/minimax-reasoning-split.test.ts @@ -376,11 +376,11 @@ describe("MiniMax split reasoning", () => { }); }); -describe("MiniMax-M3.1-Flash-Preview reasoning wire", () => { +describe("MiniMax-M3.1-Flash reasoning wire", () => { // Probed 2026-09-30: thinking cannot be turned off (effort none or thinking disabled // answers 400 code 2013), effort low..max is accepted as-is, reasoning_split is ignored // and thinking always returns as reasoning_content. - const PREVIEW = "MiniMax-M3.1-Flash-Preview"; + const PREVIEW = "MiniMax-M3.1-Flash"; test("Codex efforts go out as identity reasoning_effort and never disable thinking", () => { const route = minimaxRoute(PREVIEW); diff --git a/tests/providers/model-roster-seed-repair.test.ts b/tests/providers/model-roster-seed-repair.test.ts index 0c7c3d390d4..9ea1b1b6144 100644 --- a/tests/providers/model-roster-seed-repair.test.ts +++ b/tests/providers/model-roster-seed-repair.test.ts @@ -15,7 +15,7 @@ import { import { PROVIDER_REGISTRY } from "../../src/providers/registry"; import type { OcxConfig, OcxProviderConfig } from "../../src/types"; -const PREVIEW = "MiniMax-M3.1-Flash-Preview"; +const PREVIEW = "MiniMax-M3.1-Flash"; function minimaxConfig(provider: string, row: Partial): OcxConfig { return { diff --git a/tests/providers/provider-registry-parity.test.ts b/tests/providers/provider-registry-parity.test.ts index 68787660838..30018ed2e29 100644 --- a/tests/providers/provider-registry-parity.test.ts +++ b/tests/providers/provider-registry-parity.test.ts @@ -201,7 +201,7 @@ describe("provider registry parity", () => { expect(KEY_LOGIN_PROVIDERS).toEqual(deriveKeyLoginMap()); expect(Object.keys(KEY_LOGIN_PROVIDERS)).toEqual(EXPECTED_KEY_PROVIDER_IDS); expect(Object.keys(deriveKeyLoginMap())).toEqual(EXPECTED_KEY_PROVIDER_IDS); - expect(KEY_LOGIN_PROVIDERS.minimax.defaultModel).toBe("MiniMax-M3"); + expect(KEY_LOGIN_PROVIDERS.minimax.defaultModel).toBe("MiniMax-M3.1-Flash"); expect(KEY_LOGIN_PROVIDERS.umans).toMatchObject({ label: "Umans AI Coding Plan", adapter: "anthropic", @@ -510,7 +510,7 @@ describe("provider registry parity", () => { }); const minimaxModels = [ - "MiniMax-M3.1-Flash-Preview", + "MiniMax-M3.1-Flash", "MiniMax-M3", "MiniMax-M2.7", "MiniMax-M2.7-highspeed", "MiniMax-M2.5", "MiniMax-M2.5-highspeed", @@ -522,16 +522,16 @@ describe("provider registry parity", () => { const entry = PROVIDER_REGISTRY.find(provider => provider.id === providerId); expect(entry?.adapter).toBe("openai-chat"); expect(entry?.baseUrl).toBe(providerId === "minimax" ? "https://api.minimax.io/v1" : "https://api.minimaxi.com/v1"); - expect(entry?.defaultModel).toBe("MiniMax-M3"); + expect(entry?.defaultModel).toBe("MiniMax-M3.1-Flash"); expect(entry?.models).toEqual(minimaxModels); expect(entry?.modelContextWindows?.["MiniMax-M3"]).toBe(1_000_000); - expect(entry?.modelContextWindows?.["MiniMax-M3.1-Flash-Preview"]).toBe(1_000_000); + expect(entry?.modelContextWindows?.["MiniMax-M3.1-Flash"]).toBe(1_000_000); expect(entry?.modelReasoningEfforts?.["MiniMax-M3"]).toEqual(["low", "medium", "high", "xhigh", "max"]); - expect(entry?.modelReasoningEfforts?.["MiniMax-M3.1-Flash-Preview"]).toEqual(["low", "medium", "high", "xhigh", "max"]); + expect(entry?.modelReasoningEfforts?.["MiniMax-M3.1-Flash"]).toEqual(["low", "medium", "high", "xhigh", "max"]); expect(entry?.modelDefaultReasoningEfforts?.["MiniMax-M3"]).toBe("medium"); - expect(entry?.modelDefaultReasoningEfforts?.["MiniMax-M3.1-Flash-Preview"]).toBe("max"); + expect(entry?.modelDefaultReasoningEfforts?.["MiniMax-M3.1-Flash"]).toBe("max"); expect(entry?.modelReasoningEffortMap?.["MiniMax-M3"]).toMatchObject({ low: "disabled", medium: "adaptive", high: "adaptive" }); - expect(entry?.modelReasoningEffortMap?.["MiniMax-M3.1-Flash-Preview"]).toBeUndefined(); + expect(entry?.modelReasoningEffortMap?.["MiniMax-M3.1-Flash"]).toBeUndefined(); expect(entry?.preserveReasoningContentModels).toEqual(minimaxModels); expect(entry?.reasoningSplitModels).toEqual(splitModels); expect(entry?.reasoningDetailsModels).toEqual(splitModels); From 5eacb721635c18c1ca644bfcea38dc9de5df42b1 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 26 Oct 2026 14:48:03 +0900 Subject: [PATCH 2/2] fix(minimax): rename retired Flash preview id and seed its output limit Carries #7739 onto dev. Adds a MODEL_RENAMES entry for both MiniMax presets so saved MiniMax-M3.1-Flash-Preview selections move to the GA id, seeds the 524,288 output limit during roster repair, keeps Flash input modalities at text/image like M3, and updates docs and the structure note. Co-authored-by: octo-patch <266937838+octo-patch@users.noreply.github.com> --- docs-site/src/content/docs/guides/minimax.md | 2 +- .../src/content/docs/guides/providers.md | 20 +++++------ .../src/content/docs/zh-cn/guides/minimax.md | 2 +- src/providers/model-rename-migration.ts | 10 ++++++ src/providers/registry/model-seeds.ts | 6 +++- src/providers/stale-model-roster-migration.ts | 2 ++ structure/providers-and-adapters.md | 2 +- .../minimax-combo-image-input.test.ts | 4 +-- .../model-roster-seed-repair.test.ts | 36 +++++++++++++++++++ 9 files changed, 67 insertions(+), 17 deletions(-) diff --git a/docs-site/src/content/docs/guides/minimax.md b/docs-site/src/content/docs/guides/minimax.md index db01d782d7a..121bf88c9c1 100644 --- a/docs-site/src/content/docs/guides/minimax.md +++ b/docs-site/src/content/docs/guides/minimax.md @@ -13,7 +13,7 @@ the protocol boundary it actually exposes: ## MiniMax Code In the OpenCodex Models page, both MiniMax Coding Plan regions advertise image input for -`MiniMax-M3` and `MiniMax-M3.1-Flash-Preview`. A Combo's **Image / multimodal** switch is +`MiniMax-M3` and `MiniMax-M3.1-Flash`. A Combo's **Image / multimodal** switch is available only when every selected model supports image input. The switch controls image attachments; it does not enable video uploads. diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index 9d434d103a9..1d90b8a0d78 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -885,17 +885,15 @@ attempt fails, while transient failures keep it. An unreadable or oversized body further attempts. Dollar credits show the included allowance only, excluding purchased credits, so an exhausted allowance stops routing to Ollama Cloud only when no purchased credit remains. -`MiniMax-M3.1-Flash-Preview` (1M context) is listed on both MiniMax presets. MiniMax serves it -only to Token Plan subscription keys and MiniMax Code for now, so a pay-as-you-go API key gets an -error for it. Thinking is always on: the effort picker offers `low` through `max` and defaults to -`max`, and there is no way to turn thinking off. MiniMax has not published a per-token price -for the preview; usage is drawn from your -[Token Plan quota](https://platform.minimax.io/docs/guides/pricing-token-plan), so OpenCodex -shows no estimated cost for it. MiniMax's `/models` endpoint does not list -the preview yet, so OpenCodex keeps it in the catalog from the preset. An install whose saved -MiniMax model list is still the previous default receives it on the next start; a list you edited -is left as it is; register the preview by hand with -`ocx models add minimax MiniMax-M3.1-Flash-Preview --context-window 1000000`. +`MiniMax-M3.1-Flash` (1M context, up to 524,288 output tokens) is the default model on both MiniMax +presets. MiniMax released it on 2026-10-19 and retired the `MiniMax-M3.1-Flash-Preview` id, so a +saved configuration that still names the preview is renamed to `MiniMax-M3.1-Flash` on the next +start. Thinking is always on: the effort picker offers `low` through `max` and defaults to `max`, +and there is no way to turn thinking off. MiniMax's `/models` endpoint does not list Flash, so +OpenCodex keeps it in the catalog from the preset. An install whose saved MiniMax model list is +still the previous default receives it on the next start; a list you edited is left as it is; +register it by hand with +`ocx models add minimax MiniMax-M3.1-Flash --context-window 1000000`. **OpenCode Go** routes `gemini-4-argon-contributor` through its Gemini API, including streaming and tool-result continuations. The existing `opencode-go` preset keeps its diff --git a/docs-site/src/content/docs/zh-cn/guides/minimax.md b/docs-site/src/content/docs/zh-cn/guides/minimax.md index d7baff5ceeb..ca0b375156e 100644 --- a/docs-site/src/content/docs/zh-cn/guides/minimax.md +++ b/docs-site/src/content/docs/zh-cn/guides/minimax.md @@ -11,7 +11,7 @@ MiniMax 发布两种不同的命令行产品。OpenCodex 在它们实际提供 ## MiniMax Code 在 OpenCodex 的模型管理页面,MiniMax Coding Plan 两个区域的 `MiniMax-M3` 和 -`MiniMax-M3.1-Flash-Preview` 均声明支持图片输入。只有所有选定模型均支持图片输入时, +`MiniMax-M3.1-Flash` 均声明支持图片输入。只有所有选定模型均支持图片输入时, Combo 的“图片 / 多模态”开关才可用。该开关控制图片附件,不提供视频上传能力。 先按照 MiniMax 的说明安装并登录 MiniMax Code,然后启动 OpenCodex 并连接可逆的文件集成: diff --git a/src/providers/model-rename-migration.ts b/src/providers/model-rename-migration.ts index 37a778766a1..3b677a6d17d 100644 --- a/src/providers/model-rename-migration.ts +++ b/src/providers/model-rename-migration.ts @@ -19,6 +19,7 @@ // Everything else in the row is left alone. import { PROVIDER_REGISTRY, normalizedProviderEndpoint } from "./registry"; +import { MINIMAX_M31_FLASH, MINIMAX_M31_FLASH_PREVIEW_RETIRED } from "./registry/model-seeds"; import { MODEL_KEYED_RECORDS, MODEL_ID_LISTS, MODEL_ID_SCALARS, MODEL_NESTED_RECORDS } from "./model-rename-fields"; import { providerConfigSeed } from "./derive"; import type { OcxConfig, OcxProviderConfig } from "../types"; @@ -138,6 +139,15 @@ export const MODEL_RENAMES: readonly ModelRename[] = [ // may also hold one as a value. 3.8 resolves tiers from its own suffix ladder instead. dropReasoningEffortMap: true, })), + // MiniMax shipped M3.1-Flash as generally available on 2026-10-19 and retired the preview + // id, so a saved MiniMax-M3.1-Flash-Preview selection would answer model-not-found. The + // stale-roster refresh only matches exact old seeds; this repairs the preview id itself. + ...(["minimax", "minimax-cn"] as const).map(provider => ({ + provider, + from: MINIMAX_M31_FLASH_PREVIEW_RETIRED, + to: MINIMAX_M31_FLASH, + reason: "MiniMax shipped M3.1-Flash as generally available and retired the preview id", + })), ]; function renameInList(value: unknown, from: string, to: string): string[] | null { diff --git a/src/providers/registry/model-seeds.ts b/src/providers/registry/model-seeds.ts index 1a1d2261248..62201972287 100644 --- a/src/providers/registry/model-seeds.ts +++ b/src/providers/registry/model-seeds.ts @@ -159,6 +159,10 @@ export const ZAI_GLM_5X_REASONING_EFFORTS: Record = { // (effort none or thinking disabled answers 400), omitted effort = max. It returns thinking as // reasoning_content and ignores reasoning_split. The live /v1/models roster may omit it. export const MINIMAX_M31_FLASH = "MiniMax-M3.1-Flash"; +/** The preview id MiniMax retired when M3.1-Flash went GA (2026-10-19); see MODEL_RENAMES. */ +export const MINIMAX_M31_FLASH_PREVIEW_RETIRED = "MiniMax-M3.1-Flash-Preview"; +/** MiniMax's published M3.1-Flash output ceiling (512K). */ +export const MINIMAX_M31_FLASH_MAX_OUTPUT_TOKENS = 524_288; export const MINIMAX_MODELS = [ MINIMAX_M31_FLASH, "MiniMax-M3", @@ -177,7 +181,7 @@ export const MINIMAX_MODEL_CONTEXT_WINDOWS: Record = Object.from /** MiniMax's OpenAI-compatible M3 endpoints accept image_url; keep video off Codex's input enum. */ export const MINIMAX_MODEL_INPUT_MODALITIES: Record = { "MiniMax-M3": ["text", "image"], - [MINIMAX_M31_FLASH]: ["text", "image", "video"], + [MINIMAX_M31_FLASH]: ["text", "image"], }; export const MINIMAX_M3_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"]; /** Identity efforts on the wire; no map, so none omits the field instead of disabling thinking. */ diff --git a/src/providers/stale-model-roster-migration.ts b/src/providers/stale-model-roster-migration.ts index db15480841e..9a3ee18885c 100644 --- a/src/providers/stale-model-roster-migration.ts +++ b/src/providers/stale-model-roster-migration.ts @@ -32,6 +32,7 @@ import { META_MUSE_WONDER_MODEL, MINIMAX_M31_DEFAULT_REASONING_EFFORT, MINIMAX_M31_FLASH, + MINIMAX_M31_FLASH_MAX_OUTPUT_TOKENS, MINIMAX_MODELS, MINIMAX_MODELS_BEFORE_M31, MINIMAX_MODEL_CONTEXT_WINDOWS, @@ -97,6 +98,7 @@ export const STALE_MODEL_ROSTERS: readonly StaleModelRoster[] = [ from: MINIMAX_MODELS_BEFORE_M31, to: MINIMAX_MODELS, contextWindows: { [MINIMAX_M31_FLASH]: MINIMAX_MODEL_CONTEXT_WINDOWS[MINIMAX_M31_FLASH]! }, + maxOutputTokens: { [MINIMAX_M31_FLASH]: MINIMAX_M31_FLASH_MAX_OUTPUT_TOKENS }, defaultReasoningEfforts: { [MINIMAX_M31_FLASH]: MINIMAX_M31_DEFAULT_REASONING_EFFORT }, })), ...[ diff --git a/structure/providers-and-adapters.md b/structure/providers-and-adapters.md index 32a4a3789c1..ccaf687ea09 100644 --- a/structure/providers-and-adapters.md +++ b/structure/providers-and-adapters.md @@ -391,7 +391,7 @@ axis that outranks every source here, so it is where a deliberate text-only over (`ocx provider edit --model --text-only` writes it) and the one declaration a restart cannot take back. -When `/models` omits MiniMax-M3.1-Flash-Preview, `src/providers/stale-model-roster-migration.ts` replaces only a saved roster identical to the old seed and fills existing window and default-effort records during startup; `CALLABLE_CONFIGURED_COMPATIBILITY_MODELS` (`src/codex/catalog/model-hints.ts`) retains it in the live catalog. +When `/models` omits MiniMax-M3.1-Flash, `src/providers/stale-model-roster-migration.ts` replaces only a saved roster identical to the old seed and fills existing window, output-limit and default-effort records during startup; `CALLABLE_CONFIGURED_COMPATIBILITY_MODELS` (`src/codex/catalog/model-hints.ts`) retains it in the live catalog. `MODEL_RENAMES` (`src/providers/model-rename-migration.ts`) repairs saved rows that still name the retired MiniMax-M3.1-Flash-Preview id. Both MiniMax Coding Plan presets declare `text` and `image` for M3 and M3.1 in `src/providers/registry/model-seeds.ts`; registry enrichment fills missing saved declarations, so id-only live rows enable the Combo image switch when every target supports images. Explicit overrides still win; video is outside Codex's catalog input enum. diff --git a/tests/providers/minimax-combo-image-input.test.ts b/tests/providers/minimax-combo-image-input.test.ts index 7b0e9c247cf..abef19e950f 100644 --- a/tests/providers/minimax-combo-image-input.test.ts +++ b/tests/providers/minimax-combo-image-input.test.ts @@ -33,7 +33,7 @@ describe("MiniMax Coding Plan Combo image input", () => { for (const region of REGIONS) { const fresh = seeded(region); expect(fresh.modelInputModalities?.[M3]).toEqual(["text", "image"]); - expect(fresh.modelInputModalities?.[PREVIEW]).toEqual(["text", "image", "video"]); + expect(fresh.modelInputModalities?.[PREVIEW]).toEqual(["text", "image"]); expect(fresh.modelInputModalities?.["MiniMax-M2.7"]).toBeUndefined(); const saved: OcxProviderConfig = { @@ -43,7 +43,7 @@ describe("MiniMax Coding Plan Combo image input", () => { }; enrichProviderFromRegistry(region, saved); expect(saved.modelInputModalities).toMatchObject({ - [M3]: ["text", "image"], [PREVIEW]: ["text", "image", "video"], "MiniMax-M2.7": ["text"], + [M3]: ["text", "image"], [PREVIEW]: ["text", "image"], "MiniMax-M2.7": ["text"], }); expect(saved.modelCapabilities?.[M3]?.inputModalities).toEqual(["text"]); expect(isModelVisionSidecarConsumer(saved, M3)).toBe(true); diff --git a/tests/providers/model-roster-seed-repair.test.ts b/tests/providers/model-roster-seed-repair.test.ts index 9ea1b1b6144..42c1ba1399e 100644 --- a/tests/providers/model-roster-seed-repair.test.ts +++ b/tests/providers/model-roster-seed-repair.test.ts @@ -94,6 +94,42 @@ describe("stale model roster migration", () => { expect(projection.config.providers!.minimax!.modelDefaultReasoningEfforts).toEqual({ [PREVIEW]: "low" }); }); + test("fills the Flash output limit into an existing partial output map", () => { + // Custom catalog rows read the saved map directly; without this the added id would + // publish with no output ceiling (CodeRabbit on #7739). + const projection = projectStaleModelRosters(minimaxConfig("minimax", { + models: [...MINIMAX_MODELS_BEFORE_M31], + modelMaxOutputTokens: { "MiniMax-M3": 128_000 }, + })); + expect(projection.config.providers!.minimax!.modelMaxOutputTokens).toEqual({ + "MiniMax-M3": 128_000, [PREVIEW]: 524_288, + }); + }); + + test("renames a saved MiniMax-M3.1-Flash-Preview selection to the GA id on both presets", () => { + const RETIRED = "MiniMax-M3.1-Flash-Preview"; + for (const [provider, baseUrl] of [["minimax", "https://api.minimax.io/v1"], ["minimax-cn", "https://api.minimaxi.com/v1"]] as const) { + const config = minimaxConfig(provider, { + baseUrl, + authMode: "key", + defaultModel: RETIRED, + models: MINIMAX_MODELS.map(id => (id === PREVIEW ? RETIRED : id)), + modelContextWindows: { [RETIRED]: 1_000_000, "MiniMax-M3": 1_000_000 }, + modelDefaultReasoningEfforts: { [RETIRED]: "high" }, + }); + const projection = projectStartupConfigRepairs(config); + const row = projection.config.providers![provider]!; + expect(projection.changed).toBe(true); + expect(JSON.stringify(projection.config)).not.toContain(RETIRED); + expect(row.models).toEqual(MINIMAX_MODELS); + expect(row.defaultModel).toBe(PREVIEW); + expect(row.modelContextWindows).toEqual({ [PREVIEW]: 1_000_000, "MiniMax-M3": 1_000_000 }); + // The user's saved effort survives the rename rather than being reset to the seed. + expect(row.modelDefaultReasoningEfforts).toEqual({ [PREVIEW]: "high" }); + expect(projectStartupConfigRepairs(structuredClone(projection.config)).changed).toBe(false); + } + }); + test("leaves a hand-edited roster alone", () => { const trimmed = MINIMAX_MODELS_BEFORE_M31.filter(id => id !== "MiniMax-M2"); const reordered = [...MINIMAX_MODELS_BEFORE_M31].reverse();