Minor Changes
-
#1353
f834c81Thanks @threepointone! - AlignAIChatAgentgenerics and types with@cloudflare/think, plus a reference example for multi-session chat built on the sub-agent routing primitive.- New
Propsgeneric:AIChatAgent<Env, State, Props>extendingAgent<Env, State, Props>. Subclasses now get properly typedthis.ctx.props. - Shared lifecycle types:
ChatResponseResult,ChatRecoveryContext,ChatRecoveryOptions,SaveMessagesResult, andMessageConcurrencynow live inagents/chatand are re-exported by both@cloudflare/ai-chatand@cloudflare/think. No behavior change; one place to edit when shapes evolve. ChatMessagestays the public message type: the package continues to exportChatMessage, and the public API/docs keep using that name.messagesstays 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/chatwhere both classes benefit) is captured indesign/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: anInboxAgent owns the chat list + shared memory; each chat is anAIChatAgentfacet (this.subAgent(Chat, id)). The client addresses the active chat viauseAgent({ sub: [{ agent: "Chat", name: chatId }] })— no separate DO binding, no custom routing on the server.Inbox.onBeforeSubAgentgates withhasSubAgentas a strict registry, andChatreaches its parent viathis.parentAgent(Inbox). - New
Patch Changes
-
#1358
ea229b1Thanks @threepointone! - FixuseAgentChat()crashing on first render whenagent.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-chatunconditionally callednew URL(agent.getHttpUrl()). See #1356.useAgentChat()now treats a missing HTTP URL as "not ready yet":- The built-in
/get-messagesfetch is deferred until the URL is known, and applied exactly once when it resolves (empty chats only — existing messages are never overwritten). - Custom
getInitialMessagescallbacks continue to run and are passedurl: undefinedso they can load from other sources if they don't need the socket URL.GetInitialMessagesOptions.urlis nowstring | undefined; callers that previously typedurl: stringshould widen tourl?: 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
useChatinstance keeps a stableidacross 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.
- The built-in