Messages
Each thread owns an ordered, persistent list of messages — the conversation history the agent reasons over. Tools, hooks, and endpoints read, inject, queue, and update these messages through ThreadState.
This page documents the message record, the APIs for manipulating the list, and delivery semantics for queued messages. Thread identity, execution state, and everything else about threads live on the Threads parent page.
Note: The APIs on this page mutate persisted message storage. To modify, inject, or filter messages non-destructively — only for the current model call, with the stored history untouched — use Hooks, specifically
filter_messages,prefilter_llm_history,before_create_message, andbefore_update_message.
1. Message Structure
| Property | Type | Description |
|---|---|---|
id | string | Unique message ID |
role | 'system' | 'user' | 'assistant' | 'tool' | Message role |
content | string | null | Message content |
name | string | null | Tool name (for tool results) |
tool_calls | string | null | JSON-encoded tool calls |
tool_call_id | string | null | Tool call ID (for results) |
created_at | number | Creation timestamp |
parent_id | string | null | Parent message (sub-prompts) |
depth | number | Nesting depth (0 = top-level) |
silent | boolean | Hidden from UI |
metadata | Record<string, unknown> | Custom metadata (may include runtime status markers such as status_kind) |
subagent_id | string | null | Subagent reference UUID associated with the message |
subagent_name | string | null | Projected child agent name (when available) |
subagent_title | string | null | Projected child agent title (when available) |
subagent_description | string | null | Projected child description (when available) |
subagent_status | string | null | Projected child status (when available) |
subagent_resumable | boolean | null | Projected resumable flag (when available) |
subagent_blocking | boolean | null | Projected blocking flag (when available) |
subagent_thread_name | string | null | Projected human-friendly child instance name (when available) |
subagent_spawn_group_id | string | null | Projected spawn grouping identifier (when available) |
2. Reading Messages
// Get recent messages
const { messages, total, hasMore } = await state.getMessages({
limit: 50,
order: 'desc',
});
// Get a single message
const message = await state.getMessage('msg-123');
2.1 Query Options
| Option | Type | Default | Description |
|---|---|---|---|
limit | number | - | Max messages to return |
offset | number | 0 | Messages to skip |
order | 'asc' | 'desc' | 'desc' | Sort order |
includeSilent | boolean | false | Include silent messages |
maxDepth | number | - | Max nesting depth |
3. Injecting Messages
Messages can be injected into the conversation:
const message = await state.injectMessage({
role: 'user',
content: 'Additional context...',
silent: true, // Hide from UI
metadata: { source: 'tool' },
});
4. Queueing Messages
Messages can be queued for delivery on the next execution step:
await state.queueMessage({
role: 'user', // maps to side_b perspective
content: 'Follow-up task',
silent: true,
});
Queue semantics:
- If the thread is executing, queued messages are injected before the next LLM request.
- If the thread is idle, queueing forces a new turn.
- Queued messages are processed in order.
5. Updating Messages
Existing messages can be updated:
const updated = await state.updateMessage('msg-123', {
content: 'Updated content',
metadata: { edited: true },
});
6. Deleting Messages
const deleted = await state.deleteMessage('msg-123');
Returns true if the message was found and removed, false otherwise. Tool-result messages cascade with their parent assistant message.