#11825: fix: keep tool_use/tool_result pairs together during session compaction
agents
stale
Cluster:
Error Handling in Agent Tools
## Problem
When sessions get summarized to save tokens, the chunking functions (`splitMessagesByTokenShare`, `chunkMessagesByMaxTokens`) split messages purely by token count without considering Anthropic's API requirement that `tool_use` blocks must be immediately followed by matching `tool_result` messages.
This causes the error:
```
unexpected tool_use_id found in tool_result blocks
```
### Root Cause
1. `splitMessagesByTokenShare()` splits at token boundaries
2. `chunkMessagesByMaxTokens()` splits at token boundaries
When a split happens between an assistant message (containing `tool_use`) and its corresponding `tool_result`:
- The `tool_use` gets summarized away
- The `tool_result` remains with an ID referencing a non-existent tool call
- Anthropic API rejects the malformed transcript
## Solution
Added helper functions and modified the chunking logic:
### New Helper Functions
```typescript
hasPendingToolCalls(message) // Detects assistant messages with tool calls
isToolResultMessage(message) // Detects tool_result messages
```
### Modified Functions
**`splitMessagesByTokenShare`** - Now checks before splitting:
- Won't split if previous message has pending tool calls
- Won't split if current message is a tool_result
**`chunkMessagesByMaxTokens`** - Same guards as above
## Testing
Added comprehensive tests:
- ✅ Verifies tool_use and tool_result stay in the same chunk
- ✅ Verifies chunks never start with tool_result
- ✅ Tests both `splitMessagesByTokenShare` and `chunkMessagesByMaxTokens`
## Backwards Compatibility
- No API changes
- No configuration changes
- Existing sessions work correctly
- Chunks may be slightly larger in edge cases (tool pairs kept together)
The existing `repairToolUseResultPairing` in `pruneHistoryForContextShare` provides defense-in-depth, but preventing bad splits is more robust.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
Updates the session compaction chunking logic to avoid splitting between `tool_use` and the corresponding `tool_result` message, which can create malformed transcripts rejected by the Anthropic API. This is done by adding helpers to detect assistant tool-call blocks and tool-result messages, then guarding split points in both `splitMessagesByTokenShare` and `chunkMessagesByMaxTokens`. Adds unit tests intended to assert that chunks don’t begin with `toolResult` and that tool-use/result pairs remain co-located.
<h3>Confidence Score: 4/5</h3>
- Mostly safe to merge, but one test issue can mask regressions.
- The production change is localized and the new split guards are straightforward, but the added tests currently identify the tool-use chunk too broadly (any assistant message), so they can pass even if pairing is broken. Fixing the test predicates would better validate the intended invariant.
- src/agents/compaction.test.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#14328: fix: strip incomplete tool_use blocks from errored/aborted messages...
by Kropiunig · 2026-02-12
86.0%
#13062: fix: remove orphaned tool_result blocks from user message content d...
by trevorgordon981 · 2026-02-10
86.0%
#21195: fix: suppress orphaned tool_use/tool_result errors after session co...
by ruslansychov-git · 2026-02-19
84.8%
#6687: fix(session-repair): strip malformed tool_use blocks to prevent per...
by NSEvent · 2026-02-01
84.7%
#4700: fix: deduplicate tool_use IDs and enable sanitization for Anthropic
by marcelomar21 · 2026-01-30
84.7%
#4844: fix(agents): skip error/aborted assistant messages in transcript re...
by lailoo · 2026-01-30
84.6%
#4852: fix(agents): sanitize tool pairing after compaction and history tru...
by lailoo · 2026-01-30
84.5%
#8270: fix: support snake_case 'tool_use' in transcript repair (#8264)
by heliosarchitect · 2026-02-03
84.3%
#15050: fix: transcript corruption resilience — strip aborted tool_use bloc...
by yashchitneni · 2026-02-12
84.2%
#20538: fix: handle orphaned tool_result errors gracefully instead of leaki...
by echoVic · 2026-02-19
84.0%