Skip to content

fix(agents): clear pending tool call state on interruption regardless of provider#32120

Merged
steipete merged 2 commits intoopenclaw:mainfrom
jnMetaCode:fix/orphaned-tool-use-pending-clear
Mar 2, 2026
Merged

fix(agents): clear pending tool call state on interruption regardless of provider#32120
steipete merged 2 commits intoopenclaw:mainfrom
jnMetaCode:fix/orphaned-tool-use-pending-clear

Conversation

@jnMetaCode
Copy link
Contributor

Summary

Fixes #32098 — orphaned tool_use block when user message interrupts in-flight tool call permanently breaks the session.

Root cause: In session-tool-result-guard.ts, the flush logic that clears pending tool call state was gated behind if (allowSyntheticToolResults). For providers where this is false (OpenAI, OpenRouter, and most third-party providers), the pending map was never cleared when a user message arrived during in-flight tool execution. This left orphaned tool_use blocks in the transcript with no matching tool_result, causing the provider API to reject all subsequent requests.

Fix: Remove the allowSyntheticToolResults guard around the flush calls. flushPendingToolResults() already handles both cases correctly internally — it only inserts synthetic results when allowSyntheticToolResults is true, and always calls pending.clear(). The outer guard was simply preventing the cleanup from ever running for affected providers.

Two call sites fixed:

  1. Line 174: when sanitized assistant message is empty
  2. Lines 218-227: when a non-tool-result message arrives while tool calls are pending

Test plan

  • All 26 session-tool-result-guard tests pass
  • oxfmt --check passes
  • CI green

🤖 Generated with Claude Code

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

Removes unnecessary guard around pending tool call cleanup logic, fixing session-breaking bug for OpenAI/OpenRouter providers.

The fix correctly addresses the root cause: flushPendingToolResults() already has the right internal logic (only inserts synthetic results when allowSyntheticToolResults is true, but always clears the pending map). The outer guard at lines 174 and 218-227 was preventing cleanup from ever running for providers where allowSyntheticToolResults is false.

Key insight from src/agents/transcript-policy.ts:133:

  • allowSyntheticToolResults: !isOpenAi && (isGoogle || isAnthropic)
  • This means OpenAI, OpenRouter (non-Gemini), and most third-party providers have this set to false

Behavior after fix:

  • Anthropic/Google: inserts synthetic results + clears pending (no change)
  • OpenAI/OpenRouter/etc: skips synthetic results + clears pending (now works correctly)

The added comment clearly documents the rationale for future maintainers.

Confidence Score: 5/5

  • Safe to merge - minimal, well-reasoned fix that addresses a critical session-breaking bug
  • The fix is minimal (removes unnecessary guards), logically correct (flushPendingToolResults already handles both cases internally), and all 26 existing tests pass. The added comment clearly documents the rationale. No breaking changes or edge cases identified.
  • No files require special attention

Last reviewed commit: 17cfb91

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: XS labels Mar 2, 2026
jnMetaCode and others added 2 commits March 2, 2026 21:26
… of provider

When `allowSyntheticToolResults` is false (OpenAI, OpenRouter, and most
third-party providers), the guard never cleared its pending tool call map
when a user message arrived during in-flight tool execution. This left
orphaned tool_use blocks in the transcript with no matching tool_result,
causing the provider API to reject all subsequent requests with 400 errors
and permanently breaking the session.

The fix removes the `allowSyntheticToolResults` gate around the flush
calls. `flushPendingToolResults()` already handles both cases correctly:
it only inserts synthetic results when allowed, and always clears the
pending map. The gate was preventing the map from being cleared at all
for providers that disable synthetic results.

Fixes openclaw#32098

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@steipete steipete force-pushed the fix/orphaned-tool-use-pending-clear branch from 17cfb91 to 2372b57 Compare March 2, 2026 21:28
@steipete steipete merged commit 42e402d into openclaw:main Mar 2, 2026
1 check passed
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Landed via temp rebase onto main.

  • Gate: pnpm -s vitest run src/agents/session-tool-result-guard.test.ts src/agents/transcript-policy.test.ts
  • Land commit: 2372b57563f25959ae76f2f40a4c66f532a03f52
  • Merge commit: 42e402d

Thanks @jnMetaCode!

dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
OWALabuy pushed a commit to kcinzgg/openclaw that referenced this pull request Mar 4, 2026
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 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 size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Orphaned tool_use block when user message interrupts in-flight tool call — session permanently broken

2 participants