.NET API
RunStatus
Tracon.Abstractions.dllStatus of a run.
[JsonConverter(typeof(JsonStringEnumConverter<RunStatus>))]public enum RunStatusFields
Section titled “Fields”AwaitingApproval = 6
The run waits for an operator to decide on a tool call and cannot advance without that decision.
Seen on any root (Depth == 0) agent run, whatever started it
— the management API, an OpenAI-compatible endpoint, MCP, A2A, or the queue
(Prefer: respond-async). The first version covered only the queue path: the synchronous
paths did not reflect this status at all, and a tool call waiting for
approval silently looked RunStatus.Completed. However the decision
arrives — POST /api/approvals/{id}/decide for the queue, the caller’s
own next turn for synchronous callers — the status label follows the same
principle.
It follows the SAME principle as RunStatus.AwaitingInput: an answered run
stays in this status, because rewriting history would break the
append-only rule of the event stream. On the queue path the decision
is made through POST /api/approvals/{id}/decide, which enqueues a
new run (same sessionId, new RunId).
The value was appended at the end for the same reason as RunStatus.AwaitingInput.
AwaitingInput = 4
The run waits for human input and cannot advance without it.
Seen on RunKind.Workflow rows, and on the root agent run of a tool call an
MCP server suspended to ask the user for input (MCP elicitation). When a workflow reaches an
external request port — Magentic plan approval, for example —
execution stops, its state is written to a checkpoint and the stream closes.
The answer arrives through POST /api/workflows/runs/{runId}/respond,
which opens a new run that resumes from the checkpoint.
On an agent run the request is the next turn’s input, the same as an approval: the caller
answers in the inputResponses of the next run request of the same session, and the
suspended tool call runs again from its start with the answer. Only a run started through the
management API’s run endpoint can wait this way; on every other surface (an OpenAI-compatible
call, A2A, an MCP tool call, a queued run) and below the root of an agent tree the server’s
request is declined.
The value was appended at the end: statuses are stored as smallint in
the database and shifting the existing values would misread old rows. An
answered run stays AwaitingInput; rewriting history would
break the append-only rule of the event stream. The continued work
shows up in the new run row.
Canceled = 3
The run was cancelled.
Completed = 1
The run finished successfully.
Failed = 2
The run ended with an error.
Queued = 5
The run has not started its work: it waits for a worker, or for a concurrency slot.
Seen for runs started with Prefer: respond-async. The
row is written as Queued at enqueue time; when the worker actually
runs the job the same id is written again and moves to RunStatus.Running.
Seen too for a workflow run that waits, in the process that runs it, for a slot of
Tracon:Workflows:MaxConcurrentRuns or of MaxConcurrentRunsPerTenant. No job
holds that run; the process does, and writes a heartbeat for it, so run reconciliation closes
the row if the process is gone. The row moves to RunStatus.Running when the run has its slots.
The value was appended at the end for the same reason as RunStatus.AwaitingInput.
Running = 0
The run is in progress.
Remarks
Section titled “Remarks”Written to JSON by name ("Code"), not by number. The
wire contract explains itself that way and survives a change in value order.
The converter sits on the type, so the format is the same everywhere without
touching the consumer’s application-wide JSON options. No enum is PERSISTED as
JSON (RunStatus and RunEventType are smallint in the database,
AgentDefinitionOrigin is rebuilt on read), so a format change does not affect
stored data.