fix(providers): remove deprecated MiMo v2 entries (#6248)

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.
This commit is contained in:
backryun
2026-07-05 19:54:57 +09:00
committed by GitHub
parent 9285dc1b89
commit 4d330dafa9
10 changed files with 50 additions and 54 deletions

View File

@@ -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)
---

View File

@@ -416,7 +416,6 @@ export const AUDIO_SPEECH_PROVIDERS: Record<string, AudioProvider> = {
{ 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);
}

View File

@@ -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",

View File

@@ -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" },

View File

@@ -435,9 +435,6 @@ export const CHAT_OPENAI_COMPAT_MODELS: Record<string, RegistryModel[]> = {
"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 },

View File

@@ -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.",
},

View File

@@ -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"));

View File

@@ -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

View File

@@ -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);
});

View File

@@ -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<typeof executor.execute>[0]);
assert.ok(result.response instanceof Response);
assert.equal(result.response.status, 401);
const body = await result.response.json() as Record<string, unknown>;
const body = (await result.response.json()) as Record<string, unknown>;
const errMsg = (body?.error as Record<string, unknown>)?.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<typeof executor.execute>[0]);
assert.ok(result.response instanceof Response);
assert.equal(result.response.status, 401);
const body = await result.response.json() as Record<string, unknown>;
const body = (await result.response.json()) as Record<string, unknown>;
const errMsg = ((body?.error as Record<string, unknown>)?.message as string) || "";
// Hard Rule #12 — no stack traces
assert.ok(!errMsg.includes("at /"), "error must not contain stack trace path");