Skip to main content

Runs API

Runs are individual agent executions within a thread.

Create Run​

POST /threads/{thread_id}/runs

Request Body​

{
"input": {
"messages": [
{"role": "user", "content": "Hello!"}
]
},
"agent_id": "my-agent",
"metadata": {"source": "cli"},
"config": {
"temperature": 0.7
}
}
FieldDescription
inputInput data passed to the agent
agent_idOptional. Graph/agent name to invoke (defaults to the first agent in langgraph.json)
metadataOptional. Arbitrary key/value metadata for the run
configOptional. Run configuration passed through to the agent

Query Parameters​

ParameterDefaultDescription
wait (alias timeout)-Wait for completion. Accepts a duration string (e.g. 30s, 5m) or a plain integer number of seconds. Capped at 10 minutes.

If the run reaches a terminal status before wait elapses, the response is 200 OK with the final RunResponse (see below). If wait elapses first, the response is still 200 OK, but with the run's current non-terminal status (running today — see the async response below) instead — the run is not cancelled by this and keeps executing; poll GET /threads/{id}/runs/{runId} for its eventual outcome.

Automatic restart shares this wait budget

If the run hits an infrastructure or guest-crash failure, AgentVisor™ restarts it automatically (see Run Status below) before this call's wait completes — the 10-minute cap is unchanged, but restart backoff now consumes part of it. A run that would otherwise have reached a definitive status: "error" within the wait window can instead still be mid-restart when wait elapses, so this call returns its current non-terminal status just as it would for any other still-running run — poll GET /threads/{id}/runs/{runId} afterward for the actual outcome. Set temporal.run_restart.max_attempts: 0 to disable automatic restart entirely if this budget-sharing is undesirable for a given deployment.

Response (Async — 202 Accepted)​

{
"run_id": "thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"thread_id": "thread-abc123",
"status": "running",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}

The current implementation transitions a run straight to running on creation — pending is a defined status value but not currently reachable via this endpoint.

run_id is a composite {thread_id}_{run_uuid} string. Use it as-is with the Run by ID endpoints, or the trailing UUID portion as {run_id} under /threads/{thread_id}/runs/{run_id}.

Response (with ?wait=30s, run completes in time — 200 OK)​

{
"run_id": "thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"thread_id": "thread-abc123",
"status": "completed",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:05Z",
"output": {
"messages": [
{"role": "user", "content": "Hello!"},
{"role": "assistant", "content": "Hi there!"}
]
}
}

If wait instead elapses before the run completes, the response is the same shape as the async response above (status: "running", no output), still 200 OK.

Example​

# Async
curl -X POST http://localhost:8090/threads/thread-abc123/runs \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Hello"}]}}'

# Sync (wait for result)
curl -X POST "http://localhost:8090/threads/thread-abc123/runs?wait=30s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Hello"}]}}'

List Runs​

GET /threads/{thread_id}/runs

Query Parameters​

ParameterDefaultDescription
limit100Max number of runs to return (max 1000)
offset0Pagination offset

Response​

[
{
"run_id": "thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"thread_id": "thread-abc123",
"status": "completed",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:05Z"
},
{
"run_id": "thread-abc123_b2c3d4e5-f6a7-8901-bcde-f12345678901",
"thread_id": "thread-abc123",
"status": "completed",
"created_at": "2024-01-15T10:25:00Z",
"updated_at": "2024-01-15T10:25:03Z"
}
]

Get Run​

GET /threads/{thread_id}/runs/{run_id}

Response​

{
"run_id": "thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"thread_id": "thread-abc123",
"status": "completed",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:05Z",
"output": {
"messages": [
{"role": "user", "content": "Hello!"},
{"role": "assistant", "content": "Hi there!"}
]
}
}

There is no input field on the run response — the run's input is not persisted; retrieve it from thread state or history instead.

Run Status​

StatusDescription
pendingDefined for a run not yet started; not currently returned by any endpoint
runningExecution in progress (the status of a newly-created run). A run that hit an infrastructure or guest-crash failure and is automatically restarting also reports running throughout — restart never introduces a separate status
completedFinished successfully
interruptedWaiting for human input
errorExecution failed (including a restartable failure whose restart budget was exhausted)
cancellingCancellation requested, not yet stopped
cancelledCancelled by user

Automatic Restart Fields​

Two additional fields on the run object surface AgentVisor's automatic restart history for infrastructure/guest-crash failures, and — since a Continue-As-New-triggered interruption of an active run is bookkept the same way — a CAN boundary too (see Recovery Scenarios). Both are omitted entirely unless the run has restarted at least once — a run that succeeded or failed on its first attempt never sets them:

