Skip to content

Support fallbackMessages for instant conversation switching #1045

@alexanderjacobsen

Description

@alexanderjacobsen

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

  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:

// 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions