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

6 hours ago

Minor Changes

  • #1353 f834c81 Thanks @threepointone! - Align AIChatAgent generics and types with @cloudflare/think, plus a reference example for multi-session chat built on the sub-agent routing primitive.

    • New Props generic: AIChatAgent<Env, State, Props> extending Agent<Env, State, Props>. Subclasses now get properly typed this.ctx.props.
    • Shared lifecycle types: ChatResponseResult, ChatRecoveryContext, ChatRecoveryOptions, SaveMessagesResult, and MessageConcurrency now live in agents/chat and are re-exported by both @cloudflare/ai-chat and @cloudflare/think. No behavior change; one place to edit when shapes evolve.
    • ChatMessage stays the public message type: the package continues to export ChatMessage, and the public API/docs keep using that name.
    • messages stays a public field: messages: ChatMessage[].

    The full stance (AIChatAgent is first-class, production-ready, and continuing to get features; shared infrastructure should land in agents/chat where both classes benefit) is captured in design/rfc-ai-chat-maintenance.md.

    A new example, examples/multi-ai-chat, demonstrates the multi-session pattern end-to-end on top of the sub-agent routing primitive: an Inbox Agent owns the chat list + shared memory; each chat is an AIChatAgent facet (this.subAgent(Chat, id)). The client addresses the active chat via useAgent({ sub: [{ agent: "Chat", name: chatId }] }) — no separate DO binding, no custom routing on the server. Inbox.onBeforeSubAgent gates with hasSubAgent as a strict registry, and Chat reaches its parent via this.parentAgent(Inbox).

Patch Changes

  • #1358 ea229b1 Thanks @threepointone! - Fix useAgentChat() crashing on first render when agent.getHttpUrl() returns an empty string. This happened in setups where the WebSocket handshake hadn't completed by the time React rendered — most commonly when the agent is reached through a proxy or custom-routed worker — because @cloudflare/ai-chat unconditionally called new URL(agent.getHttpUrl()). See #1356.

    useAgentChat() now treats a missing HTTP URL as "not ready yet":

    • The built-in /get-messages fetch is deferred until the URL is known, and applied exactly once when it resolves (empty chats only — existing messages are never overwritten).
    • Custom getInitialMessages callbacks continue to run and are passed url: undefined so they can load from other sources if they don't need the socket URL. GetInitialMessagesOptions.url is now string | undefined; callers that previously typed url: string should widen to url?: string.
    • Initial messages are cached by agent identity (class + name) rather than by URL + identity, so the URL-arrival transition no longer invalidates the cache, re-invokes the loader, or re-triggers Suspense once the chat has already been populated.
    • The underlying useChat instance keeps a stable id across the URL-arrival transition, so in-flight stream resume and chat state are preserved.

    No API or behavior changes for apps where the URL was already available synchronously on first render.

Don't miss a new agents release

NewReleases is sending notifications on new releases.