Copy page
View as Markdown View this page as plain text

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, and before_update_message.

1. Message Structure

PropertyTypeDescription
idstringUnique message ID
role'system' | 'user' | 'assistant' | 'tool'Message role
contentstring | nullMessage content
namestring | nullTool name (for tool results)
tool_callsstring | nullJSON-encoded tool calls
tool_call_idstring | nullTool call ID (for results)
created_atnumberCreation timestamp
parent_idstring | nullParent message (sub-prompts)
depthnumberNesting depth (0 = top-level)
silentbooleanHidden from UI
metadataRecord<string, unknown>Custom metadata (may include runtime status markers such as status_kind)
subagent_idstring | nullSubagent reference UUID associated with the message
subagent_namestring | nullProjected child agent name (when available)
subagent_titlestring | nullProjected child agent title (when available)
subagent_descriptionstring | nullProjected child description (when available)
subagent_statusstring | nullProjected child status (when available)
subagent_resumableboolean | nullProjected resumable flag (when available)
subagent_blockingboolean | nullProjected blocking flag (when available)
subagent_thread_namestring | nullProjected human-friendly child instance name (when available)
subagent_spawn_group_idstring | nullProjected 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

OptionTypeDefaultDescription
limitnumber-Max messages to return
offsetnumber0Messages to skip
order'asc' | 'desc''desc'Sort order
includeSilentbooleanfalseInclude silent messages
maxDepthnumber-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.