Kimi and Kimi CN join the provider catalog: OpenAI-compatible endpoints, verified live

- kimi -> https://api.moonshot.ai/v1 (platform.kimi.ai keys), kimi-cn -> https://api.moonshot.cn/v1 (platform.kimi.com keys)
- Adapters via openAiCompatibleAdapter; agent loop via makeChatCompletionsTurn; live model listing
- Curated fallback models per current docs: kimi-k2.7-code, kimi-k2.7-code-highspeed, kimi-k2.6
- Migration 056 seeds both providers (disabled) into existing organizations
- Both endpoints probed live: OpenAI-style 401 error envelope confirmed
This commit is contained in:
ZacharyZhang-NY committed 2026-07-10 17:12:16 -04:00
1 parent c30cbce459
commit 813276de71
9 files changed
+60 -2

No files matched your search

@@ -0,0 +1,12 @@
export const kimiProvidersSchema = `
insert or ignore into providers(id, org_id, provider_key, label, auth_type, model, credential_id, enabled, created_at)
select 'prv_' || lower(hex(randomblob(16))), organizations.id, 'kimi', 'Kimi', 'api_key', 'kimi-k2.7-code', null, 0, datetime('now')
from organizations;
insert or ignore into providers(id, org_id, provider_key, label, auth_type, model, credential_id, enabled, created_at)
select 'prv_' || lower(hex(randomblob(16))), organizations.id, 'kimi-cn', 'Kimi CN', 'api_key', 'kimi-k2.7-code', null, 0, datetime('now')
from organizations;
insert into schema_migrations(version, name, applied_at)
values (56, 'kimi_providers', datetime('now'));
`;
+2
View File
@@ -54,6 +54,7 @@ import { avatarImagesSchema } from "./migrations/052-avatar-images";
import { autonomousPauseSchema } from "./migrations/053-autonomous-pause";
import { closeStaleWakeTasksSchema } from "./migrations/054-close-stale-wake-tasks";
import { taskOriginSchema } from "./migrations/055-task-origin";
import { kimiProvidersSchema } from "./migrations/056-kimi-providers";
interface Migration {
version: number;
@@ -117,6 +118,7 @@ const MIGRATIONS: Migration[] = [
{ version: 53, name: "autonomous_pause", sql: autonomousPauseSchema },
{ version: 54, name: "close_stale_wake_tasks", sql: closeStaleWakeTasksSchema },
{ version: 55, name: "task_origin", sql: taskOriginSchema },
{ version: 56, name: "kimi_providers", sql: kimiProvidersSchema },
];
const SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
+12
View File
@@ -210,6 +210,18 @@ export const providerAdapters: ProviderAdapterRegistry = {
endpoint: "https://openrouter.ai/api/v1/chat/completions",
healthUrl: "https://openrouter.ai/api/v1/models",
}),
kimi: openAiCompatibleAdapter({
providerKey: "kimi",
label: "Kimi",
endpoint: "https://api.moonshot.ai/v1/chat/completions",
healthUrl: "https://api.moonshot.ai/v1/models",
}),
"kimi-cn": openAiCompatibleAdapter({
providerKey: "kimi-cn",
label: "Kimi CN",
endpoint: "https://api.moonshot.cn/v1/chat/completions",
healthUrl: "https://api.moonshot.cn/v1/models",
}),
"github-copilot": browserTokenAdapter("github-copilot", PROVIDER_AUTH_TYPE.OAUTH_PKCE),
"google-antigravity": browserTokenAdapter("google-antigravity", PROVIDER_AUTH_TYPE.OAUTH_PKCE),
"gpt-account": browserTokenAdapter("gpt-account", PROVIDER_AUTH_TYPE.ACCOUNT_SUBSCRIPTION),
@@ -23,6 +23,8 @@ const TURNS: Record<string, ToolTurnFn> = {
mistral: makeChatCompletionsTurn("https://api.mistral.ai/v1/chat/completions", "Mistral"),
cerebras: makeChatCompletionsTurn("https://api.cerebras.ai/v1/chat/completions", "Cerebras"),
openrouter: makeChatCompletionsTurn("https://openrouter.ai/api/v1/chat/completions", "OpenRouter"),
kimi: makeChatCompletionsTurn("https://api.moonshot.ai/v1/chat/completions", "Kimi"),
"kimi-cn": makeChatCompletionsTurn("https://api.moonshot.cn/v1/chat/completions", "Kimi CN"),
"gpt-account": runCodexTurn,
"github-copilot": runCopilotTurn,
"google-antigravity": runAntigravityTurn,
+18
View File
@@ -74,6 +74,24 @@ const RAW_CATALOG: Omit<ProviderCatalogEntry, "models" | "supportsLiveModels">[]
signInUrl: null,
credentialHelp: "Generate an API key at openrouter.ai → Keys.",
},
{
key: "kimi",
label: "Kimi",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "kimi-k2.7-code",
capabilityTags: ["chat", "coding"],
signInUrl: null,
credentialHelp: "Generate an API key at platform.kimi.ai → API keys.",
},
{
key: "kimi-cn",
label: "Kimi CN",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "kimi-k2.7-code",
capabilityTags: ["chat", "coding"],
signInUrl: null,
credentialHelp: "Generate an API key at platform.kimi.com → API keys.",
},
{
key: "github-copilot",
label: "GitHub Copilot",
+10
View File
@@ -3,6 +3,14 @@ export interface ProviderModelEntry {
name: string;
}
// Shared by the international (api.moonshot.ai) and CN (api.moonshot.cn)
// platforms, which publish the same model line-up under different endpoints.
const KIMI_MODELS: ProviderModelEntry[] = [
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code" },
{ id: "kimi-k2.7-code-highspeed", name: "Kimi K2.7 Code Highspeed" },
{ id: "kimi-k2.6", name: "Kimi K2.6" },
];
const ANTHROPIC_MODELS: ProviderModelEntry[] = [
{ id: "claude-opus-4-7", name: "Claude Opus 4.7" },
{ id: "claude-opus-4-6", name: "Claude Opus 4.6" },
@@ -216,6 +224,8 @@ export const PROVIDER_MODELS: Record<string, ProviderModelEntry[]> = {
{ id: "zai-glm-4.7", name: "Z.AI GLM-4.7" },
{ id: "llama3.1-8b", name: "Llama 3.1 8B" },
],
kimi: KIMI_MODELS,
"kimi-cn": KIMI_MODELS,
openrouter: [
{ id: "anthropic/claude-sonnet-4.5", name: "Anthropic: Claude Sonnet 4.5" },
{ id: "anthropic/claude-opus-4.5", name: "Anthropic: Claude Opus 4.5" },
@@ -18,6 +18,8 @@ const PROVIDER_SECRET_SAMPLES: Record<string, string> = {
mistral: "sk-live-provider",
cerebras: "csk-live-provider",
openrouter: "sk-or-live-provider",
kimi: "sk-live-provider",
"kimi-cn": "sk-live-provider",
"github-copilot": "ghu_live_provider",
"google-antigravity": "antigravity-session",
"gpt-account": "chatgpt-session",
+1 -1
View File
@@ -24,7 +24,7 @@ describe("domain services", () => {
const connection = createConnection();
const rows = connection.db.prepare("select version from schema_migrations order by version asc").all() as Array<{ version: number }>;
expect(rows.map((row) => row.version)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]);
expect(rows.map((row) => row.version)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56]);
connection.close();
});
+1 -1
View File
@@ -186,7 +186,7 @@ describe("aws sigv4", () => {
describe("tool-turn router", () => {
test("supports every agent-capable provider (incl. cloud and custom) and rejects unknown ones", () => {
for (const key of ["openai", "anthropic", "xai", "groq", "mistral", "cerebras", "openrouter", "gpt-account", "github-copilot", "google-antigravity", "claude-pro", "custom-openai", "custom-anthropic", "azure-openai", "aws-bedrock", "vertex-ai"]) {
for (const key of ["openai", "anthropic", "xai", "groq", "mistral", "cerebras", "openrouter", "kimi", "kimi-cn", "gpt-account", "github-copilot", "google-antigravity", "claude-pro", "custom-openai", "custom-anthropic", "azure-openai", "aws-bedrock", "vertex-ai"]) {
expect(supportsToolTurn(key)).toBe(true);
expect(typeof selectToolTurn(key)).toBe("function");
}