-
Notifications
You must be signed in to change notification settings - Fork 447
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:
useAgentChat({
agent,
fallbackMessages: cachedMessages,
})Behavior
- If
fallbackMessagesis provided, use those as the initial messages — nouse(), no Suspense, renders instantly - The default
getInitialMessagesfetch still runs in the background (unchanged) - 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:
// Module-level cache
const messageCache = new Map<string, UIMessage[]>();
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 <MessageList messages={messages} />;
}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.