Skip to main content

Threads

AgentFlow organises conversation history into threads. Each thread has a unique thread_id and stores a sequence of messages and a state snapshot (checkpoint). The client provides methods to list, inspect, update, and delete threads and their messages.

Requires checkpointer

Thread endpoints require the checkpointer field to be configured in agentflow.json. Without a checkpointer the server returns empty results or 404 for single-thread operations.

Source: src/client.ts, src/endpoints/threads*.ts, src/endpoints/threadState.ts


Thread management

threads(request?)

List all threads. Supports optional search and pagination.

// List all threads
const response = await client.threads();

// With search
const response = await client.threads({ search: 'Paris' });

// With pagination
const response = await client.threads({ offset: 0, limit: 20 });

Overloads:

client.threads(): Promise<ThreadsResponse>
client.threads(request: ThreadsRequest): Promise<ThreadsResponse>
client.threads(search?: string, offset?: number, limit?: number): Promise<ThreadsResponse>

ThreadsRequest:

FieldTypeDescription
searchstringSubstring filter applied to thread names.
offsetnumberNumber of threads to skip (for pagination). Must be ≥ 0.
limitnumberMaximum number of threads to return. Must be > 0.

ThreadsResponse:

interface ThreadsResponse {
data: {
threads: ThreadItem[];
};
metadata: ResponseMetadata;
}

interface ThreadItem {
thread_id: string;
thread_name: string | null;
user_id: string | null;
metadata: Record<string, any> | null;
updated_at: string | null;
run_id: string | null;
}

threadDetails(threadId)

Fetch metadata for a single thread.

const response = await client.threadDetails('thread-123');
console.log(response.data.thread_data.thread);

Parameters:

ParameterTypeDescription
threadIdstring | numberThe thread ID. Must be non-empty (string) or ≥ 1 (integer).

ThreadDetailsResponse:

interface ThreadDetailsResponse {
data: {
thread_data: {
thread: Record<string, any>;
};
};
metadata: ResponseMetadata;
}

deleteThread(threadId, config?)

Delete a thread and all its associated state and messages. This is irreversible.

await client.deleteThread('thread-123');

// With optional config
await client.deleteThread('thread-123', { user_id: 'u-456' });

Parameters:

ParameterTypeDescription
threadIdstring | numberThe thread ID to delete.
configRecord<string, any>Optional configuration passed with the delete request body.

Thread state

threadState(threadId)

Fetch the current state snapshot for a thread (the full graph state at the last checkpoint).

const response = await client.threadState(12345);
console.log(response.data);
// { state: { messages: [...], user_id: 'abc', ... } }

Parameters:

ParameterTypeDescription
threadIdnumberThe thread ID. Note: this method accepts numbers only (not strings) because state is keyed on the integer thread ID.

updateThreadState(threadId, config, state)

Write a new state snapshot for a thread. Use this to seed initial state, repair a corrupted thread, or inject values that the graph needs but cannot derive from messages alone.

await client.updateThreadState(
12345,
{ configurable: {} }, // run config
{ user_preferences: { lang: 'fr' } } // new state
);

Parameters:

ParameterTypeDescription
threadIdnumberThe thread ID.
configRecord<string, any>LangGraph-style run configuration map.
stateanyNew state object to write. Keys must match the graph's state schema.

clearThreadState(threadId)

Delete all checkpointed state for a thread. The thread itself (its metadata and messages) is not deleted — only the state snapshot is cleared.

await client.clearThreadState(12345);

Parameters:

ParameterTypeDescription
threadIdnumberThe thread ID.

Messages

threadMessages(threadId, request?)

List messages for a thread with optional search and pagination.

// All messages
const response = await client.threadMessages('thread-123');

// With search term
const response = await client.threadMessages('thread-123', 'capital');

// As a request object
const response = await client.threadMessages('thread-123', {
search: 'capital',
offset: 0,
limit: 50,
});

Overloads:

