fix(providers): expose base-URL override for Kimi/Moonshot CN-region keys (#7447) (#8500)

CN-region Moonshot/Kimi API keys (issued on the domestic
platform.kimi.com/moonshot.cn account) belong to a completely separate
keyspace than the international platform.kimi.ai/api.moonshot.ai
account, so OmniRoute's hard-coded international base URL rejects them
with a generic "Invalid API key" 401.

Neither "kimi" (legacy id) nor "moonshot" (current user-facing id) was
in CONFIGURABLE_BASE_URL_PROVIDERS, so the Add-connection modal never
rendered a base-URL field for them and there was no supported way to
point a new connection at api.moonshot.cn. The underlying
resolveBaseUrl()/buildUrl() primitives already honor a
providerSpecificData.baseUrl override generically (same mechanism used
by siliconflow, xiaomi-mimo, etc.) -- this only exposes that existing
affordance for kimi/moonshot, defaulting to the unchanged
international host so existing users see no behavior change.

Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-07-25 04:56:46 -03:00
committed by GitHub
parent e0aef4deb9
commit 24142a8e91
3 changed files with 71 additions and 0 deletions

View File

@@ -0,0 +1 @@
- fix(providers): expose a base-URL override for Kimi/Moonshot so CN-region API keys (issued on platform.kimi.com / moonshot.cn) can be pointed at api.moonshot.cn instead of being rejected by the international host (#7447)

View File

@@ -223,6 +223,16 @@ export const CONFIGURABLE_BASE_URL_PROVIDERS = new Set([
"searxng-search",
"petals",
"comfyui",
// #7447 — Moonshot/Kimi's international host (api.moonshot.ai) rejects
// CN-region keys (issued on platform.kimi.com/moonshot.cn — a separate
// account/keyspace). Neither "kimi" (legacy id) nor "moonshot" (current
// user-facing id) previously exposed a base-URL field at Add-connection
// time, so a CN-region user had no way to point a new connection at
// api.moonshot.cn. resolveBaseUrl()/buildUrl() already honor a
// providerSpecificData.baseUrl override generically — this only exposes
// the existing override affordance for these two ids.
"kimi",
"moonshot",
]);
export const DEFAULT_PROVIDER_BASE_URLS: Record<string, string> = {
@@ -234,6 +244,11 @@ export const DEFAULT_PROVIDER_BASE_URLS: Record<string, string> = {
"searxng-search": "http://localhost:8888/search",
petals: "https://chat.petals.dev/api/v1/generate",
comfyui: "http://localhost:8188",
// #7447 — default stays the international host so existing/new
// international Kimi/Moonshot users see the same prefilled value as
// before; a CN-region user overrides it (see placeholder hint below).
kimi: "https://api.moonshot.ai/v1",
moonshot: "https://api.moonshot.ai/v1",
};
export function getLocalProviderMetadata(providerId?: string | null) {
@@ -327,6 +342,11 @@ export function getProviderBaseUrlPlaceholder(providerId?: string | null) {
return "https://example-account.snowflakecomputing.com";
case "searxng-search":
return "http://localhost:8888/search";
case "kimi":
case "moonshot":
// #7447 — surfaces the CN-region alternative host as the placeholder
// example (mirrors the siliconflow.com/siliconflow.cn pattern above).
return "https://api.moonshot.cn/v1";
default:
return "";
}

View File

@@ -0,0 +1,50 @@
// #7447 — Kimi/Moonshot CN-region API keys were rejected because the built-in
// "kimi"/"moonshot" registry entries are hard-coded to the international host
// (api.moonshot.ai) and neither provider exposed a base-URL field at
// Add-connection time, so a CN-region key (issued on platform.kimi.com /
// moonshot.cn — a separate account/keyspace) had no supported way to point a
// new connection at api.moonshot.cn. Fix: expose the existing generic
// providerSpecificData.baseUrl override affordance for "kimi" and "moonshot"
// via CONFIGURABLE_BASE_URL_PROVIDERS, defaulting to the unchanged
// international host so existing users see no behavior change.
import test from "node:test";
import assert from "node:assert/strict";
import { getRegistryEntry } from "../../open-sse/config/providerRegistry.ts";
import {
isBaseUrlConfigurableProvider,
getProviderBaseUrlDefault,
getProviderBaseUrlPlaceholder,
} from "../../src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts";
test("kimi/moonshot registry entries still default to the international api.moonshot.ai host", () => {
const kimi = getRegistryEntry("kimi");
const moonshot = getRegistryEntry("moonshot");
assert.ok(kimi, "expected a registered 'kimi' provider entry");
assert.ok(moonshot, "expected a registered 'moonshot' provider entry");
assert.equal(kimi!.baseUrl, "https://api.moonshot.ai/v1/chat/completions");
assert.equal(moonshot!.baseUrl, "https://api.moonshot.ai/v1/chat/completions");
});
test("kimi and moonshot are base-URL configurable at Add-connection time (regression guard for #7447)", () => {
assert.equal(
isBaseUrlConfigurableProvider("kimi"),
true,
"expected 'kimi' to be base-URL configurable so a CN-region key can be pointed at api.moonshot.cn"
);
assert.equal(
isBaseUrlConfigurableProvider("moonshot"),
true,
"expected 'moonshot' to be base-URL configurable so a CN-region key can be pointed at api.moonshot.cn"
);
});
test("default base URL for kimi/moonshot stays international (no behavior change for existing users)", () => {
assert.equal(getProviderBaseUrlDefault("kimi"), "https://api.moonshot.ai/v1");
assert.equal(getProviderBaseUrlDefault("moonshot"), "https://api.moonshot.ai/v1");
});
test("placeholder surfaces the CN-region alternative host for kimi/moonshot", () => {
assert.equal(getProviderBaseUrlPlaceholder("kimi"), "https://api.moonshot.cn/v1");
assert.equal(getProviderBaseUrlPlaceholder("moonshot"), "https://api.moonshot.cn/v1");
});