Skip to content

fix: streaming parallel tool-use emit logic (issue #197)#200

Open
jozkee wants to merge 2 commits into
anthropics:nextfrom
jozkee:issue-197
Open

fix: streaming parallel tool-use emit logic (issue #197)#200
jozkee wants to merge 2 commits into
anthropics:nextfrom
jozkee:issue-197

Conversation

@jozkee

@jozkee jozkee commented May 20, 2026

Copy link
Copy Markdown
Contributor

RawContentBlockStopEvent was iterating over the entire streamingFunctions dictionary and clearing it. When a later tool_use block's content_block_start arrived before an earlier block's content_block_stop, the stop event would emit FunctionCallContent for every tracked tool, including ones whose input_json deltas had not yet arrived, and then wipe the dictionary, losing the later tools' real arguments.

Only emit (and remove) the entry whose index matches the stop event, in both AnthropicClientExtensions and AnthropicBetaClientExtensions. Add a regression test in AnthropicClientExtensionsTestsBase so coverage applies to both client variants.

Fixes #197

@jozkee jozkee requested a review from a team as a code owner May 20, 2026 17:07
RawContentBlockStopEvent was iterating over the entire streamingFunctions
dictionary and clearing it. When a later tool_use block's content_block_start
arrived before an earlier block's content_block_stop, the stop event would
emit FunctionCallContent for every tracked tool — including ones whose
input_json deltas had not yet arrived — and then wipe the dictionary,
losing the later tools' real arguments.

Only emit (and remove) the entry whose index matches the stop event, in
both AnthropicClientExtensions and AnthropicBetaClientExtensions. Add a
regression test in AnthropicClientExtensionsTestsBase so coverage applies
to both client variants.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\"arg\":\"a\"}"}}

event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_b","name":"tool_b","input":{},"caller":{"type":"direct"}}}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@ziv690922 what's still odd to me is how you could get tool_use ids must be unique if the ids are part of the content_block_start, they should never be duplicated, even in the buggy code.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You're right, the duplicate ids are not caused by this bug. After further investigation, the tool_use ids must be unique error was coming from FunctionInvokingChatClient internally appending the assistant turn (including tool_use blocks) into the messages list across iterations, which resulted in duplicate ids being sent to the Anthropic API. That's a separate issue from what this PR fixes.

@TomerAberbach

Copy link
Copy Markdown
Contributor

@stephentoub does this look right to you?

@TomerAberbach TomerAberbach changed the title Fix streaming parallel tool-use emit logic (issue #197) fix: streaming parallel tool-use emit logic (issue #197) May 28, 2026
@stephentoub

Copy link
Copy Markdown
Contributor

@TomerAberbach, sorry for the delay. This looks good to me. Also, for future reference, both @jozkee and @jeffhandley are on my team at Microsoft and I trust them with these kinds of fixes and improvements.

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.

5 participants