Skip to content

fix: prevent duplicate tool results on provider disconnect/fallback - #46

Open
alfep wants to merge 1 commit into
freecodexyz:mainfrom
alfep:fix/dup-tool-results
Open

fix: prevent duplicate tool results on provider disconnect/fallback#46
alfep wants to merge 1 commit into
freecodexyz:mainfrom
alfep:fix/dup-tool-results

Conversation

@alfep

@alfep alfep commented Jul 28, 2026

Copy link
Copy Markdown

Summary

Fixes duplicate tool_result submission when the provider reconnects mid-stream or when the model fallback pipeline re-processes an assistant message that already contains tool_use blocks.

Picks up work from closed-unmerged PR #42 (same fix, rebased onto current upstream main @ 6b25ab6).

Root cause

Two paths can emit a duplicate tool result for the same provider-issued tool_use.id:

  1. StreamingToolExecutor queue — if the provider disconnects and reconnects, the SDK may re-send the same tool_use block. addTool() blindly queued it again → tool ran twice → two results.
  2. Fallback / interruption recoveryyieldMissingToolResultBlocks() walks every assistant message and emits one result per tool_use block. If the same ID appears twice in the same message (reconnect artifact), it yields two results.

Fix

Two minimal dedup guards, both keyed by tool_use.id:

  • src/services/tools/StreamingToolExecutor.tsaddTool returns early if block.id is already in this.tools. This guarantees at-most-once execution per ID.
  • src/query.tsyieldMissingToolResultBlocks filters content so each tool_use ID is walked at most once. This guarantees at-most-once result per ID even in the fallback path.

Together they implement the "treat a completed provider-issued tool-call ID as committed" invariant from #38.

Test plan

I have not run the reproducers in this PR — they're self-contained Python+Docker and need a Linux host. Reviewer to verify.

Fixes #37
Fixes #38

… duplicate tool results

Addresses issues freecodexyz#37 and freecodexyz#38: after provider disconnect/reconnect or
model fallback, the same tool_use ID could be submitted twice to the
provider, resulting in duplicate tool_result blocks.

Changes:
- StreamingToolExecutor.addTool: skip duplicate tool_use IDs that are
  already tracked (provider reconnect path)
- yieldMissingToolResultBlocks: deduplicate tool_use blocks by ID
  within each assistant message before yielding interruption fallback
  results (model fallback recovery path)

Reproducer (untested by AI, reviewer must run):
- Issue freecodexyz#37 gist: https://gist.github.com/N0zoM1z0/adb097dd6be467aa0cc1608d0e1dca6b
- Issue freecodexyz#38 gist: https://gist.github.com/N0zoM1z0/1c2db900f5aef155cc647458cb7ba6d2

Picks up work from closed-unmerged PR freecodexyz#42

Fixes freecodexyz#37
Fixes freecodexyz#38
Copilot AI review requested due to automatic review settings July 28, 2026 17:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Free Code resubmits a tool result after a post-tool provider disconnect [BUG] free-code repeats completed shell tool results

2 participants