A thread is the durable record of a task. It holds the messages and events that let an application show what happened, recover after a disconnect, and continue the conversation.
An engine session performs the work. Keeping the thread separate from that session lets the application follow a task without treating a browser connection as its lifetime.
- 01Your app sends a messageRequest
POST /threads/:id/messages - 02The runtime accepts and records itDurable
202 · seq · ts - 03An engine executes the turnRunning
Model → tool → result → model
- 04Events reach your interfaceStreaming
Live deltas for responsiveness; stored events for recovery.
- 05Your app reads the outcomeSettled
A completed or failed turn is distinct from acceptance.
Send a message, then follow the outcome
Start with an existing thread from your running runtime. Replace THREAD_ID with its ID. This example sends real work to that thread and can consume model usage.
export THREAD_ID='replace-with-an-existing-thread-id'
curl -i "http://127.0.0.1:4741/threads/$THREAD_ID/messages" \
-H 'content-type: application/json' \
-d '{"text":"Summarize the current task and its next step."}'
The runtime acknowledges an accepted message with HTTP 202 and a JSON body containing seq and ts. Save the sequence number. Acceptance means the request was recorded; the later turn result tells you whether execution succeeded.
Read what happened next
Use the acknowledged sequence number as AFTER. A forward tail reads events after that position.
export AFTER='replace-with-the-acknowledged-sequence-number'
curl -fsS \
"http://127.0.0.1:4741/threads/$THREAD_ID/tail?after=$AFTER&limit=20"
curl -fsS \
"http://127.0.0.1:4741/threads/$THREAD_ID/turn"
A forward tail page contains events, nextAfter, and hasMore. Continue with nextAfter to read another page. The SDK provides a follower that manages the ongoing connection.
Make the interface responsive
Use the asynchronous message endpoint when your UI should acknowledge a send immediately. Render live deltas while the turn is running, then reconcile against stored events. Keep the latest durable cursor so a reconnect can pick up after it.
| Surface | Best use |
|---|---|
| Thread summaries | A task list or sidebar |
| Durable event pages | History, recovery, and recorded outcomes |
| Live deltas | Showing an answer as it is generated |
| Turn status | Understanding the current execution state |
The /send endpoint offers a different contract: it holds the request until the turn settles and returns the reply. Use it when your caller needs a single awaited answer.
What survives a restart
Thread records and ordered events are stored in SQLite. Large event bodies can be stored in the associated blob directory. Engine transcripts and resume state have their own files. Preserve the database, blobs, and engine state when backing up or moving a deployment.
A durable record lets an application recover recorded history. Resuming execution also depends on the engine's resume state and provider behavior.
Coordinate more than one task
The runtime exposes child threads, subscriptions, approvals, interruption, and handoffs. A child has its own history, so its work can be inspected independently. Coordination records relate that work to its parent.
Start with one thread and its event stream before building a coordinator. The same read-and-follow pattern remains useful as the number of tasks grows.