You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Think sends “done” before saving the final transcript #2119
Describe the bug Think._streamResult() sends the terminal cf_agent_use_chat_response frame with done: true before it persists the completed assistant message and broadcasts cf_agent_chat_messages.
useAgentChat therefore changes to ready before the authoritative transcript is available. If the client immediately sends another message, the later transcript broadcast can replace the local message array and temporarily remove the new optimistic user message.
To Reproduce
Steps to reproduce the behavior:
Create a Think chat using useAgentChat.
Send a message and wait for its response to finish.
Immediately call sendMessage() when the chat status changes to ready.
See the new user message appear optimistically.
See it disappear when the previous turn’s delayed cf_agent_chat_messages snapshot arrives.
See it return after the new turn finishes and another transcript snapshot is broadcast.
Expected behavior
Think should persist the completed assistant message and broadcast the authoritative transcript before sending the terminal done: true frame.
The completion order should be:
_persistAssistantMessage()
_broadcastMessages()
Broadcast done: true
After useAgentChat becomes ready, the client should be able to safely start another turn without a previous-turn snapshot replacing its optimistic message.
Screenshots
Not applicable.
Version:
Reproduced with @cloudflare/think@0.15.0 and agents@0.19.0. The same ordering is present in @cloudflare/think@0.15.1.
Additional context
The WebSocket remains connected throughout the reproduction. This is separate from #1983, which concerns buffered messages during reconnect.
A regression test can drive _streamResult() with a completed UI message stream and assert the event order:
persist → transcript broadcast → done
Moving persistence and _broadcastMessages() before the terminal frame resolves the issue without requiring client-side message reconciliation.
changed the title [-]# Think sends “done” before saving the final transcript[/-][+]Think sends “done” before saving the final transcript[/+]on Aug 16, 2026
Activity
[-]# Think sends “done” before saving the final transcript[/-][+]Think sends “done” before saving the final transcript[/+]urjitc commentedon Aug 16, 2026
i can give a repro if needed
fix(think): broadcast the persisted transcript before the done frame (#…
fix(think): broadcast the persisted transcript before the done frame (#…