feat: tool-declared output compression (Tier A)
Tools can declare how their output is compressed before it enters the context pack, replacing uniform handling. Open-threads 6.3 / ADR-0003. - core:tools/compression: ToolOutputCompressor interface, IdentityCompressor default, declarative OutputCompressionSpec + CompressionRule (StripBlankLines, StripLeadingWhitespace, DropMatching, HeadTail), and the pure DeclarativeCompressor engine (regexes compiled at construction; bypassOnError passes raw on non-zero exit; never throws on input). - Tool gains `outputCompressor` (default IdentityCompressor). FileReadTool strips blanks + leading whitespace; ShellTool strips blanks + head/tail. - SessionOrchestrator applies the resolved tool's compressor on the ToolResult -> ContextEntry path only. Raw output stays authoritative in the event log (invariant #6); compression is a pure function of (raw, exitCode, spec), so no new event and replay stays deterministic. - Spec is @Serializable/config-shaped (JSON round-trip tested). No custom-tool-from-config path exists today, so first-party tools wire in code; TOML-declared compression rides along when that path lands. Tier B (format-aware parsers: failures-only test output, git-log oneline) is a documented per-tool extension behind the interface, not built here.
This commit is contained in:
+8
@@ -2,6 +2,11 @@ package com.correx.infrastructure.tools.filesystem
|
||||
|
||||
import com.correx.core.approvals.Tier
|
||||
import com.correx.core.events.events.ToolRequest
|
||||
import com.correx.core.tools.compression.CompressionRule.StripBlankLines
|
||||
import com.correx.core.tools.compression.CompressionRule.StripLeadingWhitespace
|
||||
import com.correx.core.tools.compression.DeclarativeCompressor
|
||||
import com.correx.core.tools.compression.OutputCompressionSpec
|
||||
import com.correx.core.tools.compression.ToolOutputCompressor
|
||||
import com.correx.core.tools.contract.ParamRole
|
||||
import com.correx.core.tools.contract.Tool
|
||||
import com.correx.core.tools.contract.ToolCapability
|
||||
@@ -49,6 +54,9 @@ class FileReadTool(
|
||||
override val tier: Tier = Tier.T1
|
||||
override val requiredCapabilities: Set<ToolCapability> = setOf(ToolCapability.FILE_READ)
|
||||
override val paramRoles: Map<String, ParamRole> = mapOf("path" to ParamRole.PATH)
|
||||
override val outputCompressor: ToolOutputCompressor = DeclarativeCompressor(
|
||||
OutputCompressionSpec(listOf(StripBlankLines, StripLeadingWhitespace)),
|
||||
)
|
||||
|
||||
override fun validateRequest(request: ToolRequest): ValidationResult {
|
||||
val pathString = request.parameters["path"] as? String
|
||||
|
||||
+9
@@ -4,6 +4,7 @@ import com.correx.core.events.events.ToolRequest
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.events.types.ToolInvocationId
|
||||
import com.correx.core.tools.compression.ToolOutputContext
|
||||
import com.correx.core.tools.contract.ToolResult
|
||||
import com.correx.core.tools.contract.ValidationResult
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -109,4 +110,12 @@ class FileReadToolTest {
|
||||
val failure = result as ToolResult.Failure
|
||||
assertTrue(failure.reason.contains("is not in the allowed list"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `outputCompressor strips blank lines and leading whitespace`() {
|
||||
val tool = FileReadTool()
|
||||
val raw = " fun main() {\n\n println()\n }\n"
|
||||
val compressed = tool.outputCompressor.compress(raw, ToolOutputContext(exitCode = 0))
|
||||
assertEquals("fun main() {\nprintln()\n}", compressed)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user