cloudflare / cloudflare/agents

useAgentChat: getInitialMessages fetches the previous instance on `name` change (socket URL lags one render)

Open
#1,874 0 comments 0 reactions 1 assignee Claimed by @threepointone View on GitHub
Dominant language
TypeScript
Stars
5.6k
Forks
711
Avg merge
1d 20h
Merged PRs (30d)
53

Description

### Which SDK / package

`agents` (react) + `@cloudflare/ai-chat` (react) — `useAgent` + `useAgentChat`.

### Version

`agents@0.17.3`, `@cloudflare/ai-chat@0.9.3` (latest at time of writing).

### Summary

When an app switches the agent instance by **changing the `name` passed to `useAgent`** (e.g. switching between chat conversations, where each conversation is a distinct DO instance), `useAgentChat` fetches `get-messages` for the **previous** instance, not the new one. The target instance's history never loads.

Root cause: the initial-messages URL is derived from the live socket, and the socket lags the `name` prop by one render.

### Root cause

- `useAgentChat`'s `defaultGetInitialMessagesFetch` builds the request from `agentUrlString` (the agent's socket URL): `getMessagesUrl = new URL(url); getMessagesUrl.pathname += "/get-messages"`.
- That `url` comes from the socket returned by `useAgent` → `usePartySocket` → `useStableSocket`, where the socket is held in `useState` and replaced via `setSocket` inside an effect when the memo key changes.
- So on the render where `name` changes, `useAgent` still returns the **old** socket (the `setSocket` for the new one runs in a later commit). Its URL still points at the previous instance.
- `useAgentChat` creates the `getInitialMessages` promise during that same render (consumed via `use(promise)`), so it fetches `.../agents///get-messages` → 404/empty for the intended instance.
- `GetInitialMessagesOptions` only exposes `{ agent, name, url }`, and `name` there is `agent.name` (identity-derived, also lagged), so a custom `getInitialMessages` override can't get the intended target name from the options either — it has to reach outside the SDK for the current `name` prop.

### Reproduction

1. Mount `useAgent({ agent: "ChatAgent", name })` + `useAgentChat({ agent })` once.
2. Change `name` from instance A to instance B (both have persisted history), e.g. inside a `startTransition`.
3. Observe the network: `get-messages` is requested for instance **A** (or a stale id), not **B**. B's history never loads.

The official docs only ever show a **stable** `name` (`name: userId`), so this path isn't covered by examples — but changing `name` is otherwise supported (the socket re-keys on `addressKey`).

### Impact

Any app that reuses one mounted `useAgentChat` across multiple agent instances (a very natural "chat session switcher" UX) silently loads the wrong instance's history on switch.

### Suggested fix

Derive the `get-messages` URL / `name` passed to `getInitialMessages` from the **current `name` prop** (synchronous) rather than the lagged socket URL — e.g. compute the messages URL from `options.name`/`host` the same way `getAgentMessages` does, instead of from `agent.url`. At minimum, pass the intended (prop-derived) `name` into `GetInitialMessagesOptions` so overrides can build a correct URL without reaching outside the SDK.

### Workaround (for others hitting this)

Pass a custom `getInitialMessages` that ignores the SDK-provided `url`/`name` and builds the request from your own source-of-truth session id (the value you pass as `name`), not from the socket.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.