Retrieving messages
For clients to show messages, you need to expose a query that returns the messages. For streaming, see retrieving streamed deltas for a modified version of this query. See chat/basic.ts for the server-side code, and chat/streaming.ts for the streaming example.listUIMessages, which returns UIMessages, specifically the
Agent extension that includes some extra fields like order, status, etc.
UIMessages combine multiple MessageDocs into a single UIMessage when there are
multiple tool calls followed by an assistant message, making it easy to build
UIs that work with the various “parts” on the UIMessage.
If you want to get MessageDocs, you can use listMessages instead.
Showing messages in React
See ChatStreaming.tsx for a streaming example, or ChatBasic.tsx for a non-streaming example.useUIMessages hook
The crux is to use the useUIMessages hook. For streaming, pass in
stream: true to the hook.
useThreadMessages hook instead. However, working with UIMessages
enables richer streaming capabilities, such as status on whether the agent is
actively reasoning.
UIMessage type
The Agent component extends the AI SDK’sUIMessage type to provide convenient
metadata for rendering messages.
The core UIMessage type from the AI SDK is:
partsis an array of parts (e.g. “text”, “file”, “image”, “toolCall”, “toolResult”)contentis a string of the message content.roleis the role of the message (e.g. “user”, “assistant”, “system”).
keyis a unique identifier for the message.orderis the order of the message in the thread.stepOrderis the step order of the message in the thread.statusis the status of the message (or “streaming”).agentNameis the name of the agent that generated the message.textis the text of the message._creationTimeis the timestamp of the message. For streaming messages, it’s currently assigned to the current time on the streaming client.
UIMessage from
@bijection-dev/agent.
toUIMessages helper
toUIMessages is a helper function that transforms MessageDocs into AI SDK
“UIMessage”s. This is a convenient data model for displaying messages.
If you are using useThreadMessages for instance, you can convert the messages
to UIMessages like this:
Optimistic updates for sending messages
TheoptimisticallySendMessage function is a helper function for sending a
message, so you can optimistically show a message in the message list until the
mutation has completed on the server.
Pass in the query that you’re using to list messages, and it will insert the
ephemeral message at the top of the list.
{ threadId, prompt } then you can use it as a
helper function in your optimistic update:
Saving messages
By default, the Agent will save messages to the database automatically when you provide them as a prompt, as well as all generated messages. However, it is useful to save the prompt message ahead of time and use thepromptMessageId to continue the conversation. See
Agent Usage for more details.
You can save messages to the database manually using saveMessage or
saveMessages, either on the Agent class or as a direct function call.
- You can pass a
promptor a fullmessage(ModelMessagetype) - The
metadataargument is optional and allows you to provide more details, such assources,reasoningDetails,usage,warnings,error, etc.
agent.generateText with the raw prompt, embeddings are
generated automatically for vector search (if you have a text embedding model
configured). Similarly with agent.saveMessage when calling from an action.
However, if you’re saving messages in a mutation, where calling an LLM is not
possible, it will generate them automatically if generateText receives a
promptMessageId that lacks an embedding (and you have a text embedding model
configured).
Without the Agent class:
Note: If you aren’t using the Agent class with a text embedding model set, you need to pass anembedding if you want to save it at the same time.
Using the Agent class:
skipEmbeddings: true. The embeddings for the message will be
generated lazily if the message is used as a prompt. Or you can provide an
embedding upfront if it’s available, or later explicitly generate them using
agent.generateEmbeddings.
Configuring the storage of messages
Generally the defaults are fine, but if you want to pass in multiple messages and have them all saved (vs. just the last one), or avoid saving any input or output messages, you can pass in astorageOptions object, either to the Agent
constructor or per-message.
The use-case for passing in multiple messages but not saving them is if you want
to include some extra messages for context to the LLM, but only the last message
is the user’s actual request. e.g.
messages = [...messagesFromRag, messageFromUser]. The default is to save the
prompt and all output messages.
Message ordering
Each message hasorder and stepOrder fields, which are incrementing integers
specific to a thread.
User messages saved by saveMessage or generateText are added to the thread’s
next order with a stepOrder of 0. Standalone assistant or tool messages
append to the latest order by default.
As response message(s) are generated in response to that message, they are added
at the same order with the next stepOrder.
To associate a response message with a previous message, you can pass in the
promptMessageId to generateText and others.
To start a standalone message at the next order, pass order: "next" to
saveMessage or saveMessages. The component allocates that order atomically.
To place a standalone message at a specific order, pass a number instead. If
that order is empty, the first message is saved with stepOrder: 0; otherwise
it is appended at the next stepOrder. order cannot be combined with
promptMessageId or pendingMessageId; numeric orders must be non-negative
safe integers less than Number.MAX_SAFE_INTEGER.
Note: if the promptMessageId is not the latest message in the thread, the
context for the message generation will not include any messages following the
promptMessageId.
Deleting messages
You can delete messages by their_id (returned from saveMessage or
generateText) or order / stepOrder.
By ID:
Other utilities:
serializeDataOrUrlis a utility function that serializes an AI SDKDataContentorURLto a Bijection-serializable format.filterOutOrphanedToolMessagesis a utility function that filters out tool call messages that don’t have a corresponding tool result message.extractTextis a utility function that extracts text from aModelMessage-like object.
Validators and types
There are types to validate and provide types for various valuesvMessageis a validator for aModelMessage-like object (with aroleandcontentfield e.g.).MessageDocandvMessageDocare the types for a message (which includes a.messagefield with thevMessagetype).Threadis the type of a thread returned fromcontinueThreadorcreateThread.ThreadDocandvThreadDocare the types for thread metadata.AgentComponentis the type of the installed component (e.g.components.agent).ToolCtxis thectxtype for calls tocreateTooltools.