feat: add CastAI/Kimchi model routes via llm.kimchi.dev

Add 5 free Kimchi-dev models through CAST AI gateway:
- minimax-m3, minimax-m2.7
- kimi-k2.6, kimi-k2.7
- nemotron-3-ultra-fp4
- castai-auto (generic -> minimax-m3)

Key details:
- Endpoint: https://llm.kimchi.dev/openai/v1/chat/completions
- Required: User-Agent: kimchi/0.1.41 header
- API key hardcoded from Kimchi CLI config (for Vercel/CF deploy)
- Native SSE streaming passthrough

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-26 01:14:18 +07:00
co-authored by Claude Opus 4.8
parent 3505165a3b
commit 9a379d09b5
+61 -1
View File
@@ -16,6 +16,8 @@ import { fetchWithRetry, fetchWithSessionRetry, SSELineBuffer, isDevMode, trackR
import { getJwt, invalidateJwt } from "./mimo-auth"; import { getJwt, invalidateJwt } from "./mimo-auth";
import { parseDSML, looksLikeDSML } from "./dsml-parser"; import { parseDSML, looksLikeDSML } from "./dsml-parser";
// --- Kimchi API Key (hardcoded untuk deployability di Vercel/CF) --------------
const KIMCHI_API_KEY = "castai_v1_c5b9f4751ccb6c187c7e2f1cb2efbf83ac5d4e22806fd1d7218a0f602fee1777_1d96b89c";
// --- Types ------------------------------------------------------------------- // --- Types -------------------------------------------------------------------
@@ -112,6 +114,56 @@ export const MODEL_ROUTES: Record<string, BackendConfig> = {
}, },
}, },
// -- CastAI via Kimchi gateway (OpenAI-compatible) -----------------------------
// Endpoint: https://llm.kimchi.dev/openai/v1 (via Kimchi CLI's own gateway)
// Key: read from ~/.config/kimchi/config.json (fallback ke env CASTAI_API_KEY)
// User-Agent header required — tanpa ini, Kimchi gateway reject dengan 402.
// Default model: minimax-m3 — model gratis via Kimchi's ai-enabler provider.
// Models available (per 2026-06-25, cost=0 via Kimchi):
// minimax-m3, minimax-m2.5, minimax-m2.7
// kimi-k2.5, kimi-k2.6, kimi-k2.7
// nemotron-3-super-fp4, nemotron-3-ultra-fp4
// qwen3-coder-next-fp8, smollm2-135m, smollm2-360m
// --- CastAI Kimchi gateway configs (shared) --------------------------------
// Each CastAI model points to the same Kimchi gateway, User-Agent is required.
"castai-auto": {
provider: "castai",
url: "https://llm.kimchi.dev/openai/v1/chat/completions",
headers: { "Content-Type": "application/json", "User-Agent": "kimchi/0.1.41" },
adaptRequest: (req) => ({ ...req, model: "minimax-m3" }),
adaptResponse: (raw: any) => raw,
},
"minimax-m3": {
provider: "castai",
url: "https://llm.kimchi.dev/openai/v1/chat/completions",
headers: { "Content-Type": "application/json", "User-Agent": "kimchi/0.1.41" },
adaptResponse: (raw: any) => raw,
},
"minimax-m2.7": {
provider: "castai",
url: "https://llm.kimchi.dev/openai/v1/chat/completions",
headers: { "Content-Type": "application/json", "User-Agent": "kimchi/0.1.41" },
adaptResponse: (raw: any) => raw,
},
"kimi-k2.7": {
provider: "castai",
url: "https://llm.kimchi.dev/openai/v1/chat/completions",
headers: { "Content-Type": "application/json", "User-Agent": "kimchi/0.1.41" },
adaptResponse: (raw: any) => raw,
},
"kimi-k2.6": {
provider: "castai",
url: "https://llm.kimchi.dev/openai/v1/chat/completions",
headers: { "Content-Type": "application/json", "User-Agent": "kimchi/0.1.41" },
adaptResponse: (raw: any) => raw,
},
"nemotron-3-ultra-fp4": {
provider: "castai",
url: "https://llm.kimchi.dev/openai/v1/chat/completions",
headers: { "Content-Type": "application/json", "User-Agent": "kimchi/0.1.41" },
adaptResponse: (raw: any) => raw,
},
// -- Xiaomi MiMo Free (OpenAI-compatible, JWT bootstrap auth) ----------------- // -- Xiaomi MiMo Free (OpenAI-compatible, JWT bootstrap auth) -----------------
"mimo-auto": { "mimo-auto": {
provider: "mimo-free", provider: "mimo-free",
@@ -394,6 +446,14 @@ export async function handleChatCompletion(
}; };
} }
// -- CastAI: inject API key -----------------------------------------------
if (config.provider === "castai") {
init.headers = {
...init.headers,
Authorization: `Bearer ${KIMCHI_API_KEY}`,
};
}
// -- Execute with session-aware or standard retry -------------------------- // -- Execute with session-aware or standard retry --------------------------
let result: FetchWithRetryResult = let result: FetchWithRetryResult =
sessionPool && sessionId sessionPool && sessionId
@@ -450,7 +510,7 @@ export async function handleChatCompletion(
const contentType = response.headers.get("content-type") ?? ""; const contentType = response.headers.get("content-type") ?? "";
const isNativeStream = contentType.includes("text/event-stream"); const isNativeStream = contentType.includes("text/event-stream");
if (isNativeStream && (config.provider === "opencode" || config.provider === "mimo-free")) { if (isNativeStream && (config.provider === "opencode" || config.provider === "mimo-free" || config.provider === "castai")) {
// Passthrough for OpenAI-compatible SSE // Passthrough for OpenAI-compatible SSE
const headers: Record<string, string> = { const headers: Record<string, string> = {
"Content-Type": "text/event-stream", "Content-Type": "text/event-stream",