// 客户端请求头:5 个模式(recommended / disabled / claude-code / codex-cli / custom)。 // ClaudeCode profile 的 body metadata 信号由 ../claude-code-compat.ts 在请求发送前补齐。 // // [喵喵喵]: 内置值由私有抓包工具生成,公开插件不携带捕获能力 (2026-07-26) import { cloneStringRecord, hasStringRecordEntries } from "../common.ts"; import { t } from "../i18n.ts"; import type { ApiKind, BuiltInClientHeaderProfileId, ClientHeaderProfileId, CompatSettings, StoredClientHeaderCapture } from "../types.ts"; import { CLAUDE_CODE_CLIENT_HEADERS, CODEX_CLI_CLIENT_HEADERS } from "./builtin-client-headers.ts"; const ANTHROPIC_INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14"; export function getClientHeaderProfileLabel(profile: ClientHeaderProfileId): string { if (profile === "recommended") return t("自动推荐"); if (profile === "disabled") return t("不添加"); if (profile === "custom") return t("自定义请求头"); return profile === "claude-code" ? "ClaudeCode" : "Codex"; } function removeAnthropicBetaFeature(headers: Record, feature: string): void { const betaHeaderKey = Object.keys(headers).find((name) => name.toLowerCase() === "anthropic-beta"); if (!betaHeaderKey) return; const retained = headers[betaHeaderKey]! .split(",") .map((value) => value.trim()) .filter((value) => value && value !== feature); if (retained.length > 0) headers[betaHeaderKey] = retained.join(","); else delete headers[betaHeaderKey]; } function cloneHeadersForCompat( headers: Record, api: ApiKind, compat?: CompatSettings, ): Record { const cloned = cloneStringRecord(headers); if (api === "anthropic-messages" && compat?.forceAdaptiveThinking === true) { removeAnthropicBetaFeature(cloned, ANTHROPIC_INTERLEAVED_THINKING_BETA); } return cloned; } function deleteHeaderCaseInsensitive(headers: Record, name: string): void { const normalized = name.toLowerCase(); for (const existingName of Object.keys(headers)) { if (existingName.toLowerCase() === normalized) delete headers[existingName]; } } /** 模型原生 headers 先保留,插件 profile 对同名字段拥有最终覆盖权。 */ export function mergeModelRequestHeaders( nativeHeaders: Record | undefined, profileHeaders: Record | undefined, ): Record | undefined { const merged = cloneStringRecord(nativeHeaders); for (const [name, value] of Object.entries(profileHeaders ?? {})) { deleteHeaderCaseInsensitive(merged, name); merged[name] = value; } return hasStringRecordEntries(merged) ? merged : undefined; } /** 读取 models.json 时剥离当前 profile 管理的字段,避免把生成值误当作用户原生 headers。 */ export function stripManagedClientHeaders( storedHeaders: Record | undefined, profileHeaders: Record | undefined, ): Record | undefined { const nativeHeaders = cloneStringRecord(storedHeaders); for (const name of Object.keys(profileHeaders ?? {})) deleteHeaderCaseInsensitive(nativeHeaders, name); return hasStringRecordEntries(nativeHeaders) ? nativeHeaders : undefined; } function getRecommendedClientHeaderProfile(api: ApiKind): ClientHeaderProfileId { if (api === "anthropic-messages") return "claude-code"; if (api === "openai-completions" || api === "openai-responses") return "codex-cli"; return "disabled"; } export function resolveClientHeaderProfile(profile: ClientHeaderProfileId, api: ApiKind): ClientHeaderProfileId { return profile === "recommended" ? getRecommendedClientHeaderProfile(api) : profile; } export function getClientHeadersForProfile( profile: ClientHeaderProfileId, api: ApiKind, customHeaders: Record, clientHeaderCaptures: Partial> = {}, compat?: CompatSettings, ): Record | undefined { const resolved = resolveClientHeaderProfile(profile, api); if (resolved === "disabled") return undefined; if (resolved === "claude-code") { const headers = hasStringRecordEntries(clientHeaderCaptures[resolved]?.headers) ? clientHeaderCaptures[resolved]!.headers : CLAUDE_CODE_CLIENT_HEADERS; return cloneHeadersForCompat(headers, api, compat); } if (resolved === "codex-cli") { const headers = hasStringRecordEntries(clientHeaderCaptures[resolved]?.headers) ? clientHeaderCaptures[resolved]!.headers : CODEX_CLI_CLIENT_HEADERS; return cloneStringRecord(headers); } return hasStringRecordEntries(customHeaders) ? cloneHeadersForCompat(customHeaders, api, compat) : undefined; } export function getClientHeaderProfileDisplay(profile: ClientHeaderProfileId, api: ApiKind): string { const resolved = resolveClientHeaderProfile(profile, api); if (profile === "recommended") { return `${getClientHeaderProfileLabel("recommended")} → ${getClientHeaderProfileLabel(resolved)}`; } return getClientHeaderProfileLabel(profile); }