Skip to content

fix: re-run sanitization after limitHistoryTurns to fix orphaned tool results#5032

Closed
shayan919293 wants to merge 1 commit intoopenclaw:mainfrom
shayan919293:fix/post-limit-sanitization
Closed

fix: re-run sanitization after limitHistoryTurns to fix orphaned tool results#5032
shayan919293 wants to merge 1 commit intoopenclaw:mainfrom
shayan919293:fix/post-limit-sanitization

Conversation

@shayan919293
Copy link
Contributor

@shayan919293 shayan919293 commented Jan 30, 2026

Summary

After limitHistoryTurns cuts off older messages, tool_use blocks can be removed while their corresponding tool_result blocks remain, creating orphaned tool results that cause the Anthropic API to reject requests with errors like:

LLM request rejected: messages.18.content.1: unexpected tool_use_id found in tool_result blocks

Similarly, the limiting can create consecutive assistant messages that violate Gemini's format requirements.

Fix

This fix re-runs the sanitization functions after limitHistoryTurns is applied:

  1. sanitizeToolUseResultPairing() - drops orphaned tool results created by the cut-off
  2. validateGeminiTurns() - merges consecutive assistant messages
  3. validateAnthropicTurns() - merges consecutive user messages

The same fix is applied to both:

  • src/agents/pi-embedded-runner/run/attempt.ts (main request path)
  • src/agents/pi-embedded-runner/compact.ts (compaction path)

Testing

  • All existing tests pass
  • Lint and type-check pass

Closes #4650


Pull Request opened by Augment Code with guidance from the PR author

Greptile Overview

Greptile Summary

This PR updates the embedded Pi runner and compaction code paths to re-run transcript sanitization after limitHistoryTurns() is applied. The intent is to fix cases where truncation can leave orphaned tool_result messages (without their preceding tool_use) and can create consecutive same-role turns that certain providers reject (e.g., Gemini assistant-assistant or Anthropic user-user turns). The change adds a post-limit pass of sanitizeToolUseResultPairing(), validateGeminiTurns(), and validateAnthropicTurns() before persisting the truncated message list back into the session.

Confidence Score: 4/5

  • This PR is likely safe to merge and should reduce provider request rejections by repairing transcripts after truncation.
  • The change is localized to post-processing of an already-sanitized/validated transcript and uses existing, well-scoped helper functions. Main remaining risk is behavioral: sanitizeToolUseResultPairing() can insert synthetic tool results for missing tool calls, and re-running it after truncation could add new synthetic entries; whether that is always desired depends on TranscriptPolicy expectations. CI/test execution couldn't be verified in this environment (no node/pnpm available).
  • src/agents/pi-embedded-runner/run/attempt.ts, src/agents/pi-embedded-runner/compact.ts

… results

After limitHistoryTurns cuts off older messages, tool_use blocks can be
removed while their corresponding tool_result blocks remain, creating
orphaned tool results that cause Anthropic API to reject requests.

Similarly, the limiting can create consecutive assistant messages that
violate Gemini's format requirements.

This fix re-runs sanitizeToolUseResultPairing, validateGeminiTurns, and
validateAnthropicTurns after the history limit is applied, repairing any
issues created by the cut-off.

Closes openclaw#4650
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +542 to +545
const postLimitRepaired = transcriptPolicy.repairToolUseResultPairing
? sanitizeToolUseResultPairing(limited)
: limited;
const postLimitGemini = transcriptPolicy.validateGeminiTurns
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Post-limit pass may insert synthetic tool results, not just dropsessionphans.

The comment says this is to "fix any orphaned tool results", but sanitizeToolUseResultPairing() delegates to repairToolUseResultPairing(), which also inserts synthetic error tool results for missing tool calls (makeMissingToolResult() in src/agents/session-transcript-repair.ts:38-55). After limitHistoryTurns() truncation, that can happen if the tool call remains but the matching tool result was truncated, increasing message count and potentially affecting token budgeting/compaction behavior. If the intent here is strictly to drop orphaned tool_results (as described in the PR), consider either adjusting the comment to reflect the insertion behavior, or using the repair report to drop-orphans-only in this post-limit step.

Also appears in src/agents/pi-embedded-runner/compact.ts:427-432.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/attempt.ts
Line: 542:545

Comment:
[P2] Post-limit pass may *insert* synthetic tool results, not just dropsessionphans.

The comment says this is to "fix any orphaned tool results", but `sanitizeToolUseResultPairing()` delegates to `repairToolUseResultPairing()`, which also **inserts synthetic error tool results** for missing tool calls (`makeMissingToolResult()` in `src/agents/session-transcript-repair.ts:38-55`). After `limitHistoryTurns()` truncation, that can happen if the tool call remains but the matching tool result was truncated, increasing message count and potentially affecting token budgeting/compaction behavior. If the intent here is strictly to *drop orphaned tool_results* (as described in the PR), consider either adjusting the comment to reflect the insertion behavior, or using the repair report to drop-orphans-only in this post-limit step.

Also appears in `src/agents/pi-embedded-runner/compact.ts:427-432`.

How can I resolve this? If you propose a fix, please make it concise.

@sebslight
Copy link
Member

Closing as duplicate of #13974. If this is incorrect, comment and we can reopen.

@sebslight sebslight closed this Feb 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Tool Use/Result Pairing and Consecutive Assistant Messages After History Limiting

2 participants