Patch Changes
-
#1661
41315b6Thanks @threepointone! - Heal a malformedtool_use.inputwhen loading persisted messages.AIChatAgentdelegatesconvertToModelMessagesto youronChatMessage, so it has no framework-side pre-send pass to repair a transcript. A session that persisted a non-object toolinput—null,undefined,"", an array, or a raw string — before the write-side guard shipped would therefore keep 400ing withtool_use.input: Input should be an objecton every turn, wedged across reconnects/redeploys/evictions.autoTransformMessage(run on every load) now normalizes malformed tool inputs to{}(parsing stringified-JSON objects, and leaving healthy object inputs untouched), so existing wedged sessions self-heal on their next load without per-DO storage surgery. Healthy messages are returned by reference, so the persistence cache stays a no-op for them. -
#1654
f34cd30Thanks @cjol! - FixisStreamingstaying true after aborting during server-side tool calls. -
#1657
7bff8d7Thanks @threepointone! - fix(think): serialize parallel client-tool result/approval applies so siblings aren't clobbered (#1649 follow-up)The auto-continuation barrier added in #1651 stopped premature continuation, but a deeper race remained in Think. Each
tool-result/tool-approvalWebSocket message fired an independent read-modify-write of the whole assistant message, and_applyToolUpdateToMessagesawaits a storage read before its write. When the model fanned out parallel tool calls, the concurrent applies all read the sameinput-availablesnapshot, each patched only its own part, and the last write clobbered its siblings back toinput-available. The continuation barrier then timed out and the transcript-repair backstop errored the lost calls with "The tool call was interrupted before a result was recorded."Applies are now chained off a serialization tail so each read-modify-write commits atomically in arrival order.
_pendingInteractionPromisestill tracks the newest link, so the barrier's single-slot wake-up transitively waits for every predecessor.The same serialization is applied to
@cloudflare/ai-chatdefensively: its apply is currently synchronous (no await between the message read and the SQLite write), so it does not exhibit this clobber today, but the queue keeps the invariant safe if that ever changes.