Messages and Parts
Read Active and Segment history and understand Messages, Parts, and sequence
Messages and Parts
session.messages() returns every persisted Message in the current Active set. It does not take a limit; subscribe() complements the snapshot with live changes.
const page = await session.messages();
for (const message of page.items) {
render_message(message);
}It returns:
interface SessionMessagePage {
items: SessionMessage[];
total: number;
source: "active" | "segment";
start_sequence?: number;
end_sequence?: number;
next_before_sequence?: number;
has_more: boolean;
}total is the total number of real Messages created by the Session, not items.length. source identifies whether the result came from Active or one closed Segment.
Four top-level Message types
type | Meaning | Typical presentation |
|---|---|---|
user | User input or in-flight steering | User bubble and attachments |
assistant | One generated model response segment | Text, reasoning, tools, files |
action | Runtime activity such as a model change or compaction | Status notice |
error | A displayable Session or Turn error | Error callout and retry entry point |
A Session has one top-level Message sequence ordered by sequence. Tool calls are neither a second Timeline nor top-level Messages: they live in an Assistant Message's parts, so text -> tool -> text is persisted in its real generation order.
Assistant Parts
type | Key fields | Meaning |
|---|---|---|
text | text, state | Visible output, streaming -> done |
reasoning | text, state | Reasoning output; product decides whether to display it |
tool | tool_call_id, tool_name, state | Tool input, approval, execution, and result |
file | url, media_type | A file generated or referenced by the Assistant |
data | data_type, data | Structured UI data |
Every Assistant Part has a stable part_id and immutable internal sequence. A tool state change updates the same Part; a UI should not create separate request and result rows.
Order, revision, and visibility
Every Message has a stable message_id, a creation-time sequence that never changes, and a revision that increases with each complete snapshot update. A client must not replace a greater revision with a lower one.
messages() returns only visibility: "visible" Messages by default. Pass include_internal: true for debugging or audit. A Compact Summary is not a Message, consumes no sequence, and never appears in messages().
Loading older history
Call the method with no arguments first to load all Active Messages. When has_more is true, pass next_before_sequence back unchanged to read the immediately preceding whole Segment:
let page = await session.messages();
render_messages(page.items);
while (page.has_more && page.next_before_sequence !== undefined) {
page = await session.messages({
before_sequence: page.next_before_sequence,
});
prepend_messages(page.items);
}before_sequence must be a positive integer. Each historical read returns one complete Segment. There is no limit, cursor, offset, or slicing within a Segment. This keeps UI boundaries aligned with physical Compact boundaries and avoids reading cumulative Summaries as Messages.
Combining snapshots with live Mutations
- Use
messages()to establish the Active state. - Replace the targeted snapshot for a
messageorpartMutation. - Append new text for a
deltaMutation. - Load older Segments one at a time with
next_before_sequence. - On disconnect, reload Active and merge by
message_id + revision.
See Reconnect and sync for synchronization and Metadata and storage for persistence details.