fix: emit tool-input-end before tool-call in multi-chunk and flush paths#415
fix: emit tool-input-end before tool-call in multi-chunk and flush paths#415robert-j-y wants to merge 2 commits intomainfrom
Conversation
Fixes #413. The multi-chunk tool call merge path and the flush path for unsent tool calls were missing the tool-input-end event before tool-call, diverging from the stream event protocol used by @ai-sdk/openai. Changes: - Multi-chunk merge path: add tool-input-end before tool-call - Flush path: emit full tool-input-start/delta/end sequence for unsent tools - Update existing test expectations to match corrected protocol - Add e2e regression test for issue #413 Co-Authored-By: Robert Yeakel <robert.yeakel@openrouter.ai>
There was a problem hiding this comment.
🚩 Pre-existing: initial chunk arguments are not emitted as a delta in the multi-chunk path
When the first chunk of a tool call includes non-empty but non-parsable-JSON arguments (e.g., {"val), those arguments are stored in toolCall.function.arguments at line 889 but never emitted as a tool-input-delta. The tool-input-start and first tool-input-delta are only emitted on the second chunk (merge path, lines 968-987), which only includes the merge chunk's delta, not the initial arguments. In the existing test (src/chat/index.test.ts:1476), the initial chunk has arguments: "" (empty string), so this isn't visible. This is a pre-existing issue not introduced by this PR, but worth noting for correctness if providers ever send non-empty partial arguments in the first tool call chunk.
(Refers to lines 884-893)
Was this helpful? React with 👍 or 👎 to provide feedback.
… is true Co-Authored-By: Robert Yeakel <robert.yeakel@openrouter.ai>
Addressing "Key areas for review"1. Flush path branching (lines 1057–1069)Verified correct. When This matches 2. E2e test modelsAcceptable. The issue was reported against |
Description
Fixes #413. The multi-chunk tool call merge path and the flush path for unsent tool calls were missing
tool-input-endevents before emittingtool-call, diverging from the stream event protocol used by@ai-sdk/openai.Before (multi-chunk path):
tool-input-start → tool-input-delta… → tool-call(missingtool-input-end)After (multi-chunk path):
tool-input-start → tool-input-delta… → tool-input-end → tool-callThe flush path for unsent tool calls now also emits the full
tool-input-start → tool-input-delta → tool-input-endsequence beforetool-callwhen the tool call was never partially streamed. When partial deltas were already streamed (i.e.inputStartedis true), onlytool-input-endis emitted to avoid duplicate deltas.Validated by comparing line-by-line against the
@ai-sdk/openaireference implementation (openai-chat-language-model.ts), which consistently emitstool-input-endbeforetool-callin both its single-chunk and multi-chunk paths.Updates since last revision
tool-input-deltaemission in the flush path was unconditional, meaning partially-streamed tool calls (whereinputStartedis true) would receive a duplicate delta with the full accumulated input on top of the deltas already sent during streaming. Nowtool-input-deltais only emitted inside theif (!toolCall.inputStarted)guard.should emit tool-input-end without duplicate delta when partially-streamed tool call is flushedcovers the scenario where tool call arguments are streamed across multiple chunks but the JSON never completes, forcing the tool call through the flush path. Verifies only the streaming deltas are present (no duplicate from flush).Key areas for review
src/chat/index.tslines 1057–1069): WheninputStartedis false, the full sequence (start, delta, end) is emitted. When true, onlytool-input-endis emitted. Verify this correctly avoids duplicate deltas without dropping required events.openai/gpt-5.2; the e2e test usesopenai/gpt-4.1-nanoandopenai/gpt-4.1-minifor availability/stability.Checklist
pnpm stylecheckandpnpm typecheckpnpm testand all tests passChangeset
pnpm changesetto create a changeset fileLink to Devin run | Requested by @robert-j-y