← Back to PRs

#4852: fix(agents): sanitize tool pairing after compaction and history truncation

by lailoo open 2026-01-30 19:16 View on GitHub →
agents
## Summary When compaction prunes older messages or `limitHistoryTurns` truncates history, `tool_result` entries can become orphaned if their matching `tool_use` was removed. This causes `unexpected tool_use_id` API errors. ## Changes ### compaction-safeguard.ts - Call `sanitizeToolUseResultPairing()` after `pruneHistoryForContextShare()` to clean up orphan `tool_result` entries ### history.ts - Call `sanitizeToolUseResultPairing()` after truncating history in `limitHistoryTurns()` ### Tests - Added 2 new tests for `limitHistoryTurns` tool pairing scenarios: - `removes orphan toolResult after truncation` - `preserves valid tool pairs after truncation` ## Root Cause Both compaction and history truncation can remove `assistant` messages containing `tool_use` blocks while leaving their corresponding `tool_result` entries in the retained portion. This creates orphaned `tool_result` entries that reference non-existent `tool_use` blocks. ## Testing - All 17 tests in `compaction-safeguard.test.ts` pass - All 11 tests in `pi-embedded-runner.limithistoryturns.test.ts` pass ## Fixes - #4739 - Compaction drops tool_use but keeps tool_result - #4728 - Session corruption after compaction with tool calls - #4723 - Compaction safeguard leaves orphan tool_result - #3462 - Context compaction breaks tool pairing - #3455 - Compaction causes unexpected tool_use_id error - #4261 - Long session compaction corrupts transcript - #4367 - DM history limit causes orphan tool_result - #4323 - limitHistoryTurns breaks tool pairing - #4650 - History truncation leaves orphan tool_result <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR hardens transcript integrity by running `sanitizeToolUseResultPairing()` after two history-shaping operations: compaction pruning (`pruneHistoryForContextShare`) and DM history truncation (`limitHistoryTurns`). This prevents “orphan” `toolResult` entries whose matching `toolCall/tool_use` messages were removed, which can trigger strict-provider API errors like `unexpected tool_use_id`. Changes are localized to the compaction safeguard extension and embedded runner history logic, plus two new unit tests covering tool pairing behavior during truncation. <h3>Confidence Score: 4/5</h3> - This PR is safe to merge with low risk; it adds a focused repair step after truncation/pruning and includes targeted tests. - Core change is a small call-site addition to an existing transcript-repair utility in two places that can create orphan tool results. Behavior is consistent with existing repair semantics (dropping free-floating tool results). Only notable concern is that one new test doesn’t strongly assert correct pairing/order, so a narrow regression could slip through. - src/agents/pi-embedded-runner.limithistoryturns.test.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs