Agents sometimes need to pause: to get human approval before executing a sensitive action, to request structured input, to wait on an out-of-band policy decision. AG-UI exposes this as an interrupt-aware run lifecycle — a terminal model where the run ends with an interrupt outcome, and the client starts a new run carrying per-interrupt responses.Documentation Index
Fetch the complete documentation index at: https://docs.ag-ui.com/llms.txt
Use this file to discover all available pages before exploring further.
Lifecycle
Run outcomes
RunFinished carries an optional outcome field — a discriminated union with
the variant-specific data nested inside:
- omitted — legacy/back-compat. Treated as a normal completion. Pre-existing AG-UI clients that did not yet know about interrupts still emit this shape, and new readers should accept it.
{ type: "success" }— the run completed normally. The optionalresultstays at the root of the event for back-compat.{ type: "interrupt", interrupts: [...] }— the run paused for user input.interruptsis a non-empty array, and it lives inside the outcome so it travels with the variant that needs it.
outcome is optional, an old producer that has never heard of
interrupts (no outcome field) still validates as a RunFinished event under
the new schema — clients only need to inspect outcome when they care about
the interrupt-aware variant.
The Interrupt type
| Field | Purpose |
|---|---|
id | Correlation key across interrupt, resume, idempotency, and audit. |
reason | Categorical routing hint — see Reason taxonomy. |
message | Human-readable prompt. Universal fallback UI content. |
toolCallId | Binds the interrupt to a prior ToolCall* sequence. |
responseSchema | JSON Schema for the expected resume.payload. |
expiresAt | Optional ISO-8601 TTL. Stale resumes produce RunError. |
metadata | Free-form framework-specific data. |
Resuming a run
The nextRunAgentInput on the same thread carries a resume array:
resolved— the user responded.payloadcarries the response, validated against the interrupt’sresponseSchema. Denials are expressed inside the payload (for example,{ approved: false }), not as a separate status.cancelled— the user abandoned without providing meaningful input.payloadshould be omitted.
Contract rules
- Same thread. Resume requests must use the same
threadIdas the interrupted run. - Resume linkage.
resume[].interruptIdmust reference anidfrom the interrupted run’sinterrupts[].parentRunIdis orthogonal — it retains its existing AG-UI branching/time-travel semantics. - Cover all open interrupts. A single
resumearray must address every open interrupt from the interrupted run. Partial resumes are not supported. - Pending interrupts block new input. If a thread has unresolved
interrupts, any
RunAgentInputon that thread must include aresumeaddressing them. Agents receiving a non-conforming input must emitRunError. - Idempotency. A resume with the same
(threadId, interruptId, status, payload)must be safe to replay. - Payload validation. If an interrupt declares a
responseSchema, the agent may validate the corresponding resumepayloadand emitRunErroron mismatch. Clients should validate before submitting. - Expiry enforcement. Clients must not submit a resume past an
interrupt’s
expiresAt. Stale resumes produceRunError. - Graceful handling. Agents should handle missing or invalid resume
payloads via
RunError, not silent failures.
State at the interrupt boundary
At the moment of interrupt, the agent must emit any state required for resume viaStateSnapshot and MessagesSnapshot events before the
RunFinished event that carries the interrupt.
This rule makes the protocol resume-mode-agnostic: both replay-style
continuations (rebuild context from messages + state) and checkpoint-style
continuations (restore a suspended coroutine) must produce identical
observable behavior on resume. Framework-native checkpointing is an
implementation optimization, not a protocol contract.
Error handling
RunError is the sole error event. The outcome enum does not carry an
"error" value. Interrupt-specific error conditions that produce RunError:
- A resume arrives past an interrupt’s
expiresAt. - A resume payload fails validation against its
responseSchema. - A resume references an
interruptIdthe agent cannot correlate. - A resume fails to address every open interrupt (violates rule 3).
- A
RunAgentInputon a thread with pending interrupts omitsresume(violates rule 4).
Reason taxonomy
reason is a required string. A small set of core values is spec-defined; any
other string is a valid extension.
Core values
| Value | Semantics | Typical companion fields |
|---|---|---|
tool_call | Interrupt bound to a specific tool call awaiting decision. | toolCallId must be set. |
input_required | Agent needs structured input to continue. | responseSchema should be set. |
confirmation | Free-standing yes/no decision not bound to a tool. | responseSchema optional; boolean default. |
Custom reasons
Any other string is valid. Agents should namespace custom reasons as<framework>:<name> (for example, langgraph:database_modification,
mastra:workflow_suspend). The core: prefix is reserved for future spec
additions.
Client routing
- Clients should switch on known core values for dedicated UI.
- For unknown reasons, clients must not error. Render from
message,responseSchema, andmetadata.
Tool-bound interrupts
When an interrupt carriesreason: "tool_call" and a toolCallId, the tool
call and its resolution span two runs. The full audit trail is:
ToolCallArgsfrom the interrupted run (the agent’s proposal).RunAgentInput.resumepayload from the resumed run (user decision and edits).ToolCallResultfrom the resumed run (actual execution outcome).
ToolCallStart/ToolCallArgs/ToolCallEnd
in the resumed run — it emits ToolCallResult against the original
toolCallId.
Approve with edits
The recommendedresponseSchema pattern for tool-bound interrupts that
support approve-with-edits:
editedArgs is a full replacement, not a partial merge. Its presence in the
schema is the capability signal that the client may offer edit UI.
Examples
Minimal tool approval
The agent interrupts after proposingsendEmail:
run-2, emits ToolCallResult against tc-001, then
RunFinished { outcome: { type: "success" } }.
Approve with edits (full audit)
tc-42:
run-10ToolCallArgs— original proposal.run-11RunAgentInput.resume[0].payload.editedArgs— user edits.run-11ToolCallResult— actual outcome.
Parallel interrupts
run-21 the agent emits ToolCallResult for tc-a and tc-b and treats
tc-c as not-executed.
Non-tool input request
Related
- Events — how
RunFinishedfits into the broader event stream. - Capabilities — the
humanInTheLoop.interruptsandhumanInTheLoop.approveWithEditsflags agents declare.