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.
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 previously failed fast enough to return a definitive status: "error" within the wait window can instead exhaust this endpoint's own wait timeout first, returning 504 Gateway Timeout — the run itself is not cancelled by that timeout and keeps restarting host-side; poll GET /threads/{id}/runs/{runId} afterward for the actual outcome rather than treating a 504 as a definitive failure. 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=30s200 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!"}
]
}
}

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 InvokeRun 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