@cloudflare/ai-chat@0.5.0

cloudflare/agents@cloudflare/ai-chat@0.5.0Apr 23, 2026by github-actions[bot]

AI Summary

This release aligns AIChatAgent with @cloudflare/think by introducing a new Props generic and consolidating shared lifecycle types in agents/chat. It also fixes a crash in useAgentChat() when the WebSocket URL isn't available on first render, which commonly occurred when the agent is reached through a proxy.

Key Highlights

  • New Props generic AIChatAgent<Env, State, Props> extending Agent for properly typed this.ctx.props
  • Shared lifecycle types (ChatResponseResult, ChatRecoveryContext, etc.) now in agents/chat and re-exported by both packages
  • New multi-ai-chat example demonstrating multi-session chat using sub-agent routing primitive
  • Fixed useAgentChat() crash when agent.getHttpUrl() returns empty string on first render
  • Messages now cached by agent identity rather than URL + identity, preserving chat state across URL transitions

Breaking Changes

  • GetInitialMessagesOptions.url is now string | undefined; callers that previously typed url: string should widen to url?: string

New Features

  • New Props generic for AIChatAgent extending Agent base class
  • Multi-session chat example (examples/multi-ai-chat) using sub-agent routing with Inbox and Chat agents
  • Deferred /get-messages fetch until URL is known, applied once when resolved
  • Custom getInitialMessages callbacks now receive url: undefined when HTTP URL not available
  • Stable useChat id across URL-arrival transition preserving stream resume and chat state

Full Release Notes

### Minor Changes

-   [#1353](https://github.com/cloudflare/agents/pull/1353) [`f834c81`](https://github.com/cloudflare/agents/commit/f834c814db16a6b7cba51cebef4be02b9364a088) Thanks [@threepointone](https://github.com/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`](../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](https://github.com/cloudflare/agents/pull/1358) [`ea229b1`](https://github.com/cloudflare/agents/commit/ea229b12dd11178881539c389c6625c6d3546e3b) Thanks [@threepointone](https://github.com/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](https://github.com/cloudflare/agents/issues/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.