From e5edb1a69bc76acab10347b928593f24abf3571d Mon Sep 17 00:00:00 2001 From: safeer Date: Thu, 20 Aug 2026 15:32:18 -0300 Subject: [PATCH] fix(compression): restore #9144 code-preservation guard dropped by the regex rewrite The regex rewrite of cleanupArtifacts removed isCodeDominantText and its call site in cavemanCompress, which was the #9144 guard against recapitalizing unfenced code as prose (function -> Function, var -> Var). Restores the guard on top of the new regex-based cleanupArtifacts/normalizeMessageWhitespace, so the performance gain is kept without reintroducing the #9144 regression. Caught by tests/unit/compression/caveman-file-reference-9144.test.ts, which passes on origin/release/v3.8.50 and failed after this PR's own change. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --- open-sse/services/compression/caveman.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/open-sse/services/compression/caveman.ts b/open-sse/services/compression/caveman.ts index 3248f0b5ee..c629cb125e 100644 --- a/open-sse/services/compression/caveman.ts +++ b/open-sse/services/compression/caveman.ts @@ -12,6 +12,7 @@ import { createCompressionStats, estimateCompressionTokens } from "./stats.ts"; import { validateCompression } from "./validation.ts"; import { mapTextContent } from "./messageContent.ts"; import { detectCompressionLanguage } from "./languageDetector.ts"; +import { isCodeLikeLine } from "./toolResultCompressor.ts"; interface ChatMessage { role: string; @@ -214,6 +215,22 @@ function cleanupArtifacts(text: string): string { .replace(/\n+$/, ""); } +/** + * #9144: raw (unfenced) multi-line code — e.g. a Copilot `#file` reference — was + * getting whitespace-collapsed and sentence-recapitalized as if it were prose, + * corrupting keyword/identifier casing (`function`→`Function`) and indentation. + * Preservation only protects explicitly fenced/marked blocks; this catches the + * unfenced case by requiring a strong majority of lines to look like code before + * skipping prose normalization for the whole span — conservative on purpose + * (biases toward less compression, never toward destructive mutation). + */ +function isCodeDominantText(text: string): boolean { + const lines = text.split("\n").filter((line) => line.trim().length > 0); + if (lines.length < 3) return false; + const codeLikeCount = lines.filter(isCodeLikeLine).length; + return codeLikeCount / lines.length >= 0.3; +} + function recapitalizeSentences(text: string): string { return text.replace(/(^|[.!?][ \t]|\n[ \t]*)([a-z])/g, (_match, prefix: string, char: string) => { return `${prefix}${char.toUpperCase()}`; @@ -367,7 +384,9 @@ export function cavemanCompress( const { text: rulesApplied, appliedRules } = applyRulesToText(extractedText, rules); allAppliedRules.push(...appliedRules); - const normalized = recapitalizeSentences(cleanupArtifacts(rulesApplied)); + const normalized = isCodeDominantText(rulesApplied) + ? rulesApplied + : recapitalizeSentences(cleanupArtifacts(rulesApplied)); const cleaned = blocks.length > 0 ? cleanupArtifacts(restorePreservedBlocks(normalized, blocks))