feat(tools): collapse-consecutive-duplicates compression rule

adr-0003 §1.3 dedup: collapse runs of identical adjacent lines into `line (×N)`, order-preserving and lossless (count retained). Wired into ShellTool's default spec before HeadTail so the head/tail window holds distinct content. Safe as a default, unlike DropMatching.
This commit is contained in:
2026-06-02 13:57:57 +04:00
parent 198cf95725
commit 97ad456778
4 changed files with 60 additions and 2 deletions
@@ -2,6 +2,7 @@ package com.correx.infrastructure.tools.shell
import com.correx.core.approvals.Tier
import com.correx.core.events.events.ToolRequest
import com.correx.core.tools.compression.CompressionRule.CollapseConsecutiveDuplicates
import com.correx.core.tools.compression.CompressionRule.HeadTail
import com.correx.core.tools.compression.CompressionRule.StripBlankLines
import com.correx.core.tools.compression.DeclarativeCompressor
@@ -50,7 +51,14 @@ class ShellTool(
setOf(ToolCapability.SHELL_EXEC, ToolCapability.PROCESS_SPAWN)
override val paramRoles: Map<String, ParamRole> = mapOf("argv" to ParamRole.EXEC_COMMAND)
override val outputCompressor: ToolOutputCompressor = DeclarativeCompressor(
OutputCompressionSpec(listOf(StripBlankLines, HeadTail(HEAD_LINES, TAIL_LINES)), bypassOnError = true),
OutputCompressionSpec(
// Collapse repeated identical lines (retries, warning spam) before truncating, so the
// head/tail window holds distinct content rather than duplicates. Dedup is lossless
// (count is preserved) and order-preserving, so it is safe as a default — unlike a
// progress-dropping regex, which can silently eat real output.
listOf(StripBlankLines, CollapseConsecutiveDuplicates, HeadTail(HEAD_LINES, TAIL_LINES)),
bypassOnError = true,
),
)
override fun validateRequest(request: ToolRequest): ValidationResult {