diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index fc9b5403be..5bb6cbe288 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -1226,7 +1226,7 @@ export async function handleChatCore({ const allMessages = body?.messages || body?.input || body?.contents || body?.request?.contents || []; if (body && Array.isArray(allMessages) && allMessages.length > 0) { - const estimatedTokens = estimateTokens(JSON.stringify(allMessages)); + let estimatedTokens = estimateTokens(JSON.stringify(allMessages)); let contextLimit = getTokenLimit(provider, effectiveModel); if (isCombo && comboName) { @@ -1271,7 +1271,7 @@ export async function handleChatCore({ // Prompt compression pipeline — Phase 1 (lite) + Phase 2 (standard/caveman) try { const compressionConfig = getCompressionSettings(); - const estimatedTokens = estimateCompressionTokens(body); + estimatedTokens = estimateCompressionTokens(body); const mode = selectCompressionStrategy(compressionConfig, comboName ?? null, estimatedTokens); if (mode !== "off") { const compressionResult = applyCompression(body as Record, mode, { @@ -1281,6 +1281,7 @@ export async function handleChatCore({ if (compressionResult.compressed && compressionResult.stats) { body = compressionResult.body as typeof body; const s = compressionResult.stats; + estimatedTokens = s.compressedTokens; log?.info?.( "COMPRESSION", `Prompt compression (${s.mode}): ${s.originalTokens} → ${s.compressedTokens} tokens (${s.savingsPercent}% savings, ${s.durationMs ?? 0}ms${ diff --git a/open-sse/services/compression/aggressive.ts b/open-sse/services/compression/aggressive.ts index d1091aa914..8e2d3e85c4 100644 --- a/open-sse/services/compression/aggressive.ts +++ b/open-sse/services/compression/aggressive.ts @@ -121,7 +121,7 @@ export function compressAggressive( preserveCode: true, }); if (summary && summary.length < text.length) { - summarizerSavings += text.length - summary.length; + summarizerSavings += estimateTokens(text) - estimateTokens(summary); return setContent(msg, `[COMPRESSED:summary] ${summary}`); } return msg; @@ -172,11 +172,11 @@ export function compressAggressive( } } - resultStats.techniquesUsed = [ + resultStats.techniquesUsed.push( ...(toolResultSavings > 0 ? ["toolResult"] : []), ...(agingSavings > 0 ? ["aging"] : []), - ...(summarizerSavings > 0 ? ["summarizer"] : []), - ]; + ...(summarizerSavings > 0 ? ["summarizer"] : []) + ); resultStats.aggressive = { summarizerSavings, diff --git a/open-sse/services/compression/progressiveAging.ts b/open-sse/services/compression/progressiveAging.ts index 138896fe68..2b742ecf9f 100644 --- a/open-sse/services/compression/progressiveAging.ts +++ b/open-sse/services/compression/progressiveAging.ts @@ -5,6 +5,10 @@ import { cavemanCompress } from "./caveman.ts"; const COMPRESSED_MARKER_RE = /^\[COMPRESSED:/; +function estimateTokens(text: string): number { + return Math.ceil(text.length / 4); +} + interface ChatMessage { role: string; content?: string | Array<{ type: string; text?: string }>; @@ -73,7 +77,7 @@ export function applyAging( ? compressed.body.messages[0].content : extractText(compressed.body.messages[0].content); const tagged = `[COMPRESSED:aging:light] ${newContent}`; - saved += text.length - tagged.length; + saved += estimateTokens(text) - estimateTokens(tagged); result.push(setContent(msg, tagged)); } else { result.push(msg); @@ -86,7 +90,7 @@ export function applyAging( ? compressed.body.messages[0].content : extractText(compressed.body.messages[0].content); const tagged = `[COMPRESSED:aging:moderate] ${newContent}`; - saved += text.length - tagged.length; + saved += estimateTokens(text) - estimateTokens(tagged); result.push(setContent(msg, tagged)); } else { result.push(msg); @@ -95,12 +99,12 @@ export function applyAging( if (msg.role === "assistant") { const summary = sum.summarize([msg]); const tagged = `[COMPRESSED:aging:fullSummary] ${summary}`; - saved += text.length - tagged.length; + saved += estimateTokens(text) - estimateTokens(tagged); result.push(setContent(msg, tagged)); } else if (msg.role === "user") { const firstLine = text.split("\n")[0]?.slice(0, 120) ?? ""; const tagged = `[COMPRESSED:aging:fullSummary] ${firstLine}`; - saved += text.length - tagged.length; + saved += estimateTokens(text) - estimateTokens(tagged); result.push(setContent(msg, tagged)); } else { result.push(msg); diff --git a/open-sse/services/compression/toolResultCompressor.ts b/open-sse/services/compression/toolResultCompressor.ts index 743dbaa940..573fb592a3 100644 --- a/open-sse/services/compression/toolResultCompressor.ts +++ b/open-sse/services/compression/toolResultCompressor.ts @@ -110,41 +110,63 @@ function compressErrorMessage(content: string): string | null { return result; } -export function compressToolResult(content: string, opts: ToolStrategiesConfig): CompressionResult { - const originalLen = content.length; +function estimateTokens(text: string): number { + return Math.ceil(text.length / 4); +} +export function compressToolResult(content: string, opts: ToolStrategiesConfig): CompressionResult { if (opts.fileContent) { const result = compressFileContent(content); if (result !== null) { - return { compressed: result, strategy: "fileContent", saved: originalLen - result.length }; + return { + compressed: result, + strategy: "fileContent", + saved: estimateTokens(content) - estimateTokens(result), + }; } } if (opts.grepSearch) { const result = compressGrepSearch(content); if (result !== null) { - return { compressed: result, strategy: "grepSearch", saved: originalLen - result.length }; + return { + compressed: result, + strategy: "grepSearch", + saved: estimateTokens(content) - estimateTokens(result), + }; } } if (opts.shellOutput) { const result = compressShellOutput(content); if (result !== null) { - return { compressed: result, strategy: "shellOutput", saved: originalLen - result.length }; + return { + compressed: result, + strategy: "shellOutput", + saved: estimateTokens(content) - estimateTokens(result), + }; } } if (opts.json) { const result = compressJson(content); if (result !== null) { - return { compressed: result, strategy: "json", saved: originalLen - result.length }; + return { + compressed: result, + strategy: "json", + saved: estimateTokens(content) - estimateTokens(result), + }; } } if (opts.errorMessage) { const result = compressErrorMessage(content); if (result !== null) { - return { compressed: result, strategy: "errorMessage", saved: originalLen - result.length }; + return { + compressed: result, + strategy: "errorMessage", + saved: estimateTokens(content) - estimateTokens(result), + }; } }