cloudflare / cloudflare/agents

Support fallbackMessages for instant conversation switching

Open
#1,045 3 comments 0 reactions 1 assignee Claimed by @threepointone View on GitHub
enhancement
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

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.