From 4d330dafa90100e9d018c5d617c8ae7c661e5dce Mon Sep 17 00:00:00 2001 From: backryun Date: Sun, 5 Jul 2026 19:54:57 +0900 Subject: [PATCH] fix(providers): remove deprecated MiMo v2 entries (#6248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chore(providers): remove deprecated MiMo V2 catalog entries (superseded by V2.5); realign provider-catalog tests. Merged — thank you, @backryun! Base-reds only. Integrated into release/v3.8.45. --- CHANGELOG.md | 1 + open-sse/config/audioRegistry.ts | 6 +--- .../providers/registry/opencode/go/index.ts | 2 -- .../providers/registry/zenmux-free/index.ts | 3 +- open-sse/config/providers/shared.ts | 3 -- src/shared/constants/providers/web-cookie.ts | 2 +- tests/unit/opencode-executor.test.ts | 28 +++++++++---------- .../opencode-go-catalog-alignment.test.ts | 14 ++++++++-- tests/unit/xiaomi-mimo-provider.test.ts | 22 +++++++-------- tests/unit/zenmux-free-provider.test.ts | 23 +++++++-------- 10 files changed, 50 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3258a81e5c..a7ca50c8c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ ### 📝 Maintenance - **i18n(it):** add 118 missing Italian (`it`) translations (net-additive — no existing keys dropped, valid JSON), improving Italian UI coverage. ([#6212](https://github.com/diegosouzapw/OmniRoute/pull/6212) — thanks @serverless83) +- **chore(providers):** remove deprecated **MiMo V2** model entries from the catalogs (xiaomi-mimo, opencode-go, zenmux-free, audio TTS) — the upstream V2 line is superseded by MiMo V2.5; drops `mimo-v2-tts`, `mimo-v2-pro`, `mimo-v2-omni`, `mimo-v2-flash`, `mimo-v2-flash-free` and realigns the provider-catalog tests. ([#6248](https://github.com/diegosouzapw/OmniRoute/pull/6248) — thanks @backryun) --- diff --git a/open-sse/config/audioRegistry.ts b/open-sse/config/audioRegistry.ts index cbeaa789e5..144d0f563f 100644 --- a/open-sse/config/audioRegistry.ts +++ b/open-sse/config/audioRegistry.ts @@ -416,7 +416,6 @@ export const AUDIO_SPEECH_PROVIDERS: Record = { { id: "mimo-v2.5-tts", name: "MiMo V2.5 TTS" }, { id: "mimo-v2.5-tts-voicedesign", name: "MiMo V2.5 Voice Design" }, { id: "mimo-v2.5-tts-voiceclone", name: "MiMo V2.5 Voice Clone" }, - { id: "mimo-v2-tts", name: "MiMo V2 TTS" }, ], }, }; @@ -512,10 +511,7 @@ export function parseSpeechModel(modelStr: string | null, dynamicProviders?: Aud return parseAudioModel(modelStr, AUDIO_SPEECH_PROVIDERS, dynamicProviders); } -export function parseTranslationModel( - modelStr: string | null, - dynamicProviders?: AudioProvider[] -) { +export function parseTranslationModel(modelStr: string | null, dynamicProviders?: AudioProvider[]) { return parseAudioModel(modelStr, AUDIO_TRANSLATION_PROVIDERS, dynamicProviders); } diff --git a/open-sse/config/providers/registry/opencode/go/index.ts b/open-sse/config/providers/registry/opencode/go/index.ts index b1c0b4f12e..c8e575b185 100644 --- a/open-sse/config/providers/registry/opencode/go/index.ts +++ b/open-sse/config/providers/registry/opencode/go/index.ts @@ -25,8 +25,6 @@ export const opencode_goProvider: RegistryEntry = { { id: "kimi-k2.5", name: "Kimi K2.5" }, { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro" }, { id: "mimo-v2.5", name: "MiMo-V2.5" }, - { id: "mimo-v2-pro", name: "MiMo-V2-Pro" }, - { id: "mimo-v2-omni", name: "MiMo-V2-Omni" }, // #3110: MiniMax M3 via OpenCode Go tier { id: "minimax-m3", diff --git a/open-sse/config/providers/registry/zenmux-free/index.ts b/open-sse/config/providers/registry/zenmux-free/index.ts index 126e2bf203..21ff0139bd 100644 --- a/open-sse/config/providers/registry/zenmux-free/index.ts +++ b/open-sse/config/providers/registry/zenmux-free/index.ts @@ -9,7 +9,7 @@ import type { RegistryEntry } from "../../shared.ts"; * for all API requests as a query parameter. * * Models available on the free tier (5 Flows/5h, 38.64 Flows/week): - * DeepSeek V3.2, GLM 4.7 Flash Free, MiMo V2 Flash Free, and others. + * DeepSeek V3.2, GLM 4.7 Flash Free, and others. * * Short alias "zmf" is distinct from the paid "zenmux" (alias "zm") which * uses API-key auth against the OpenAI-compatible endpoint. @@ -27,7 +27,6 @@ export const zenmux_freeProvider: RegistryEntry = { { id: "deepseek/deepseek-reasoner", name: "DeepSeek V3.2 (Thinking)", supportsReasoning: true }, { id: "deepseek/deepseek-v4-pro", name: "DeepSeek V4 Pro", supportsReasoning: true }, { id: "kuaishou/kat-coder-pro-v1-free", name: "KAT Coder Pro V1 Free" }, - { id: "xiaomi/mimo-v2-flash-free", name: "MiMo V2 Flash Free" }, { id: "z-ai/glm-4.7-flash-free", name: "GLM 4.7 Flash Free" }, { id: "stepfun/step-3.5-flash-free", name: "Step 3.5 Flash Free" }, { id: "inclusionai/ling-1t", name: "Ling 1T" }, diff --git a/open-sse/config/providers/shared.ts b/open-sse/config/providers/shared.ts index 1a90d258e6..4059673697 100644 --- a/open-sse/config/providers/shared.ts +++ b/open-sse/config/providers/shared.ts @@ -435,9 +435,6 @@ export const CHAT_OPENAI_COMPAT_MODELS: Record = { "xiaomi-mimo": [ { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", contextLength: 1048576, maxOutputTokens: 131072 }, { id: "mimo-v2.5", name: "MiMo-V2.5", contextLength: 1048576, maxOutputTokens: 131072 }, - { id: "mimo-v2-pro", name: "MiMo-V2-Pro", contextLength: 262144, maxOutputTokens: 131072 }, - { id: "mimo-v2-omni", name: "MiMo-V2-Omni", contextLength: 262144, maxOutputTokens: 131072 }, - { id: "mimo-v2-flash", name: "MiMo-V2-Flash", contextLength: 262144, maxOutputTokens: 65536 }, ], gitlawb: [ { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", contextLength: 1048576, maxOutputTokens: 131072 }, diff --git a/src/shared/constants/providers/web-cookie.ts b/src/shared/constants/providers/web-cookie.ts index 39e0bbc053..6b00ba0dd1 100644 --- a/src/shared/constants/providers/web-cookie.ts +++ b/src/shared/constants/providers/web-cookie.ts @@ -315,7 +315,7 @@ export const WEB_COOKIE_PROVIDERS = { website: "https://zenmux.ai", hasFree: true, freeNote: - "Free tier (5 Flows/5h, 38.64 Flows/week) — DeepSeek V3.2, GLM 4.7 Flash Free, MiMo V2 Flash Free and more. No subscription required.", + "Free tier (5 Flows/5h, 38.64 Flows/week) — DeepSeek V3.2, GLM 4.7 Flash Free and more. No subscription required.", authHint: "Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days.", }, diff --git a/tests/unit/opencode-executor.test.ts b/tests/unit/opencode-executor.test.ts index 1cee807258..716c0f3d91 100644 --- a/tests/unit/opencode-executor.test.ts +++ b/tests/unit/opencode-executor.test.ts @@ -228,8 +228,8 @@ describe("OpencodeExecutor", () => { // Register new models registerModel("opencode-go", { id: "glm-5.1", name: "GLM-5.1", contextLength: 204800 }); registerModel("opencode-go", { id: "kimi-k2.6", name: "Kimi K2.6" }); - registerModel("opencode-go", { id: "mimo-v2-pro", name: "MiMo V2 Pro" }); - registerModel("opencode-go", { id: "mimo-v2-omni", name: "MiMo V2 Omni" }); + registerModel("opencode-go", { id: "mimo-v2.5-pro", name: "MiMo V2.5 Pro" }); + registerModel("opencode-go", { id: "mimo-v2.5", name: "MiMo V2.5" }); // glm-5.1 const glm51 = await goExecutor.execute(createInput("glm-5.1")); @@ -239,13 +239,13 @@ describe("OpencodeExecutor", () => { const kimi26 = await goExecutor.execute(createInput("kimi-k2.6")); assert.equal(kimi26.url, "https://opencode.ai/zen/go/v1/chat/completions"); - // mimo-v2-pro - const mimoPro = await goExecutor.execute(createInput("mimo-v2-pro")); + // mimo-v2.5-pro + const mimoPro = await goExecutor.execute(createInput("mimo-v2.5-pro")); assert.equal(mimoPro.url, "https://opencode.ai/zen/go/v1/chat/completions"); - // mimo-v2-omni - const mimoOmni = await goExecutor.execute(createInput("mimo-v2-omni")); - assert.equal(mimoOmni.url, "https://opencode.ai/zen/go/v1/chat/completions"); + // mimo-v2.5 + const mimo = await goExecutor.execute(createInput("mimo-v2.5")); + assert.equal(mimo.url, "https://opencode.ai/zen/go/v1/chat/completions"); }); it("routes opencode-go qwen models to claude messages endpoint", async () => { @@ -278,21 +278,21 @@ describe("OpencodeExecutor", () => { it("routes opencode-go catalog-only models to chat completions", async () => { // Register new models registerModel("opencode-go", { id: "glm-6-max", name: "GLM-6 Max" }); - registerModel("opencode-go", { id: "mimo-v2-pro", name: "MiMo-V2-Pro" }); - registerModel("opencode-go", { id: "mimo-v2-omni", name: "MiMo-V2-Omni" }); + registerModel("opencode-go", { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro" }); + registerModel("opencode-go", { id: "mimo-v2.5", name: "MiMo-V2.5" }); registerModel("opencode-go", { id: "hy3-preview", name: "Hunyuan3 Preview" }); // glm-6-max const glm6 = await goExecutor.execute(createInput("glm-6-max")); assert.equal(glm6.url, "https://opencode.ai/zen/go/v1/chat/completions"); - // mimo-v2-pro - const mimoPro = await goExecutor.execute(createInput("mimo-v2-pro")); + // mimo-v2.5-pro + const mimoPro = await goExecutor.execute(createInput("mimo-v2.5-pro")); assert.equal(mimoPro.url, "https://opencode.ai/zen/go/v1/chat/completions"); - // mimo-v2-omni - const mimoOmni = await goExecutor.execute(createInput("mimo-v2-omni")); - assert.equal(mimoOmni.url, "https://opencode.ai/zen/go/v1/chat/completions"); + // mimo-v2.5 + const mimo = await goExecutor.execute(createInput("mimo-v2.5")); + assert.equal(mimo.url, "https://opencode.ai/zen/go/v1/chat/completions"); // hy3-preview const hy3 = await goExecutor.execute(createInput("hy3-preview")); diff --git a/tests/unit/opencode-go-catalog-alignment.test.ts b/tests/unit/opencode-go-catalog-alignment.test.ts index dd9741a1dd..6b9bd3b68b 100644 --- a/tests/unit/opencode-go-catalog-alignment.test.ts +++ b/tests/unit/opencode-go-catalog-alignment.test.ts @@ -11,14 +11,15 @@ import test from "node:test"; import assert from "node:assert/strict"; -const { opencode_goProvider } = await import( - "../../open-sse/config/providers/registry/opencode/go/index.ts" -); +const { opencode_goProvider } = + await import("../../open-sse/config/providers/registry/opencode/go/index.ts"); function modelIds(): string[] { return (opencode_goProvider.models ?? []).map((m) => m.id); } +const DEPRECATED_MIMO_V2_MODELS = ["mimo-v2-pro", "mimo-v2-omni"]; + test("opencode-go advertises glm-5.2 (official Go endpoint addition)", () => { assert.ok( modelIds().includes("glm-5.2"), @@ -33,6 +34,13 @@ test("opencode-go advertises kimi-k2.7-code (live API rejects plain kimi-k2.7 fo ); }); +test("opencode-go does not advertise deprecated MiMo V2 models", () => { + const ids = modelIds(); + for (const modelId of DEPRECATED_MIMO_V2_MODELS) { + assert.ok(!ids.includes(modelId), `${modelId} is deprecated`); + } +}); + test("opencode-go preserves the pre-existing minimax-m3 and qwen routing via targetFormat=claude", () => { // Routing through the /messages endpoint is OmniRoute's declarative // equivalent of upstream's MESSAGES_FORMAT_MODELS set; the alignment diff --git a/tests/unit/xiaomi-mimo-provider.test.ts b/tests/unit/xiaomi-mimo-provider.test.ts index c114dbe635..91a2ab0369 100644 --- a/tests/unit/xiaomi-mimo-provider.test.ts +++ b/tests/unit/xiaomi-mimo-provider.test.ts @@ -11,14 +11,19 @@ import { } from "../../src/shared/validation/schemas.ts"; import { validateBody } from "../../src/shared/validation/helpers.ts"; -test("xiaomi-mimo registry uses the current default base URL and MiMo V2.5 + V2 models", () => { +const DEPRECATED_MIMO_V2_MODELS = ["mimo-v2-pro", "mimo-v2-omni", "mimo-v2-flash", "mimo-v2-tts"]; + +test("xiaomi-mimo registry uses the current default base URL and MiMo V2.5 models", () => { const entry = REGISTRY["xiaomi-mimo"]; assert.ok(entry, "xiaomi-mimo should exist in registry"); assert.equal(entry.baseUrl, "https://api.xiaomimimo.com/v1"); + for (const modelId of DEPRECATED_MIMO_V2_MODELS) { + assert.ok(!entry.models.some((model) => model.id === modelId), `${modelId} is deprecated`); + } assert.deepEqual( entry.models.map((model) => model.id), - ["mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", "mimo-v2-omni", "mimo-v2-flash"] + ["mimo-v2.5-pro", "mimo-v2.5"] ); }); @@ -32,7 +37,7 @@ test("xiaomi-mimo TTS models are registered in the audio speech registry", () => assert.equal(provider.format, "xiaomi-mimo-tts"); assert.deepEqual( provider.models.map((model) => model.id), - ["mimo-v2.5-tts", "mimo-v2.5-tts-voicedesign", "mimo-v2.5-tts-voiceclone", "mimo-v2-tts"] + ["mimo-v2.5-tts", "mimo-v2.5-tts-voicedesign", "mimo-v2.5-tts-voiceclone"] ); assert.ok( getAllAudioModels().some( @@ -98,14 +103,9 @@ test("xiaomi-mimo update schema accepts custom regional baseUrl", () => { } }); -test("only MiMo V2.5 and V2-Omni report vision; the *-pro/flash chat models are text-only", () => { - // Corrected: Xiaomi documents ONLY mimo-v2.5 and mimo-v2-omni as image-capable - // (mimo.mi.com .../image-understanding). models.dev mislabels the *-pro models - // (hermes-agent#18884); see the hard override in src/lib/modelCapabilities.ts. +test("registered Xiaomi MiMo V2.5 chat models keep capability overrides", () => { + // models.dev mislabels the *-pro models (hermes-agent#18884); see the hard override in + // src/lib/modelCapabilities.ts. assert.equal(getModelSpec("mimo-v2.5")?.supportsVision, true); - assert.equal(getModelSpec("mimo-v2-omni")?.supportsVision, true); - // text-only chat models assert.equal(getModelSpec("mimo-v2.5-pro")?.supportsVision, false); - assert.equal(getModelSpec("mimo-v2-pro")?.supportsVision, false); - assert.equal(getModelSpec("mimo-v2-flash")?.supportsVision, undefined); }); diff --git a/tests/unit/zenmux-free-provider.test.ts b/tests/unit/zenmux-free-provider.test.ts index 1ddc004ce3..ff677b4e9d 100644 --- a/tests/unit/zenmux-free-provider.test.ts +++ b/tests/unit/zenmux-free-provider.test.ts @@ -36,6 +36,10 @@ test("zenmux-free WEB_COOKIE_PROVIDERS entry is marked as free-tier", () => { >; assert.equal(p.hasFree, true); assert.ok(typeof p.freeNote === "string" && (p.freeNote as string).length > 0); + assert.ok( + !(p.freeNote as string).includes("MiMo V2 Flash Free"), + "free note must not advertise deprecated MiMo V2 Flash Free" + ); assert.ok(typeof p.authHint === "string" && (p.authHint as string).length > 0); }); @@ -52,12 +56,11 @@ test("zenmux-free is present in the provider REGISTRY with correct shape", () => assert.equal(r.authHeader, "cookie"); }); -test("zenmux-free registry has 12 models including the 3 key free-tier ones", () => { +test("zenmux-free registry excludes deprecated MiMo V2 Flash Free", () => { const r = REGISTRY["zenmux-free"]; assert.ok(r.models && r.models.length > 0, "must have at least one model"); const ids = r.models.map((m) => m.id); - // The 3 main models mentioned in the upstream PR assert.ok( ids.includes("deepseek/deepseek-chat"), "deepseek/deepseek-chat (DeepSeek V3.2) must be registered" @@ -66,11 +69,8 @@ test("zenmux-free registry has 12 models including the 3 key free-tier ones", () ids.includes("z-ai/glm-4.7-flash-free"), "z-ai/glm-4.7-flash-free (GLM 4.7 Flash Free) must be registered" ); - assert.ok( - ids.includes("xiaomi/mimo-v2-flash-free"), - "xiaomi/mimo-v2-flash-free (MiMo V2 Flash Free) must be registered" - ); - assert.equal(r.models.length, 12, "must have exactly 12 models"); + assert.ok(!ids.includes("xiaomi/mimo-v2-flash-free"), "xiaomi/mimo-v2-flash-free is deprecated"); + assert.equal(r.models.length, 11, "must have exactly 11 models"); }); test("zenmux-free model names are human-readable strings", () => { @@ -115,7 +115,7 @@ test("ZenmuxFreeExecutor returns 401 when ctoken is missing from cookies", async } as Parameters[0]); assert.ok(result.response instanceof Response); assert.equal(result.response.status, 401); - const body = await result.response.json() as Record; + const body = (await result.response.json()) as Record; const errMsg = (body?.error as Record)?.message as string; assert.ok(errMsg && typeof errMsg === "string", "error.message must be present"); assert.ok(errMsg.includes("ctoken"), "error must mention ctoken"); @@ -162,10 +162,7 @@ test("ZenmuxFreeExecutor injects Cookie header from credentials when ctoken is p const req = intercepted[0]; // URL must include ctoken as query param - assert.ok( - req.url.includes("ctoken=my-ctoken-value"), - "ctoken must appear in the request URL" - ); + assert.ok(req.url.includes("ctoken=my-ctoken-value"), "ctoken must appear in the request URL"); // Cookie header must carry the full cookie string assert.ok(req.headers["cookie"], "Cookie header must be set"); assert.ok( @@ -200,7 +197,7 @@ test("ZenmuxFreeExecutor handles upstream 401 and returns clean error (not raw m } as Parameters[0]); assert.ok(result.response instanceof Response); assert.equal(result.response.status, 401); - const body = await result.response.json() as Record; + const body = (await result.response.json()) as Record; const errMsg = ((body?.error as Record)?.message as string) || ""; // Hard Rule #12 — no stack traces assert.ok(!errMsg.includes("at /"), "error must not contain stack trace path");