| import crypto from "crypto"; | |
| interface Message { | |
| role: string; | |
| content: string | unknown[]; | |
| } | |
| interface PrefixAnalysis { | |
| prefixEndIdx: number; | |
| prefixHash: string; | |
| prefixTokens: number; | |
| prefixType: "system_only" | "system_and_tools" | "system_tools_history"; | |
| confidence: number; | |
| } | |
| function normalizeContent(content: string | unknown[]): string { | |
| if (typeof content === "string") return content; | |
| return JSON.stringify(content); | |
| } | |
| function estimateTokens(text: string): number { | |
| return Math.ceil(text.length / 4); | |
| } | |
| export function analyzePrefix(messages: Message[]): PrefixAnalysis { | |
| if (!Array.isArray(messages) || messages.length === 0) { | |
| return { | |
| prefixEndIdx: -1, | |
| prefixHash: "", | |
| prefixTokens: 0, | |
| prefixType: "system_only", | |
| confidence: 0, | |
| }; | |
| } | |
| let prefixEndIdx = -1; | |
| let prefixType: PrefixAnalysis["prefixType"] = "system_only"; | |
| let confidence = 0.5; | |
| for (let i = 0; i < messages.length; i++) { | |
| const msg = messages[i]; | |
| const role = msg.role || "user"; | |
| if (role === "system") { | |
| prefixEndIdx = i; | |
| prefixType = "system_only"; | |
| confidence = 0.9; | |
| } else if (role === "tool" || (role === "assistant" && Array.isArray(msg.content))) { | |
| prefixEndIdx = i; | |
| prefixType = "system_and_tools"; | |
| confidence = 0.8; | |
| } else if (role === "assistant") { | |
| prefixEndIdx = i; | |
| prefixType = "system_tools_history"; | |
| confidence = 0.7; | |
| } else { | |
| break; | |
| } | |
| } | |
| const prefixMessages = messages.slice(0, prefixEndIdx + 1); | |
| const prefixText = prefixMessages.map((m) => normalizeContent(m.content)).join("\n"); | |
| const prefixHash = crypto.createHash("sha256").update(prefixText).digest("hex"); | |
| const prefixTokens = estimateTokens(prefixText); | |
| return { | |
| prefixEndIdx, | |
| prefixHash, | |
| prefixTokens, | |
| prefixType, | |
| confidence, | |
| }; | |
| } | |
| export function shouldInjectCacheControl(analysis: PrefixAnalysis, minTokens = 1024): boolean { | |
| return analysis.prefixTokens >= minTokens && analysis.confidence >= 0.7; | |
| } | |
| export function generatePromptCacheKey(messages: Message[]): string { | |
| const analysis = analyzePrefix(messages); | |
| if (analysis.prefixHash) { | |
| return `omni-${analysis.prefixHash.slice(0, 32)}`; | |
| } | |
| return ""; | |
| } | |