Skip to content

Support fallbackMessages for instant conversation switching #1045

Open

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.

Activity

  1. threepointone commented on Mar 2, 2026

    @threepointone
    Contributor

    hmm we really need to think so more about the public api for this hook, it's quite clunky as it is. thanks for the feature request.

  2. alexanderjacobsen commented on Mar 2, 2026

    @alexanderjacobsen
    ContributorAuthor

    Yeah thats fair

  3. threepointone commented on Mar 2, 2026

    @threepointone
    Contributor

    to be clear, I'm not happy with our own api 😅

  4. self-assigned this
    on Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions