cloudflare / cloudflare/agents
Support fallbackMessages for instant conversation switching
- Dominant language
- TypeScript
- Stars
- 5.6k
- Forks
- 711
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 53
Description
## Problem
Apps that support multiple conversations need to switch between them. With the current SDK, every conversation switch triggers a `getInitialMessages` fetch that suspends via `use()`, showing a loading state while messages are fetched from the server — even if the user just visited that conversation seconds ago.
This is noticeable in apps with a conversation list/sidebar where users switch between chats frequently.
## Proposal
Add a `fallbackMessages` option to `useAgentChat` that renders immediately while the real fetch happens in the background:
```typescript
useAgentChat({
agent,
fallbackMessages: cachedMessages,
})
```
### Behavior
1. If `fallbackMessages` is provided, use those as the initial messages — no `use()`, no Suspense, renders instantly
2. The default `getInitialMessages` fetch still runs in the background (unchanged)
3. When the fetch resolves, replace messages with the server response
This doesn't introduce any new fetching logic. The SDK already fetches via `getInitialMessages` — the only change is that instead of suspending while that promise resolves, it shows `fallbackMessages` first. Conceptually similar to React Suspense's `fallback` but for data, or SWR/React Query's `fallbackData`/`placeholderData`.
### Edge case: user sends a message before revalidation completes
If the user sends a message while the background fetch is still in-flight, the revalidation result should be discarded. The message was sent through the WebSocket to the server, so the server is already up to date — the WebSocket becomes the source of truth from that point.
## Usage example
The consuming app manages a simple message cache:
```typescript
// Module-level cache
const messageCache = new Map();
function ChatContent({ conversationId }: { conversationId: string }) {
const agent = useAgent({ agent: "chat-agent", name: conversationId, host });
const { messages } = useAgentChat({
agent,
fallbackMessages: messageCache.get(conversationId),
});
// Update cache when messages change
useEffect(() => {
if (messages.length > 0) {
messageCache.set(conversationId, messages);
}
}, [conversationId, messages]);
return ;
}
```
Recently visited conversations render instantly with cached messages, while the SDK silently verifies against the server and updates if needed.
## Why not just use `getInitialMessages`?
You can return cached messages from a custom `getInitialMessages`, but then the SDK considers messages "loaded" and never fetches from the server. There's no way to say "show these now, but also verify with the server." You'd have to reimplement the server fetch yourself, which means knowing the internal URL format and handling reconciliation manually.
`fallbackMessages` keeps the existing fetch pipeline intact and just changes what's shown while it resolves.
Contributor guide
Assessment
This issue has not been assessed yet.