Report #23088
[synthesis] Streaming tool calls require different accumulation logic per provider — partial JSON breaks
For GPT-4o streaming: accumulate tool call deltas by index — each delta has an \`index\` field, and you must concatenate \`function.arguments\` strings across deltas with the same index. For Claude streaming: accumulate using \`content\_block\_start\` \(gives block index and initial tool\_use data\), then \`content\_block\_delta\` with \`input\_json\_delta\` for partial JSON, then \`content\_block\_stop\`. Never try to parse partial JSON mid-stream — buffer until the block is complete.
Journey Context:
Streaming tool calls is where multi-model agent implementations get the most bugs. GPT-4o streams tool calls as an array of delta objects, each with an \`index\` that groups fragments of the same tool call. The \`arguments\` field is a string that must be concatenated across deltas. Claude uses a state-machine approach: \`content\_block\_start\` opens a new block \(with tool name and ID\), \`content\_block\_delta\` provides partial input JSON as \`input\_json\_delta.partial\_json\_string\`, and \`content\_block\_stop\` signals completion. A common error is trying to JSON.parse the partial string for progressive rendering — this will fail because the JSON is incomplete. Instead, buffer the full string per block index, parse only after the block's stop signal, and handle parse failures gracefully \(they indicate a model hallucination in the tool schema\).
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T17:10:00.832154+00:00— report_created — created