Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
516 changes: 258 additions & 258 deletions docs/reference/PROVIDER_REFERENCE.md

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion open-sse/config/providers/registry/kimi/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ export const kimi_webProvider: RegistryEntry = {
alias: "kimi-web",
format: "openai",
executor: "kimi-web",
baseUrl: "https://kimi.moonshot.cn/api/chat",
// International consumer chat — the legacy `kimi.moonshot.cn` domain now
// redirects every non-CN visitor to www.kimi.com, which speaks a different
// Connect-RPC API. See `open-sse/executors/kimi-web.ts` for the wire format.
baseUrl: "https://www.kimi.com",
authType: "apikey",
authHeader: "cookie",
models: [
{ id: "kimi-default", name: "Kimi Default" },
{ id: "kimi-k2.6", name: "Kimi K2.6 (Thinking)" },
{ id: "kimi-128k", name: "Kimi 128K (Long Context)" },
],
};
480 changes: 382 additions & 98 deletions open-sse/executors/kimi-web.ts

Large diffs are not rendered by default.

11 changes: 5 additions & 6 deletions open-sse/services/tokenExtractionConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,13 @@ const RAW_CONFIGS: TokenExtractionConfig[] = [
config(
"kimi-web",
"Kimi (Moonshot)",
"https://kimi.moonshot.cn/",
"https://kimi.moonshot.cn",
"https://www.kimi.com/",
"https://www.kimi.com",
[
{ type: "cookie", name: "kimi_token", domain: ".kimi.moonshot.cn" },
{ type: "localStorage", key: "kimi_token" },
{ type: "cookie", name: "kimi-auth", domain: ".kimi.com" },
],
"Log in to Kimi at kimi.moonshot.cn via phone/WeChat. The session token will be extracted.",
{ cookieDomain: ".kimi.moonshot.cn" }
"Log in to Kimi at www.kimi.com (international). The kimi-auth JWT cookie will be extracted.",
{ cookieDomain: ".kimi.com" }
),

// ── Blackbox Web ──────────────────────────────────────────
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4836,7 +4836,7 @@
"v0VercelWebLabel": "v0 Vercel Web",
"v0VercelWebDesc": "AI code generation via v0.dev",
"kimiWebLabel": "Kimi Web",
"kimiWebDesc": "Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "Doubao Web",
"doubaoWebDesc": "ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/mr.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/ms.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/phi.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/ro.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "v0 Vercel Web",
"v0VercelWebDesc": "Генерация кода ИИ через v0.dev",
"kimiWebLabel": "Kimi Web",
"kimiWebDesc": "Китайский рынок AI чата через kimi.moonshot.cn",
"kimiWebDesc": "Чат Moonshot AI через www.kimi.com (международная версия, Connect-RPC API)",
"doubaoWebLabel": "Doubao Web",
"doubaoWebDesc": "Чат AI ByteDance через doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,7 @@
"v0VercelWebLabel": "__MISSING__:v0 Vercel Web",
"v0VercelWebDesc": "__MISSING__:AI code generation via v0.dev",
"kimiWebLabel": "__MISSING__:Kimi Web",
"kimiWebDesc": "__MISSING__:Chinese market AI chat via kimi.moonshot.cn",
"kimiWebDesc": "__MISSING__:Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "__MISSING__:Doubao Web",
"doubaoWebDesc": "__MISSING__:ByteDance AI chat via doubao.com"
},
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/messages/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -4667,7 +4667,7 @@
"v0VercelWebLabel": "v0 Vercel Web",
"v0VercelWebDesc": "通过 v0.dev 的 AI 代码生成",
"kimiWebLabel": "Kimi Web",
"kimiWebDesc": "通过 kimi.moonshot.cn 访问中国市场的 AI 聊天",
"kimiWebDesc": "通过 www.kimi.com 访问 Moonshot AI 聊天(国际版,Connect-RPC API)",
"doubaoWebLabel": "豆包网",
"doubaoWebDesc": "字节跳动 AI 聊天通过 doubao.com",
"Account Deactivated": "账户已停用",
Expand Down
2 changes: 2 additions & 0 deletions src/lib/providers/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
validateChatGptWebProvider,
validatePerplexityWebProvider,
validateBlackboxWebProvider,
validateKimiWebProvider,
} from "./validation/webProvidersA";
import {
validateMuseSparkWebProvider,
Expand Down Expand Up @@ -349,6 +350,7 @@ export async function validateProviderApiKey({ provider, apiKey, providerSpecifi
"deepseek-web": validateDeepSeekWebProvider,
"grok-web": validateGrokWebProvider,
"qwen-web": validateQwenWebProvider,
"kimi-web": validateKimiWebProvider,
"chatgpt-web": validateChatGptWebProvider,
"perplexity-web": validatePerplexityWebProvider,
"blackbox-web": validateBlackboxWebProvider,
Expand Down
75 changes: 75 additions & 0 deletions src/lib/providers/validation/webProvidersA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,85 @@ import {
buildGrokCookieHeader,
buildQwenCookieHeader,
extractCookieValue,
extractKimiJwt,
extractQwenToken,
normalizeSessionCookieHeader,
} from "@/lib/providers/webCookieAuth";

// kimi-web uses the international `www.kimi.com` Connect-RPC API. The legacy
// `kimi.moonshot.cn` domain now 307-redirects every non-CN visitor, and even
// if you bypass the redirect the old `/api/chat` REST endpoint is gone. The
// SPA exposes a profile probe at `GET /api/user` that returns the user object
// at the top level when the `Authorization: Bearer <JWT>` header is valid.
//
// Auth source: the `kimi-auth` cookie set after login. The user pastes the
// full Cookie header; we extract `kimi-auth` and send it as both the Bearer
// token and a `Cookie: kimi-auth=<jwt>` replay (the latter is what the SPA
// does, though the upstream only consults the Authorization header in
// practice — verified by stripping one of the two at a time).
export async function validateKimiWebProvider({ apiKey }: any) {
const rawCred = String(apiKey ?? "").trim();
if (!rawCred) {
return {
valid: false,
error:
"Missing Kimi session — paste the full Cookie header from www.kimi.com (must contain kimi-auth=<JWT>)",
};
}

const jwt = extractKimiJwt(rawCred);
if (!jwt) {
return {
valid: false,
error:
"Could not find a kimi-auth JWT in the pasted value. Re-login at https://www.kimi.com and copy the full Cookie header.",
};
}

try {
const resp = await fetch("https://www.kimi.com/api/user", {
headers: {
Accept: "application/json, text/plain, */*",
Authorization: `Bearer ${jwt}`,
Cookie: `kimi-auth=${jwt}`,
Origin: "https://www.kimi.com",
Referer: "https://www.kimi.com/",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
},
});

if (resp.status === 401 || resp.status === 403) {
return {
valid: false,
error:
"Kimi session is invalid or expired — re-login at https://www.kimi.com and paste a fresh Cookie header",
};
}
if (!resp.ok) {
return { valid: false, error: `Kimi returned HTTP ${resp.status}` };
}

// Profile response: `{ id, name, email, region, ... }` at the top level.
try {
const data = await resp.json();
if (!data?.id) {
return {
valid: false,
error:
"Kimi session token is invalid or expired — re-login at https://www.kimi.com and paste a fresh Cookie header",
};
}
} catch {
return { valid: false, error: "Kimi returned invalid JSON response" };
}

return { valid: true, error: null };
} catch (error) {
return toValidationErrorResult(error);
}
}

export async function validateDeepSeekWebProvider({ apiKey }: any) {
if (!apiKey) {
return {
Expand Down
32 changes: 32 additions & 0 deletions src/lib/providers/webCookieAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,38 @@ export function extractQwenToken(rawValue: string): string {
return match ? match[1] : "";
}

/**
* Pull the `kimi-auth` JWT out of whatever the user pasted for the
* international Kimi consumer chat (www.kimi.com).
*
* Accepts (all return the same JWT string):
* - bare JWT `eyJhbGci...sig`
* - full Cookie header `_ga=...; kimi-auth=eyJ...; theme=dark`
* - `Cookie:` / `Authorization: Bearer` prefixed forms
* - stray `Bearer eyJ...` without a header label
*
* Returns "" if no JWT can be located.
*/
export function extractKimiJwt(rawValue: string): string {
const trimmed = stripCookieInputPrefix(rawValue);
if (!trimmed) return "";

// Bare JWT — three base64url segments separated by dots.
if (/^eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(trimmed)) {
return trimmed;
}

// Cookie-style pair: pull `kimi-auth=<value>` out of the blob.
const match = trimmed.match(/(?:^|[\s;])kimi-auth=([^;\s]+)/);
if (match) return match[1];

// Last resort: a `Bearer <jwt>` pasted without the header label.
const bearer = trimmed.match(/bearer\s+(eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)/i);
if (bearer) return bearer[1];

return "";
}

export function normalizeSessionCookieHeaders(
rawValues: Array<string | null | undefined>,
defaultCookieName: string
Expand Down
4 changes: 2 additions & 2 deletions src/shared/constants/providers/web-cookie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ export const WEB_COOKIE_PROVIDERS = {
icon: "auto_awesome",
color: "#2563EB",
textIcon: "KW",
website: "https://kimi.moonshot.cn",
authHint: "Paste your session cookie from kimi.moonshot.cn (DevTools → Application → Cookies)",
website: "https://www.kimi.com",
authHint: "Paste your Cookie header from www.kimi.com (must contain kimi-auth=...). Find it via DevTools → Network → request → Cookie.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
Expand Down
6 changes: 3 additions & 3 deletions src/shared/providers/webSessionCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ export const WEB_SESSION_CREDENTIAL_REQUIREMENTS = {
},
"kimi-web": {
kind: "cookie",
credentialName: "session",
placeholder: "session=... or full Cookie header from kimi.moonshot.cn",
credentialName: "kimi-auth",
placeholder: "kimi-auth=eyJ... (full Cookie header from www.kimi.com)",
acceptsFullCookieHeader: true,
storageKeys: ["cookie", "session"],
storageKeys: ["cookie", "kimi-auth", "session"],
},
"doubao-web": {
kind: "cookie",
Expand Down
18 changes: 11 additions & 7 deletions tests/snapshots/provider/translate-path.json
Original file line number Diff line number Diff line change
Expand Up @@ -2277,23 +2277,27 @@
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Accept": "*/*",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
"Content-Type": "application/connect+json",
"connect-protocol-version": "1"
},
"nonStream": {
"Accept": "*/*",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
"Content-Type": "application/connect+json",
"connect-protocol-version": "1"
},
"oauth": {
"Accept": "text/event-stream",
"Accept": "*/*",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
"Content-Type": "application/connect+json",
"connect-protocol-version": "1"
}
},
"url": {
"nonStream": "https://kimi.moonshot.cn/api/chat",
"stream": "https://kimi.moonshot.cn/api/chat"
"nonStream": "https://www.kimi.com/apiv2/kimi.gateway.chat.v1.ChatService/Chat",
"stream": "https://www.kimi.com/apiv2/kimi.gateway.chat.v1.ChatService/Chat"
}
},
"kiro": {
Expand Down
Loading
Loading