Patch Changes
-
#1412
8fb7c03Thanks @threepointone! - MakeapplyChunkToPartsidempotent against an existing tool part with the sametoolCallId, and addisReplayChunk(parts, chunk)for stream broadcasters that want to drop provider replay chunks (#1404).Some providers (notably the OpenAI Responses API) re-emit a prior tool call in continuation streams. The previous
tool-input-starthandler unconditionally pushed a fresh tool part, which produced duplicate parts in the message;tool-input-deltaandtool-input-availableoverwrote a fully resolved input/state if a chunk happened to arrive for an already-known toolCallId. The new behavior:tool-input-startfor atoolCallIdthat already exists inpartsis a no-op (it does not push a duplicate or regress state).tool-input-deltaonly mutates input while the existing part is stillinput-streaming.tool-input-availableonly advances frominput-streamingtoinput-available; replays against parts that have already moved pastinput-streaming(includingapproval-requested/approval-respondedand any terminal state) are no-ops.
isReplayChunk(parts, chunk)is exported fromagents/chatfor stream broadcasters (e.g.AIChatAgent._streamSSEReply) that want to detect "this chunk is a replay of an already-known tool call" and skip re-broadcasting it. AI SDK v6'supdateToolParton the client mutates an existing tool part in place when the toolCallId matches, so re-broadcasting these replay chunks would visibly regress anoutput-availablepart toinput-streamingon connected clients.tool-output-availableis not treated as a replay because its in-place update is safe when the output already matches.Tool calls that the model genuinely wants to re-issue always carry a new toolCallId, so an existing match is never a legitimate "start over".