State API
Get and update thread state directly.
Get State
GET /threads/{thread_id}/state
Response
{
"thread_id": "thread-abc123",
"values": {
"step_count": 2,
"shopping_items": ["milk", "eggs"]
},
"messages": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi there!"}
]
}
Query Parameters
| Parameter | Default | Description |
|---|---|---|
subgraphs | false | Accepted for Agent Protocol parity. AgentVisor has no per-task subgraph tree, so this has no observable effect beyond not erroring. Parsed leniently: an unparseable value (e.g. ?subgraphs=yes) is silently treated as false rather than rejected, matching limit's parsing on this and other endpoints. |
Fields
| Field | Description |
|---|---|
thread_id | The thread ID |
values | Current state values |
messages | Optional. Conversation history, if the agent's state schema tracks messages |
checkpoint | Omitted on this default (root, current head) call. Present on the checkpoint-targeted variants below. |
There is no next field — use Thread History to inspect checkpoints.
Example
curl http://localhost:8090/threads/thread-abc123/state | jq
Get State at a Checkpoint
Target a specific checkpoint or namespace (LangGraph subgraph) instead of the thread's current root state.
POST /threads/{thread_id}/state/checkpoint
Request Body
{
"checkpoint": {
"checkpoint_ns": "",
"checkpoint_id": "cp-002"
},
"subgraphs": false
}
| Field | Description |
|---|---|
checkpoint.checkpoint_ns | Optional. Selects a namespace (empty string is the root graph). Ignored when checkpoint_id is set — checkpoint IDs are already globally unique across namespaces. |
checkpoint.checkpoint_id | Optional. Targets a specific checkpoint. Empty resolves to the current head of checkpoint_ns. |
subgraphs | Accepted for Agent Protocol parity; has no observable effect (see above). |
Alternatively, fetch by checkpoint ID directly:
GET /threads/{thread_id}/state/{checkpoint_id}?subgraphs=false
Response
Same shape as Get State, but checkpoint is always populated:
{
"thread_id": "thread-abc123",
"values": {"step_count": 2},
"checkpoint": {
"thread_id": "thread-abc123",
"checkpoint_ns": "",
"checkpoint_id": "cp-002"
}
}
Example
curl -X POST http://localhost:8090/threads/thread-abc123/state/checkpoint \
-H "Content-Type: application/json" \
-d '{"checkpoint": {"checkpoint_id": "cp-002"}}'
curl http://localhost:8090/threads/thread-abc123/state/cp-002
Update State
POST /threads/{thread_id}/state
Update thread state. Useful for:
- Setting initial values
- Correcting state
- Injecting data
Request Body
The entire JSON body is the values map — there is no values/as_node wrapper, and
as_node is not supported.
{
"shopping_items": ["milk", "eggs", "bread"]
}
Response
{
"thread_id": "thread-abc123",
"values": {
"shopping_items": ["milk", "eggs", "bread"]
}
}
The response does not include messages, even if the update body contains a messages key.
Example
curl -X POST http://localhost:8090/threads/thread-abc123/state \
-H "Content-Type: application/json" \
-d '{"approved": true}'
Updating Messages
To add a message to the conversation:
curl -X POST http://localhost:8090/threads/thread-abc123/state \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "assistant", "content": "Injected message"}]
}'
Note: Messages use the add_messages reducer, so new messages are appended.
State vs Run
| Approach | Use Case |
|---|---|
| Update state | Inject data without running agent |
| Create run | Execute agent with new input |
For human-in-the-loop, you typically:
- Create run with user input
- Agent processes and may
interrupt() - Get state to see interrupt payload
- Create new run with user's response
You don't usually need to update state directly unless you're:
- Correcting errors
- Initializing state
- Testing