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>
This commit is contained in:
safeer
2026-08-20 15:32:18 -03:00
committed by Markus Hartung
parent abfbafe20b
commit e5edb1a69b

View File

@@ -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))