Skip to main content

11. HTTP and AG-UI reference

11.1 Endpoints​

Method and pathAuthPurpose
GET /_ping, GET /_health, GET /_readiness—liveness; readiness also checks the database and queue
GET /api/agents—the enabled workflows: id, title, description, version, ui, state_whitelist
POST /agui/{workflow}Bearerstart or resume a run (server-sent events)
POST /api/documentsBearer, documents.uploadupload; optional workflow field starts a run
GET /api/runs/{thread}Bearer, runs.readstatus, whitelisted state and open interrupt

A missing or invalid token is HTTP 401 before any stream opens.

11.2 AG-UI​

Start a run. The request body is an AG-UI RunAgentInput:

{ "threadId": "t1", "runId": "r1", "protocolVersion": "1.0",
"messages": [{ "id": "m1", "role": "user", "content": "Invoice INV-1001 …" }],
"forwardedProps": { "document_ref": { "document_id": "<id from an upload>" } } }
  • With no document_ref, the last user message becomes the document.
  • forwardedProps keys become context values, except the engine's own (tenant_id, approval, and so on), which are refused.

Resume a run by addressing the open interrupt:

{ "threadId": "t1", "runId": "r2", "protocolVersion": "1.0",
"resume": [{ "interruptId": "t1:approval", "status": "resolved",
"payload": { "approved": true, "comment": "ok", "edits": { "invoice.po_number": "PO-7A" } } }] }

status: "cancelled" rejects. With resolved, payload.approved must be true or false.

The event stream. A resumed run, as received with curl -N:

data: {"type":"RUN_STARTED","threadId":"<thread>","runId":"r2","protocolVersion":"1.0"}
data: {"type":"STATE_SNAPSHOT","snapshot":{…}}
data: {"type":"TEXT_MESSAGE_START","messageId":"01a1c5a2-d494-…","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"01a1c5a2-d494-…","delta":"Decision recorded"}
data: {"type":"TEXT_MESSAGE_END","messageId":"01a1c5a2-d494-…"}
data: {"type":"STATE_SNAPSHOT","snapshot":{…}}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"…","delta":"accounting.post_bill done"}
data: {"type":"STATE_SNAPSHOT","snapshot":{…}}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"…","delta":"Posted to accounting"}
data: {"type":"RUN_FINISHED","threadId":"<thread>","runId":"r2","result":{"end":"done"},"outcome":{"type":"success"}}

(Start and end events for the second and third messages are omitted.)

SituationEvents
each stepSTATE_SNAPSHOT (whitelisted state), then one narration message
run pauses (1.0 client)MESSAGES_SNAPSHOT (the conversation), then RUN_FINISHED with outcome: { type: "interrupt", interrupts: [{ id, reason, message, responseSchema, expiresAt, metadata: { workflow, ui, roles, runId } }] } (runId is the request's, so every offer, including a re-offer, is distinguishable)
run pauses (pre-1.0 client)MESSAGES_SNAPSHOT, CUSTOM named on_interrupt with { id, message, metadata }, then RUN_FINISHED with no outcome
decision refused while opena Not accepted: … message, then the same interrupt again
run endsRUN_FINISHED with outcome: { type: "success" } and result.end = the final node
errorRUN_ERROR with message and code: not_found, forbidden, bad_request, conflict or internal

A client counts as 1.0 when protocolVersion has a major version of 1 or more.