Merge pull request #1442 from hanbinnoh/fix/xiaomi-tp-cn-fallback

fix(xiaomi): add CN token-plan cluster as last fallback
This commit is contained in:
Can Bölük
2026-05-27 20:00:42 +03:00
committed by GitHub
@@ -1733,58 +1733,51 @@ export function xiaomiModelManagerOptions(
): ModelManagerOptions<"openai-completions"> {
const apiKey = config?.apiKey;
// Xiaomi splits API keys across two backends: standard `sk-` keys hit
// api.xiaomimimo.com; "token plan" `tp-` keys hit either the SG or EU
// token-plan host. Try SGP first; if discovery fails, retry AMS.
const TOKEN_PLAN_SGP_BASE_URL = "https://token-plan-sgp.xiaomimimo.com/v1";
const TOKEN_PLAN_AMS_BASE_URL = "https://token-plan-ams.xiaomimimo.com/v1";
const defaultBaseUrl = apiKey?.startsWith("tp-") ? TOKEN_PLAN_SGP_BASE_URL : "https://api.xiaomimimo.com/v1";
// Token-plan keys always use the TP baseUrl; config?.baseUrl (from catalog)
// api.xiaomimimo.com; "token plan" `tp-` keys are scoped to a regional
// cluster and are tried in order until discovery succeeds.
const TOKEN_PLAN_BASE_URLS = [
"https://token-plan-sgp.xiaomimimo.com/v1",
"https://token-plan-ams.xiaomimimo.com/v1",
"https://token-plan-cn.xiaomimimo.com/v1",
] as const;
const STANDARD_BASE_URL = "https://api.xiaomimimo.com/v1";
const isTokenPlanKey = apiKey?.startsWith("tp-");
// Token-plan keys always use a TP cluster; config?.baseUrl (from catalog)
// would incorrectly pin to the standard endpoint (api.xiaomimimo.com).
const baseUrl = apiKey?.startsWith("tp-") ? defaultBaseUrl : (config?.baseUrl ?? defaultBaseUrl);
const baseUrl = isTokenPlanKey ? TOKEN_PLAN_BASE_URLS[0] : (config?.baseUrl ?? STANDARD_BASE_URL);
const references = createBundledReferenceMap<"openai-completions">("xiaomi");
const fetchModels = (url: string) =>
fetchOpenAICompatibleModels({
api: "openai-completions",
provider: "xiaomi",
baseUrl: url,
apiKey,
filterModel: (_entry, model) => !model.id.includes("-tts"),
mapModel: (entry, defaults) => {
const reference = references.get(defaults.id);
const model = mapWithBundledReference(entry, defaults, reference);
return {
...model,
name: toModelName(entry.display_name, model.name),
};
},
});
return {
providerId: "xiaomi",
...(apiKey && {
fetchDynamicModels: async () => {
const sgpResult = await fetchOpenAICompatibleModels({
api: "openai-completions",
provider: "xiaomi",
baseUrl,
apiKey,
filterModel: (_entry, model) => !model.id.includes("-tts"),
mapModel: (entry, defaults) => {
const reference = references.get(defaults.id);
const model = mapWithBundledReference(entry, defaults, reference);
return {
...model,
name: toModelName(entry.display_name, model.name),
};
},
});
if (sgpResult || !apiKey?.startsWith("tp-")) {
return sgpResult;
if (!isTokenPlanKey) {
return fetchModels(baseUrl);
}
// Token-plan discovery failed with SGP; retry with AMS
return fetchOpenAICompatibleModels({
api: "openai-completions",
provider: "xiaomi",
baseUrl: TOKEN_PLAN_AMS_BASE_URL,
apiKey,
filterModel: (_entry, model) => !model.id.includes("-tts"),
mapModel: (entry, defaults) => {
const reference = references.get(defaults.id);
const model = mapWithBundledReference(entry, defaults, reference);
return {
...model,
name: toModelName(entry.display_name, model.name),
};
},
});
for (const url of TOKEN_PLAN_BASE_URLS) {
const result = await fetchModels(url);
if (result) return result;
}
return null;
},
}),
};
}
// ---------------------------------------------------------------------------
// 21. LiteLLM
// ---------------------------------------------------------------------------