github cloudflare/agents @cloudflare/ai-chat@0.5.2

Patch Changes

  • #1374 a6e22c3 Thanks @threepointone! - Fix useAgentChat recreating the AI SDK Chat instance — and orphaning any in-flight resumeStream — whenever agent.name transitions in place.

    The useAgent({ basePath }) + static options = { sendIdentityOnConnect: true } pattern lets the server own the Durable Object instance name. The browser starts with a placeholder ("default"), then useAgent mutates the agent object's .name to the server-assigned value when the identity frame arrives. useAgentChat previously included agent.name in the stable chat id it passed to useChat({ id }), so the transition changed the id and the AI SDK recreated the underlying Chat instance. The useEffect that fires chatRef.current.resumeStream() is keyed on the ref object, not the Chat instance, so it does not re-fire on recreation — the resumed stream kept feeding chunks into the orphaned Chat's state while React subscribed to the new Chat's state, so the user saw an empty assistant reply after a mid-stream refresh until the server's final CF_AGENT_CHAT_MESSAGES broadcast landed.

    useAgentChat now distinguishes an in-place agent.name mutation from a genuine "consumer switched chats" event by checking the agent object's reference identity:

    • same agent reference, name mutation → not a chat switch; keep the Chat instance stable.
    • new agent reference → chat switch; recompute the stable chat id so the AI SDK recreates the Chat against the new conversation.

    The stable id is also still upgraded once from the identity-only fallback to the URL-resolved key when the WebSocket handshake completes.

    Consumers who want to switch chats without remounting should pass a different agent object (e.g. a new useAgent({...}) call with a different name). To get a completely fresh Chat (e.g. when mounting a different chat tab), the conventional React pattern — key={chatId} on the parent or swapping the subtree — continues to work.

  • #1395 63cfae6 Thanks @threepointone! - Share submit concurrency bookkeeping through agents/chat and use it from both chat agents.

    This extracts the latest/merge/drop/debounce admission state machine into a SubmitConcurrencyController exported from agents/chat. AIChatAgent semantics (including merge persistence) are preserved. Think now picks up the same pending-enqueue protection, so an overlapping submit is still detected while an accepted request is between admission and turn queue registration.

    Additional fixes:

    • Think now captures the turn generation immediately after admission and threads it into _turnQueue.enqueue, so a clear that lands between admission and queue registration cannot run a stale turn.
    • Pending-enqueue tracking is now bound to a release function tied to the controller's reset epoch, so a release from a pre-reset submit can no longer erase a post-reset submit's marker and let a third submit slip through as non-overlapping.
    • Debounce cancellation correctly resolves all in-flight waiters instead of overwriting a single timer slot.
  • #1396 fdf5a8a Thanks @threepointone! - Fix Think persisting a duplicate orphan assistant row when a user submits during a streaming tool turn (#1381).

    When useAgentChat posts an in-flight assistant snapshot it minted optimistically (client-generated ID, state: "input-available"), Session's INSERT-OR-IGNORE-by-ID would store it as a separate row alongside the eventual server-owned assistant for the same toolCallId. The next turn's convertToModelMessages then produced a malformed Anthropic prompt and the provider rejected it.

    reconcileMessages and resolveToolMergeId now live in agents/chat and Think runs them in _handleChatRequest before persistence. Stale input-available snapshots pick up the server's tool output via mergeServerToolOutputs, and any incoming assistant whose toolCallId already exists on a server row adopts the server's ID so persistence updates the existing row instead of inserting an orphan.

    @cloudflare/ai-chat keeps its existing reconciler behavior; the only change is that it now imports reconcileMessages / resolveToolMergeId from agents/chat instead of a local file.

Don't miss a new agents release

NewReleases is sending notifications on new releases.