Skip to content

fix(server-utils): Keep Workers AI streamed tool calls that have no index - #25835

Open
pcbeingused333 wants to merge 2 commits into
getsentry:developfrom
pcbeingused333:fix/workers-ai-stream-tool-calls-without-index
Open

pcbeingused333 wants to merge 2 commits into
getsentry:developfrom
pcbeingused333:fix/workers-ai-stream-tool-calls-without-index

Conversation

@pcbeingused333

Copy link
Copy Markdown
Contributor

Why: The Workers AI streaming instrumentation (accumulateStreamingToolCalls) keyed every tool-call delta by toolCall.index ?? 0. OpenAI-compatible endpoints that omit index and send each parallel call whole in its own chunk therefore ended up as a single call: the first call's id and name, with the arguments of every call concatenated, and the other calls missing from gen_ai.response.tool_calls and gen_ai.output.messages. Same situation #25622 fixed for the OpenAI instrumentation.

Tool calls with a numeric index are grouped by it exactly as before. A delta without a usable index (missing or null) is kept in a separate list, in arrival order, so it can never collide with a real index: a delta whose id is already known continues that call, a new id (or a function name without an id) starts a new call, and anything else, such as an arguments fragment with neither, continues the latest one. Native and indexed streams (including the top-level name/arguments shape) behave as before.

How to review: getUnindexedToolCall and the ToolCallAccumulator split in packages/server-utils/src/ai/workers-ai/streaming.ts; the three new cases in workers-ai-streaming.test.ts (two parallel calls without an index stay separate, argument fragments of one unindexed call are merged, an unindexed call does not merge into an indexed call at index: 0). The first and third fail without the change; the whole test/ai/lib/tracing folder passes.

Unsure about: whether an unindexed delta with neither id nor name should continue the latest call (chosen here, mirrors #25622) or be dropped.

Closes: no linked issue; same class of bug as #25622.

This change was prepared with the assistance of an AI coding agent (Claude).

…ndex

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@pcbeingused333
pcbeingused333 requested a review from a team as a code owner October 28, 2026 15:41
@pcbeingused333
pcbeingused333 requested review from isaacs and mydea and removed request for a team October 28, 2026 15:41
@github-actions github-actions Bot added the external PR from an external contributor label Oct 28, 2026
@RulaKhaled
RulaKhaled self-requested a review October 29, 2026 13:33

@JosephDoUrden JosephDoUrden left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

read b403a7a against #25622 and ran instrumentWorkersAiStream from a copy with stubbed sentry imports, head vs develop, 8 delta shapes. no index and index: null parallel calls: 2 calls, develop gave 1. normal indexed stream unchanged. repo suite not run.

one gap at streaming.ts:71, it does not fully match #25622. index: 0 on every call with new ids still merges into 1 call. {index: 0, id, name} then an args fragment with no index or id now gives 2 calls, nameless one holds the args, develop gave 1. no index then indexed comes out reversed.

worth fixing before merge.

…dling

Reuse the id/index grouping of the OpenAI streaming accumulator: a new id on a taken index opens a new call, argument fragments without index or id continue the latest call, and calls keep their arrival order.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@pcbeingused333

Copy link
Copy Markdown
Contributor Author

Thanks @JosephDoUrden, good catch. Pushed 2725da7, which ports the same accumulator the OpenAI integration uses (getToolCallKey in #25622), so Workers AI streams now behave the same way:

  • index: 0 with a new id starts a new tool call instead of merging into the previous one.
  • An argument fragment with no index/id is appended to the call it belongs to, so the name is no longer empty with the args split off.
  • Calls are emitted in stream order.

I added tests for the three cases; they failed before the change and pass now.

This comment was drafted with Claude Code.

@pcbeingused333

Copy link
Copy Markdown
Contributor Author

Thanks @JosephDoUrden, good catch. Pushed a follow-up that ports the accumulator logic from the OpenAI integration (#25622) to the Workers AI streaming path:

  • {index: 0} with a new id now starts a new tool call instead of merging into the previous one.
  • An argument fragment with no index/id is appended to the call currently being built, so the name and arguments stay together.
  • Calls keep the order in which they arrived.

I added tests for these three cases; the suite passes locally.

This comment was drafted with Claude Code.

This branch has not been deployed

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

Labels

external PR from an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants