#4009: fix(agent): sanitize messages after orphan user repair
agents
Cluster:
Error Handling in Agent Tools
## Summary
When repairing orphaned trailing user messages, `buildSessionContext()` was called but messages bypassed the sanitization pipeline. This could cause `tool_result` blocks without matching `tool_use` blocks, leading to Anthropic API rejecting requests with "unexpected tool_use_id" errors.
**The fix:** Apply the full sanitization pipeline (`sanitizeSessionHistory`, `validateGeminiTurns`, `validateAnthropicTurns`, `limitHistoryTurns`) to rebuilt messages, matching the behavior of the initial sanitization at lines 502-524.
## Test Plan
- [x] Tested locally with WhatsApp bot that was experiencing this error
- [x] Confirmed the error no longer occurs after the fix
- [x] Linter passes (`npm run lint`)
## AI-Assisted PR 🤖
- [x] **AI-assisted:** This fix was developed with Claude (Opus 4.5)
- [x] **Testing level:** Fully tested - reproduced the bug, applied fix, verified resolution
- [x] **Understanding:** The fix ensures that when messages are rebuilt via `buildSessionContext()` after repairing orphaned user messages, they go through the same sanitization pipeline as the initial message processing, preventing tool_use/tool_result pairing mismatches
### Context
The bug was discovered when a WhatsApp bot session had an aborted request that created a branch in the conversation tree. When linearized, a `toolResult` was included without its corresponding `tool_use` block, causing the Anthropic API to reject the request.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This change fixes a subtle session-repair edge case in `runEmbeddedAttempt()` where rebuilding session context after repairing an orphaned trailing user message would bypass the normal transcript sanitization/validation pipeline. The new code runs rebuilt messages through `sanitizeSessionHistory()`, optional turn validators (`validateGeminiTurns` / `validateAnthropicTurns`), and `limitHistoryTurns()` before calling `activeSession.agent.replaceMessages()`, aligning behavior with the initial session sanitization done earlier in the function.
Overall this should prevent malformed tool_use/tool_result pairings (e.g., orphaned `tool_result` blocks) from reaching provider APIs like Anthropic and causing request rejections ("unexpected tool_use_id").
<h3>Confidence Score: 4/5</h3>
- This PR looks safe to merge and addresses a real failure mode, with low behavioral risk outside the repair path.
- The change is localized and mirrors an existing sanitization/validation pipeline already used earlier in the same function, which reduces the chance of introducing new transcript-format bugs. Main remaining concern is maintainability: the pipeline is duplicated in two places and could drift over time, but that’s not an immediate functional correctness issue.
- src/agents/pi-embedded-runner/run/attempt.ts (keep the duplicated sanitization pipeline in sync with the earlier one)
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#9861: fix(agents): re-run tool_use/tool_result repair after limitHistoryT...
by CyberSinister · 2026-02-05
86.1%
#3647: fix: sanitize tool arguments in session history
by nhangen · 2026-01-29
85.7%
#12487: fix(agents): strip orphaned tool_result when tool_use is sanitized ...
by skylarkoo7 · 2026-02-09
85.5%
#4700: fix: deduplicate tool_use IDs and enable sanitization for Anthropic
by marcelomar21 · 2026-01-30
85.0%
#13831: fix(agents): include Anthropic in tool call ID sanitization
by lailoo · 2026-02-11
84.7%
#8345: fix: prevent synthetic error repair from creating tool_result for d...
by vishaltandale00 · 2026-02-03
84.3%
#17743: fix(agents): disable orphaned user message deletion that causes ses...
by clawrl3000 · 2026-02-16
84.2%
#8270: fix: support snake_case 'tool_use' in transcript repair (#8264)
by heliosarchitect · 2026-02-03
84.0%
#14328: fix: strip incomplete tool_use blocks from errored/aborted messages...
by Kropiunig · 2026-02-12
83.5%
#20538: fix: handle orphaned tool_result errors gracefully instead of leaki...
by echoVic · 2026-02-19
83.3%