160 lines
4.7 KiB
TypeScript
160 lines
4.7 KiB
TypeScript
export const DETAIL_KIMI_THINKING_HEADER = "x-detail-agent-kimi-thinking";
|
|
export const DETAIL_KIMI_PROFILE_HEADER = "x-detail-agent-kimi-profile";
|
|
|
|
export type DetailKimiThinkingMode = "enabled" | "disabled";
|
|
export type DetailKimiPurpose = "plan" | "preflight" | "review" | "repair";
|
|
|
|
export type DetailKimiGenerateOptions = {
|
|
temperature?: number;
|
|
topP?: number;
|
|
maxTokens?: number;
|
|
headers?: Record<string, string>;
|
|
};
|
|
|
|
const KIMI_K26_PATTERN = /^kimi[-_.]?k2\.6(?:\b|[-_.])/i;
|
|
const KIMI_DETAIL_MODEL_PATTERN =
|
|
/^(?:kimi[-_.]?k2\.(?:6|7)(?:\b|[-_.])|kimi-for-coding$)/i;
|
|
const MOONSHOT_BASE_URL_PATTERN =
|
|
/moonshot\.(?:cn|ai)|api\.kimi\.com\/coding|kimi\.com/i;
|
|
|
|
export function isKimiK26ModelId(value: unknown) {
|
|
return KIMI_K26_PATTERN.test(String(value || "").trim());
|
|
}
|
|
|
|
export function isKimiDetailModelId(value: unknown) {
|
|
return KIMI_DETAIL_MODEL_PATTERN.test(String(value || "").trim());
|
|
}
|
|
|
|
export function isMoonshotOfficialBaseUrl(value: unknown) {
|
|
return MOONSHOT_BASE_URL_PATTERN.test(String(value || "").trim());
|
|
}
|
|
|
|
function normalizeThinkingMode(value: unknown): DetailKimiThinkingMode | null {
|
|
const normalized = String(value || "").trim().toLowerCase();
|
|
if (normalized === "enabled" || normalized === "on" || normalized === "true") {
|
|
return "enabled";
|
|
}
|
|
if (normalized === "disabled" || normalized === "off" || normalized === "false") {
|
|
return "disabled";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function getPurposeThinkingMode(purpose: DetailKimiPurpose): DetailKimiThinkingMode {
|
|
if (purpose === "plan" || purpose === "repair") return "enabled";
|
|
return "disabled";
|
|
}
|
|
|
|
function getPurposeMaxTokens(params: {
|
|
purpose: DetailKimiPurpose;
|
|
generationMode?: string | null;
|
|
}) {
|
|
if (params.purpose === "plan") {
|
|
return params.generationMode === "agent_layout" ? 16_000 : 10_000;
|
|
}
|
|
if (params.purpose === "repair") return 8_000;
|
|
if (params.purpose === "preflight") return 4_096;
|
|
return 3_000;
|
|
}
|
|
|
|
export function shouldUseKimiDetailProfile(params: {
|
|
modelId?: string | null;
|
|
providerBaseUrl?: string | null;
|
|
isLocalMoonshot?: boolean;
|
|
}) {
|
|
if (!isKimiDetailModelId(params.modelId)) return false;
|
|
return Boolean(params.isLocalMoonshot) || isMoonshotOfficialBaseUrl(params.providerBaseUrl);
|
|
}
|
|
|
|
export function buildDetailKimiGenerateOptions(params: {
|
|
purpose: DetailKimiPurpose;
|
|
generationMode?: string | null;
|
|
modelId?: string | null;
|
|
providerBaseUrl?: string | null;
|
|
isLocalMoonshot?: boolean;
|
|
}): DetailKimiGenerateOptions {
|
|
if (!shouldUseKimiDetailProfile(params)) return {};
|
|
|
|
const thinking = getPurposeThinkingMode(params.purpose);
|
|
|
|
return {
|
|
temperature: thinking === "enabled" ? 1 : 0.6,
|
|
topP: 0.95,
|
|
maxTokens: getPurposeMaxTokens(params),
|
|
headers: {
|
|
[DETAIL_KIMI_THINKING_HEADER]: thinking,
|
|
[DETAIL_KIMI_PROFILE_HEADER]: `detail-ui-${params.purpose}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
function toHeaders(headers: HeadersInit | undefined) {
|
|
const next = new Headers();
|
|
if (!headers) return next;
|
|
|
|
if (headers instanceof Headers) {
|
|
headers.forEach((value, key) => next.set(key, value));
|
|
return next;
|
|
}
|
|
|
|
if (Array.isArray(headers)) {
|
|
headers.forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) next.set(key, String(value));
|
|
});
|
|
return next;
|
|
}
|
|
|
|
Object.entries(headers).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) next.set(key, String(value));
|
|
});
|
|
return next;
|
|
}
|
|
|
|
function bodyToString(body: BodyInit | null | undefined) {
|
|
if (!body) return null;
|
|
if (typeof body === "string") return body;
|
|
if (body instanceof Uint8Array) {
|
|
return new TextDecoder().decode(body);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function applyKimiThinkingToBody(params: {
|
|
rawBody: string;
|
|
thinking: DetailKimiThinkingMode | null;
|
|
}) {
|
|
if (!params.thinking) return null;
|
|
|
|
try {
|
|
const body = JSON.parse(params.rawBody) as Record<string, unknown>;
|
|
if (!isKimiK26ModelId(body.model)) return null;
|
|
|
|
return JSON.stringify({
|
|
...body,
|
|
thinking: { type: params.thinking },
|
|
});
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function createMoonshotKimiFetch(baseFetch: typeof fetch = fetch): typeof fetch {
|
|
return async (input, init) => {
|
|
const headers = toHeaders(
|
|
init?.headers || (input instanceof Request ? input.headers : undefined)
|
|
);
|
|
const thinking = normalizeThinkingMode(headers.get(DETAIL_KIMI_THINKING_HEADER));
|
|
headers.delete(DETAIL_KIMI_THINKING_HEADER);
|
|
headers.delete(DETAIL_KIMI_PROFILE_HEADER);
|
|
|
|
const rawBody = bodyToString(init?.body);
|
|
const patchedBody = rawBody ? applyKimiThinkingToBody({ rawBody, thinking }) : null;
|
|
|
|
return baseFetch(input, {
|
|
...init,
|
|
headers,
|
|
body: patchedBody || init?.body,
|
|
});
|
|
};
|
|
}
|