← Back to PRs

#2557: fix(agents): preserve tool call/result pairing in history limiting

by steve-rodri open 2026-01-27 03:45 View on GitHub →
agents
## Problem The `limitHistoryTurns()` function in `src/agents/pi-embedded-runner/history.ts` was slicing conversation history without considering tool call/result pairing. When limiting history to the last N user turns, it could cut off tool results from their corresponding assistant tool calls, causing Anthropic API validation errors: ``` LLM request rejected: messages.266.content.1: unexpected tool_use_id found in tool_result blocks: toolu_01K7ZFJdfEDqTsKuikvRRfmi. Each tool_result block must have a corresponding tool_use block in the previous message. ``` ## Solution Modified `limitHistoryTurns()` to be tool-call-aware: 1. Added `hasToolCalls()` helper to detect assistants with tool calls 2. Added `countFollowingToolResults()` helper to count tool results 3. Before slicing at a boundary, check if there's a `toolResult` message immediately before the slice point 4. If found, walk back through consecutive tool results to find the corresponding assistant 5. Adjust the slice point to include the complete assistant + tool results sequence ## Impact This ensures tool call/result pairs stay together when limiting history via `dmHistoryLimit` config, preventing the Anthropic API validation error. ## Testing - Existing `limithistoryturns` tests pass - Fix verified to resolve the reported error <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR updates `limitHistoryTurns()` (`src/agents/pi-embedded-runner/history.ts`) to avoid slicing conversation history in a way that separates an assistant tool-call turn from its subsequent `toolResult` messages, which can cause strict provider validation errors. The new logic detects when the slice boundary would start immediately after one or more trailing `toolResult` messages and moves the slice start backward to include the corresponding assistant tool-call message as well. <h3>Confidence Score: 4/5</h3> - This PR is likely safe to merge and should reduce tool pairing validation errors, with minor edge-case coverage gaps. - The change is localized to history slicing and doesn’t affect core execution paths beyond deciding the slice start index. Main risk is behavioral mismatch in uncommon transcript shapes (e.g., toolResult blocks not immediately adjacent to the slice boundary, or tool call detection not matching all variants), plus a small amount of dead code left behind. - src/agents/pi-embedded-runner/history.ts <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</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