Skip to Content
API ReferenceSSE Events

SSE Events

AEGIS uses Server-Sent Events (SSE) to stream real-time updates from agent executions, workspace assessments, and conversation interactions.

Connection Setup

SSE endpoints return a stream of text/event-stream content. Connect using the standard EventSource API or any SSE client.

Browser clients authenticate by the aegis_token cookie (same-origin EventSource cannot set an Authorization header). The conversation stream emits named events, so listen per event name rather than using onmessage:

const eventSource = new EventSource( '/api/v1/conversations/{conversation_id}/stream?message=Hello' // same-origin: the browser sends the aegis_token cookie automatically ); for (const name of ['node_start', 'node_end', 'token', 'tool_result', 'done', 'error']) { eventSource.addEventListener(name, (event) => { const data = JSON.parse(event.data); console.log(data.event, data.node, data.data); if (name === 'done' || name === 'error') eventSource.close(); }); } eventSource.onerror = (error) => { console.error('SSE connection error:', error); };
# Using curl (Bearer header also accepted) curl -N -H "Authorization: Bearer $TOKEN" \ "http://localhost:8000/api/v1/conversations/{conversation_id}/stream?message=Hello"

SSE Endpoints

EndpointPurpose
GET /api/v1/conversations/{id}/streamStream conversation events (agent responses, tool calls)
GET /api/v1/workspaces/{checklist_id}/streamStream workspace assessment events

Resumable Conversation Streams (R39 Phase 1)

The conversation stream is rejoinable: the turn executes as a detached server-side task writing every event to a per-turn log, and the SSE endpoint is a reader of that log. A dropped connection never kills the turn.

  • Event ids. Every event carries an SSE id: (the log entry id). The browser’s EventSource tracks the last id automatically.
  • Resume. On reconnect the endpoint honors the Last-Event-ID header (or a last_event_id query parameter, for proxies that strip the header) and replays strictly after that event, then tails live.
  • Single-flight. One turn per conversation at a time. A request arriving while a turn is active attaches as a reader — its message parameter is ignored (this makes retries safe). A reconnect carrying Last-Event-ID after the turn finished replays the completed log; it never re-executes the message.
  • message is now optional. Required only to start a turn; a request with neither an active turn nor a message returns 400. A reconnect whose log has expired (default TTL 1 hour) receives a terminal error event with turn_lost: true — fall back to GET /conversations/{id}/messages.
  • Process restarts. With R39_CHECKPOINTER=on (Phase 3 Slice B), an in-flight turn RESUMES from its last checkpoint at startup — the resumed run appends to the same event log, so a reconnecting reader’s live view continues seamlessly. With the flag off (default), or when a thread has no checkpoint, readers get a fast terminal error with turn_lost: true instead of hanging.

Config: TURN_EVENT_LOG_TTL_S (3600), TURN_EVENT_LOG_MAXLEN (1000), TURN_ACTIVE_TTL_S (900), TURN_STREAM_RETRY_MS (3000), R39_CHECKPOINTER (off).

Event Format

Each conversation SSE frame is a named event whose data is a JSON object with event, node, and data fields (StreamEvent in orchestration schemas.py):

event: node_end data: {"event": "node_end", "node": "initial_llm_call", "data": {"status": "running", "tokens_used": 1892, "message": {…}}}

(Workspace events below use a flatter event_type payload — the two streams have different shapes.)

Conversation Events

Events emitted during agent conversation streaming:

EventDescriptionKey data Fields
node_start / node_endPipeline node progress (system_prompt, memory, initial_llm_call, tool_node, approval, output_format)status, tokens_used; for LLM nodes message (the assistant message incl. tool_calls); for tool_node skills_loaded
tokenStreaming text tokencontent (partial text)
tool_resultStructured result of a skill code-block tool or an artifact-bearing core tool (render_chart, R43) (emitted before the tool_node’s node_end; only successful envelopes) — the chat UI renders registered block results as charts/tables/cardstool_name (the block_key), tool_call_id, envelope ({status, message, result} — the chartable payload is envelope.result)
errorProcessing errormessage, code
doneTurn completeexecution_id (the R40a verdict-capture key — the frontend stamps it on the assistant message so the feedback affordance mounts only after completion), status, tokens_used, cost_usd, skills_injected, thinking_mode (the effective post-clamp mode, which may differ from the request), referenced_entities (entities resolved/created this turn: {entity_id, name, entity_type} — feeds the context panel), hitl_approval_id + hitl_checkpoint_type (the pause identity when status is awaiting_hitl — the client renders checkpoint-aware banner copy and routes the Review CTA from these; both null when the turn is not paused)

Example: Conversation Stream

event: node_end data: {"event": "node_end", "node": "system_prompt_node", "data": {"status": "running", "tokens_used": 0}} event: node_end data: {"event": "node_end", "node": "initial_llm_call", "data": {"status": "running", "tokens_used": 1892, "message": {"role": "assistant", "content": "", "tool_calls": [{"function": {"name": "flaring_portfolio_scan", "arguments": "{}"}}]}}} event: tool_result data: {"event": "tool_result", "node": "tool_node", "data": {"tool_name": "flaring_portfolio_scan", "tool_call_id": "toolu_…", "envelope": {"status": "success", "message": "Execution completed.", "result": {"authorizations": [], "total_count": 0, "truncated": false}}}} event: node_end data: {"event": "node_end", "node": "tool_node", "data": {"status": "running", "tokens_used": 1892}} event: node_end data: {"event": "node_end", "node": "initial_llm_call", "data": {"status": "running", "tokens_used": 4210, "message": {"role": "assistant", "content": "Across the portfolio…"}}} event: done data: {"event": "done", "node": null, "data": {"execution_id": "a1b2c3d4-…", "status": "completed", "tokens_used": 4210, "cost_usd": 0.031, "skills_injected": ["flaring_watch"], "thinking_mode": "adaptive", "referenced_entities": [], "hitl_approval_id": null, "hitl_checkpoint_type": null}}

Workspace Events

Events emitted during entity compliance workspace assessments:

Event TypeDescriptionKey Fields
checklist_item_updateChecklist item status changeditem_index, status, label
artifact_generatedDocument/artifact produceditem_index, artifact_type, artifact_id
data_table_updateData table populated/updateditem_index, rows, columns
form_field_updateForm field value setitem_index, field_name, value
validation_resultCompliance check completedrule, passed, message
spatial_updateMap/spatial data updatedcoordinates, features
agent_statusAgent processing statusstatus, phase
assessment_completeFull assessment finishedsummary, risk_level

Example: Workspace Assessment Stream

data: {"event_type": "agent_status", "status": "assessing", "phase": "data_collection"} data: {"event_type": "checklist_item_update", "item_index": 0, "status": "in_progress", "label": "Well Data Review"} data: {"event_type": "data_table_update", "item_index": 0, "rows": [...], "columns": ["API", "Operator", "Distance"]} data: {"event_type": "checklist_item_update", "item_index": 0, "status": "complete"} data: {"event_type": "checklist_item_update", "item_index": 1, "status": "in_progress", "label": "Spacing Analysis"} data: {"event_type": "validation_result", "rule": "Rule 37 Spacing", "passed": false, "message": "340ft < 467ft minimum"} data: {"event_type": "artifact_generated", "item_index": 1, "artifact_type": "spacing_report", "artifact_id": "art-123"} data: {"event_type": "checklist_item_update", "item_index": 1, "status": "complete"} data: {"event_type": "assessment_complete", "summary": "2 of 5 checks passed", "risk_level": "high"}

Reconnection

The browser’s built-in EventSource automatically reconnects on connection drops. If using a custom SSE client, implement reconnection with exponential backoff.

If the connection drops:

  1. Wait 1 second, then reconnect
  2. Double the wait on each subsequent failure (max 30 seconds)
  3. The server does not replay missed events — reconnection starts from the current state

Error Events

If an error occurs during streaming, the server emits an error event before closing:

data: {"event_type": "error", "message": "Budget exceeded: 150000 token limit reached", "code": "BUDGET_EXCEEDED"}

Common error codes:

CodeDescription
BUDGET_EXCEEDEDAgent token or cost budget exhausted
TOOL_FAILUREA tool call failed during execution
APPROVAL_TIMEOUTHITL approval request timed out
INTERNAL_ERRORUnexpected server-side error
Last updated on