Skip to content

[BUG] Pi extension double-compresses RTK-truncated tool results #3056

Description

Summary

The proposed provider-independent Pi extension in #2657 can double-compress tool results already compacted or truncated by pi-rtk-optimizer.

This does not mean RTK and Headroom cannot coexist: the hooks and /v1/compress contract work together. The problem is that Headroom does not recognize RTK's compaction metadata, so it treats an already-lossy RTK result as a fresh compression candidate.

Versions

Reproduction

  1. Use RTK's default output-compaction configuration (truncate.maxChars: 12000).
  2. Run a large bash command that emits log output (example: 2,000 repetitive structured log lines, 262,369 characters).
  3. RTK's tool_result hook changes the result to 12,000 characters and returns metadata equivalent to:
{
  "rtkCompaction": {
    "applied": true,
    "techniques": ["truncate"],
    "truncated": true,
    "originalCharCount": 262369,
    "compactedCharCount": 12000
  },
  "metadata": {
    "rtkCompaction": {
      "applied": true,
      "techniques": ["truncate"],
      "truncated": true
    }
  }
}
  1. Pass that Pi toolResult through the candidate policy in feat(integrations): add provider-independent Pi/OMP extension #2657.
  2. The candidate is still accepted because hasPruningMetadata() only checks top-level prunedAt/pruned and details.truncation.truncated; it does not inspect details.rtkCompaction.truncated or details.metadata.rtkCompaction.truncated.
  3. The candidate is sent to /v1/compress and accepted again.

Observed result with the current proxy:

original: 262369 chars
RTK:      12000 chars  (technique: truncate)
Headroom: 10698 chars  (tokens_saved: 837, transform: router:search:0.79)

The Headroom Pi bridge's validateCompression() accepts this result, so the model-facing context is compressed a second time. The CCR/retrieval path cannot restore bytes that RTK already removed.

A second error-log fixture produced:

RTK:      12000 chars  (technique: truncate)
Headroom: 10515 chars  (tokens_saved: 990, transform: router:log:0.73)

Expected behavior

Headroom should detect that the candidate was already lossily compacted by RTK and, by default, skip it or apply an explicit, documented composition policy. It should not silently perform a second lossy transformation on a result whose source has already been truncated.

RTK's command rewriting and ordinary non-truncated output should remain eligible for Headroom compression.

Suggested fix

Extend the Pi policy's pruning/compaction metadata detection to recognize RTK's shape, including both locations RTK writes:

  • details.rtkCompaction.truncated === true
  • details.metadata.rtkCompaction.truncated === true

Add a regression test using an RTK-shaped toolResult and assert that candidateFromToolResult() returns undefined. A separate test can confirm that non-truncated RTK aggregation remains configurable/eligible.

Related: #2657, #645.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions