fix: discover xiaomi live models

This commit is contained in:
Mikael Hugo 2026-05-05 17:11:24 +02:00
parent 6fee7e60c8
commit c4ee341852
3 changed files with 78 additions and 3 deletions

View file

@ -95,7 +95,7 @@ describe("getDiscoverableProviders", () => {
"openrouter",
"zai",
"minimax",
"xiaomi",
"mistral",
]);
assert.ok(!providers.includes("ollama"));
@ -147,7 +147,13 @@ describe("getDefaultTTL", () => {
});
it("returns 1 hour for direct live-listed providers", () => {
for (const provider of ["zai", "minimax", "kimi-coding", "mistral"]) {
for (const provider of [
"zai",
"minimax",
"kimi-coding",
"xiaomi",
"mistral",
]) {
assert.equal(getDefaultTTL(provider), 60 * 60 * 1000);
}
});
@ -169,6 +175,7 @@ describe("DISCOVERY_TTLS", () => {
assert.ok("zai" in DISCOVERY_TTLS);
assert.ok("minimax" in DISCOVERY_TTLS);
assert.ok("kimi-coding" in DISCOVERY_TTLS);
assert.ok("xiaomi" in DISCOVERY_TTLS);
assert.ok("mistral" in DISCOVERY_TTLS);
assert.ok("singularity-memory" in DISCOVERY_TTLS);
assert.ok("default" in DISCOVERY_TTLS);
@ -324,6 +331,67 @@ describe("ollama-cloud discovery", () => {
});
});
// ─── Xiaomi Adapter ─────────────────────────────────────────────────────────
describe("xiaomi discovery", () => {
it("uses the live Xiaomi token-plan /v1/models endpoint and keeps the Anthropic execution endpoint", async () => {
const originalFetch = globalThis.fetch;
const calls: Array<{ url: string; headers?: RequestInit["headers"] }> = [];
globalThis.fetch = (async (
input: string | URL | Request,
init?: RequestInit,
) => {
calls.push({ url: String(input), headers: init?.headers });
return new Response(
JSON.stringify({
data: [
{
id: "mimo-v2.5",
name: "MiMo V2.5",
context_length: 1048576,
max_output_tokens: 131072,
},
{
id: "mimo-v2.5-pro",
capabilities: { reasoning: true, vision: true },
},
],
}),
{ status: 200 },
);
}) as typeof fetch;
try {
const adapter = getDiscoveryAdapter("xiaomi");
const models = await adapter.fetchModels("test-key");
assert.equal(
calls[0]?.url,
"https://token-plan-ams.xiaomimimo.com/v1/models",
);
assert.deepEqual(calls[0]?.headers, {
Authorization: "Bearer test-key",
});
assert.deepEqual(
models.map((m) => m.id),
["mimo-v2.5", "mimo-v2.5-pro"],
);
assert.ok(models.every((m) => m.provider === "xiaomi"));
assert.ok(models.every((m) => m.api === "anthropic-messages"));
assert.ok(
models.every(
(m) =>
m.baseUrl === "https://token-plan-ams.xiaomimimo.com/anthropic",
),
);
assert.equal(models[1]?.reasoning, true);
assert.deepEqual(models[1]?.input, ["text", "image"]);
} finally {
globalThis.fetch = originalFetch;
}
});
});
// ─── OpenRouter Adapter ─────────────────────────────────────────────────────
describe("openrouter discovery", () => {

View file

@ -47,6 +47,7 @@ export const DISCOVERY_TTLS: Record<string, number> = {
zai: 60 * 60 * 1000, // 1 hour
minimax: 60 * 60 * 1000, // 1 hour
"kimi-coding": 60 * 60 * 1000, // 1 hour
xiaomi: 60 * 60 * 1000, // 1 hour
mistral: 60 * 60 * 1000, // 1 hour
"singularity-memory": 5 * 60 * 1000, // 5 minutes (local daemon catalog)
default: 24 * 60 * 60 * 1000, // 24 hours
@ -528,6 +529,12 @@ const adapters: Record<string, ProviderDiscoveryAdapter> = {
api: "anthropic-messages",
}),
"kimi-coding": new StaticDiscoveryAdapter("kimi-coding"),
xiaomi: new ProviderModelListAdapter({
provider: "xiaomi",
discoveryBaseUrl: "https://token-plan-ams.xiaomimimo.com",
executionBaseUrl: "https://token-plan-ams.xiaomimimo.com/anthropic",
api: "anthropic-messages",
}),
mistral: new ProviderModelListAdapter({
provider: "mistral",
discoveryBaseUrl: "https://api.mistral.ai/v1",

View file

@ -72,7 +72,7 @@ function exitIfManagedResourcesAreNewer(currentAgentDir: string): void {
async function warmDiscoveryBackedProviders(
modelRegistry: ModelRegistry,
): Promise<void> {
const providers = ["ollama-cloud"].filter((provider) =>
const providers = ["ollama-cloud", "xiaomi"].filter((provider) =>
modelRegistry.isProviderRequestReady(provider),
);
if (providers.length === 0) return;