FieldTypeDescription
attemptinteger1-indexed count of invocation attempts made for this run. Absent/0 means the run has not restarted; treat an absent value as 1.
last_failurestringThe failure class (CRASH, INFRA, or CAN for a Continue-As-New-triggered interruption) of the failure that most recently triggered a restart. Empty if the run never restarted.
{
"run_id": "thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"thread_id": "thread-abc123",
"status": "completed",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:12Z",
"attempt": 2,
"last_failure": "CRASH",
"output": {
"messages": [
{"role": "user", "content": "Hello!"},
{"role": "assistant", "content": "Hi there!"}
]
}
}

These fields report only the final attempt's outcome via status/output/error — they are restart history, not a state machine of their own. See temporal.run_restart in the configuration reference for the attempt-budget, backoff, and max_attempts: 0 disable knob.

Stream Run​

GET /threads/{thread_id}/runs/{run_id}/stream

Returns a Server-Sent Events (SSE) stream. See the Streaming guide for the full event framing reference. Summary for this endpoint:

  • One event per chunk, named after the chunk type (values, updates, messages, or custom), with data set to the chunk's raw payload object.
  • A final done event with an empty {} payload once the stream completes.
  • An error event with {"error": "<message>"} if streaming fails.

Response​

event: values
data: {"messages": [{"role": "assistant", "content": "Hi"}]}

event: values
data: {"messages": [{"role": "assistant", "content": "Hi there!"}]}

event: done
data: {}

Example​

curl -N http://localhost:8090/threads/thread-abc123/runs/run-xyz789/stream

Cancel Run​

POST /threads/{thread_id}/runs/{run_id}/cancel

Idempotent for already-terminal runs.

Response​

Returns 202 Accepted with the full run object:

{
"run_id": "thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"thread_id": "thread-abc123",
"status": "cancelling",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:02Z"
}

Stateless Runs​

Execute without a persistent thread.

Stateless Run (Async)​

POST /runs

Creates an ephemeral thread and run. Returns 202 Accepted immediately with the same RunResponse shape as Create Run (including status: "running").

Request Body​

{
"input": {"messages": [{"role": "user", "content": "Hello"}]},
"agent_id": "my-agent"
}

Stateless Run (Sync)​

POST /runs/wait

Blocks until completion and returns 200 OK with the final RunResponse. Same 10-minute default/cap and automatic-restart budget-sharing as Create Run's wait parameter.

curl -X POST http://localhost:8090/runs/wait \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Hello"}]}}'

Stateless Run (Streaming)​

POST /runs/stream

Returns an SSE stream. Unlike Stream Run, this endpoint first emits a start event, then one event per chunk with data wrapped as {"type": "<chunk type>", "data": {...}}, and finally a done event whose data is the full final RunResponse object (empty {} if the final run lookup fails).

event: start
data: {"run_id": "...", "thread_id": "...", "status": "pending"}

event: values
data: {"type": "values", "data": {"messages": [...]}}

event: done
data: {"run_id": "...", "thread_id": "...", "status": "completed", ...}
curl -N -X POST http://localhost:8090/runs/stream \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Hello"}]}}'

Run by ID​

After creating a stateless run, you can manage it by run ID without referencing the (ephemeral) thread it was created in. The same set of endpoints also work for runs created within an explicit thread — pass the full composite run_id ({thread_id}_{run_uuid}) returned by any run response.

Get Run​

GET /runs/{run_id}

Returns the run's current status and (if completed) output. Same response shape as GET /threads/{id}/runs/{runId} — there is no input field.

curl http://localhost:8090/runs/thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890 | jq

Wait for Run​

GET /runs/{run_id}/wait

Blocks until the run reaches a terminal status (completed, error, or cancelled) and returns the final response, 200 OK. Accepts the same wait/timeout query parameter as Create Run; defaults to and caps at 10 minutes. If the wait window elapses first — now more likely for a run that's mid automatic-restart-backoff, see the Create Run note — this returns 504 Gateway Timeout instead; the run is not cancelled and its current status can still be polled via GET /runs/{run_id} above.

curl http://localhost:8090/runs/thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890/wait | jq

Stream Run​

GET /runs/{run_id}/stream

Returns Server-Sent Events for the run. Not the same event shape as GET /threads/{id}/runs/{runId}/stream: chunk data here is wrapped as {"type": "<chunk type>", "data": {...}}, and the final done event's data is the full final RunResponse object (empty {} if the final run lookup fails) rather than {}.

curl -N http://localhost:8090/runs/thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890/stream

Cancel Run​

POST /runs/{run_id}/cancel

Returns 202 Accepted with the full run object. Idempotent for already-terminal runs.

curl -X POST http://localhost:8090/runs/thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890/cancel

Delete Run​

DELETE /runs/{run_id}

Removes a run record, returning 204 No Content. Blocked (409 Conflict) while the run is pending or running.

curl -X DELETE http://localhost:8090/runs/thread-abc123_a1b2c3d4-e5f6-7890-abcd-ef1234567890