useMessagesWithSeed

useMessagesWithSeed reconciles a persisted conversation seed with the live session and returns the composed conversation, oldest-first: the seed followed by the live tail that has not yet been seeded. It is the core primitive behind database-backed hydration, and the Vercel useMessageSync builds on it.

Pass the view from a resolved session. useClientSession() returns a handle whose session.view is a View.

JavaScript

1

2

3

4

5

6

7

import { useMessagesWithSeed } from '@ably/ai-transport/react';

const messages = useMessagesWithSeed({
  view: session?.view,
  seed,
  getMessageId: (message) => message.id,
});

This hook is typically used within a ClientSessionProvider, which resolves the session whose view you pass in.

The hook takes the newest seed message's id, via getMessageId, as the seam and drives View.loadUntil to page the session back until that id reappears. It then composes the seed followed by the live tail, dropping the single overlapping message at the seam. With no seed (an empty array) it surfaces the live session window unchanged.

Parameters

useMessagesWithSeed accepts a single UseMessagesWithSeedOptions<TMessage> object:

viewoptionalView<TMessage> or Undefined
The view over the live session to reconcile against, for example session.view, or undefined before the session or view resolves. The hook then surfaces the seed as-is.
seedrequiredTMessage[]
The persisted conversation, oldest-first. Compared by content, so passing a fresh array each render, for example data ?? [], is safe. An empty array is a loaded-but-empty conversation and surfaces the live session window unchanged. While the seed is still loading, set skip instead of passing [].
getMessageIdrequired(message: TMessage) => string
Returns a message's stable domain id, the seam key shared between your store and the session. The transport's internal codecMessageId is never persisted.
skipoptionalBoolean
Holds the reconciliation while the seed is still loading, for example during an async store fetch. When true the hook does not page the session and returns []. Clear it once the seed has loaded. Defaults to false.

Returns

TMessage[]. The composed conversation, oldest-first: the seed followed by the live tail newer than the seam. While skip is true, or before a seed loads, the hook returns [].

Example

A component that fetches its seed from a store, reads the view from the resolved session, and renders the composed conversation:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import { useClientSession, useMessagesWithSeed } from '@ably/ai-transport/react';

function Conversation({ seed }) {
  const { session } = useClientSession();
  const messages = useMessagesWithSeed({
    view: session?.view,
    seed,
    getMessageId: (message) => message.id,
  });

  return (
    <>
      {messages.map((message) => (
        <Message key={message.id} message={message} />
      ))}
    </>
  );
}

For Vercel AI SDK applications, the pre-typed useMessagesWithSeed from @ably/ai-transport/vercel/react omits getMessageId because it keys on UIMessage.id, and useMessageSync wraps it for useChat.