Describe the bug
When a session hits the token limit and compaction triggers, the BasicTruncator removes messages from the front of the conversation history without accounting for tool_use/tool_result pairs that straddle the truncation boundary. This leaves tool_result blocks in the remaining history with no corresponding tool_use, which causes the Anthropic API to reject the request with:
CAPIError: 400 tool call must have a tool call ID and function name
The session then gets into an unrecoverable loop — every subsequent prompt or manual /compact attempt hits the same error.
Affected version
GitHub Copilot CLI 1.0.21
Steps to reproduce the behavior
Hard to reproduce reliably, but the conditions are:
- Run a long session until it approaches the token limit.
- A new prompt triggers automatic compaction.
- The BasicTruncator removes N messages, where the cut happens to split an
assistant message (containing tool_use blocks) from its corresponding
tool.execution_complete results.
- The Anthropic API returns 400 "tool call must have a tool call ID and function
name" during compaction.
- Every subsequent prompt or /compact triggers the same failure loop.
Note: though the error message comes from the Anthropic API, the root cause (BasicTruncator not preserving tool_use/tool_result pairs) is model-agnostic and produces a similar error with OpenAI models.
Expected behavior
The truncator should keep tool_use/tool_result pairs together. When removing messages from the front of the history, it should either:
(a) also remove any subsequent tool_result messages belonging to removed tool_use blocks, or
(b) stop the truncation boundary just before a tool_use block so the pair stays intact.
Additional context
OS: Windows
Shell: PowerShell 7
Terminal: Windows Terminal
CPU: x86_64
The session.db and events.jsonl from the broken session show 176 tool_use calls and 176 tool_results total, but after truncation removed 62 messages, 3 tool_result messages were left without their corresponding tool_use.
Describe the bug
When a session hits the token limit and compaction triggers, the BasicTruncator removes messages from the front of the conversation history without accounting for tool_use/tool_result pairs that straddle the truncation boundary. This leaves tool_result blocks in the remaining history with no corresponding tool_use, which causes the Anthropic API to reject the request with:
CAPIError: 400 tool call must have a tool call ID and function name
The session then gets into an unrecoverable loop — every subsequent prompt or manual /compact attempt hits the same error.
Affected version
GitHub Copilot CLI 1.0.21
Steps to reproduce the behavior
Hard to reproduce reliably, but the conditions are:
assistant message (containing tool_use blocks) from its corresponding
tool.execution_complete results.
name" during compaction.
Note: though the error message comes from the Anthropic API, the root cause (BasicTruncator not preserving tool_use/tool_result pairs) is model-agnostic and produces a similar error with OpenAI models.
Expected behavior
The truncator should keep tool_use/tool_result pairs together. When removing messages from the front of the history, it should either:
(a) also remove any subsequent tool_result messages belonging to removed tool_use blocks, or
(b) stop the truncation boundary just before a tool_use block so the pair stays intact.
Additional context
OS: Windows
Shell: PowerShell 7
Terminal: Windows Terminal
CPU: x86_64
The session.db and events.jsonl from the broken session show 176 tool_use calls and 176 tool_results total, but after truncation removed 62 messages, 3 tool_result messages were left without their corresponding tool_use.