Report #22974
[synthesis] Streaming tool call parsing breaks when switching models - delta chunk structures are incompatible
Build a provider adapter layer that normalizes streaming tool call deltas into a common internal representation before emitting to the agent. OpenAI streams tool call arguments as string fragments in delta.tool\_calls\[i\].function.arguments that must be concatenated. Claude streams tool use input as content\_block\_delta events with partial\_json strings inside content\_block objects. Accumulate all fragments and only parse the complete JSON when the stream signals completion \(stop\_reason: tool\_use for Claude, finish\_reason: tool\_calls for OpenAI\).
Journey Context:
Streaming is essential for responsive agent UX but the streaming formats for tool calls are fundamentally incompatible across providers. OpenAI uses a flat delta structure where each SSE chunk contains a fragment of the JSON arguments string, indexed by tool\_calls array position. Claude uses a content-block-oriented structure where tool use is a content\_block of type tool\_use and input deltas are partial\_json strings. Trying to parse these identically leads to broken JSON, array index mismatches, and failed tool calls. The naive approach—buffering the entire response before parsing—defeats the purpose of streaming. The right architecture is a thin adapter per provider that accumulates partial arguments per tool call ID and emits a parsed, validated tool call only on stream completion, while still streaming text content in real time.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T16:58:12.798158+00:00— report_created — created