client.threadMessages(threadId: string | number): Promise<ThreadMessagesResponse>
client.threadMessages(threadId: string | number, request: ThreadMessagesRequest): Promise<ThreadMessagesResponse>
client.threadMessages(threadId: string | number, search?: string, offset?: number, limit?: number): Promise<ThreadMessagesResponse>

ThreadMessagesRequest (without threadId):

FieldTypeDescription
searchstringSubstring filter applied to message content.
offsetnumberNumber of messages to skip (≥ 0).
limitnumberMaximum number to return (> 0).

ThreadMessagesResponse:

interface ThreadMessagesResponse {
data: {
messages: Message[];
total?: number;
};
metadata: ResponseMetadata;
}

addThreadMessages(threadId, messages, config?, metadata?)

Append messages to a thread's saved history. Useful for injecting context, system prompts, or synthetic messages without running the graph.

await client.addThreadMessages(
'thread-123',
[Message.text_message('You are a travel guide.', 'system')],
{ configurable: {} }, // config
{ injected_by: 'setup' } // metadata
);

Parameters:

ParameterTypeDefaultDescription
threadIdstring | numberThe thread ID.
messagesMessage[]Messages to append.
configRecord<string, any>{}Run configuration map.
metadataRecord<string, any>undefinedOptional metadata attached to the checkpoint.

singleMessage(threadId, messageId)

Fetch a single message from a thread by message ID.

const response = await client.singleMessage('thread-123', 'msg-001');
console.log(response.data.message);

Parameters:

ParameterTypeDescription
threadIdstring | numberThe thread ID.
messageIdstringThe message ID. Must be non-empty.

deleteMessage(threadId, messageId, config?)

Delete a single message from a thread by message ID.

await client.deleteMessage('thread-123', 'msg-001');

Parameters:

ParameterTypeDescription
threadIdstring | numberThe thread ID.
messageIdstringThe message ID to delete. Must be non-empty.
configRecord<string, any>Optional configuration passed in the request body.

Validation rules

These rules are enforced by the server and will produce AgentFlowError status 422 if violated:

RuleDescription
thread_id non-emptyString thread IDs must not be empty or whitespace. Integer IDs must be ≥ 1.
message_id non-emptymessageId must not be empty.
offset ≥ 0Pagination offset must be a non-negative number.
limit > 0Pagination limit must be a positive number.

Common patterns

Paginate through all threads

async function* allThreads(pageSize = 50) {
let offset = 0;
while (true) {
const response = await client.threads({ offset, limit: pageSize });
const threads = response.data.threads;
if (threads.length === 0) break;
yield* threads;
offset += threads.length;
if (threads.length < pageSize) break;
}
}

for await (const thread of allThreads()) {
console.log(thread.thread_id, thread.thread_name);
}

Display a conversation history

const response = await client.threadMessages('thread-123', {
offset: 0,
limit: 100,
});

for (const msg of response.data.messages) {
const text = msg.content
.filter(b => b.type === 'text')
.map(b => (b as any).text)
.join('');
console.log(`[${msg.role}] ${text}`);
}

Reset a thread

// Keep the thread metadata but wipe the state
await client.clearThreadState(12345);

// Or delete everything including metadata and messages
await client.deleteThread('thread-123');

Common errors

ErrorCauseFix
AgentFlowError status 404Thread not found, or no checkpointer configured.Verify thread_id, and confirm checkpointer is set in agentflow.json.
AgentFlowError status 422Validation failure — invalid thread_id, empty message_id, bad pagination values.Check the field constraints listed in Validation rules.

What you learned

  • Threads persist conversation history and state between invoke() calls when a thread_id is set in config.configurable.
  • threadMessages() supports search and pagination.
  • clearThreadState() removes the state snapshot but not the thread or messages.
  • All thread operations require the checkpointer to be configured in agentflow.json.

Next step

See reference/client/memory to learn how to store and search long-term memories beyond per-thread conversation history.