#SSE v2 protocol
Clients send X-iGraph-Stream-Version: 2 on chat, feedback, and resume requests; no user identity header is required. The browser uses a fetch stream reader because native EventSource cannot send these POST requests and custom protocol headers. The server returns text/event-stream.
X-iGraph-Stream-Version: 2
Accept-Language: zh-CN
Content-Type: application/json| Chat field | Type | Description |
|---|---|---|
| message | string | Required user message. |
| start_request_id | UUID | null | Generate a UUID for a new request; retain it when retrying that same request. |
| attachments | array | null | Attachment references contain file_token and optional filename. |
| output_format | chat | report | json | Defaults to chat. |
Backend uses native background streaming runs. The frontend sends stream/background as compatibility fields; the core ChatReq contract uses the fields above plus model fields such as reasoning_mode and planning_mode.
Each v2 SSE data frame contains protocol_version, session_id, run_id, event_index, and events. Multiple UI events derived from one original event are grouped in the same events array; apply the whole array before advancing the cursor. Observation-state events with event_index=null do not advance the original-event cursor. Heartbeats are SSE comments, not business messages. An incomplete frame without its terminating blank line must not be applied at EOF.
data: {"protocol_version":2,"session_id":"SESSION_ID","run_id":"RUN_ID","event_index":12,"events":[{"type":"tool_progress","tool":"train","call_id":"JOB_ID","progress":{"epoch":2,"epochs":10}}]}
Chat requests carry the UI language at send time through Accept-Language, recorded as response_language for that turn. Switching Chinese or English affects the next submitted response; it does not rewrite existing messages.
#Resume after a disconnect
- Same-page disconnect: keep existing messages and resume from the last fully applied event_index. Commit messages, tools, plans, and the cursor in one state transaction.
- After a refresh or loss of message state: rebuild the current run into temporary state from last_event_index=-1, publish after catching up, and retain other historical messages.
- On HTTP 409 REPLAY_UNAVAILABLE or stream_recovery_required: preserve content and poll snapshot, replacing phase messages atomically only once snapshot_complete=true.
- Snapshots currently return resume_cursor=null. Do not combine snapshot messages with raw deltas after an old cursor. A run restored from a paused-phase snapshot stays in snapshot mode.
curl -N -X POST \
"http://localhost:21108/api/sessions/SESSION_ID/runs/RUN_ID/resume?last_event_index=12" \
-H "X-iGraph-Stream-Version: 2"Original-event buffers depend on the runtime process. After a restart or buffer eviction, saved messages and complete snapshots can restore visible results; this does not restart business computation from a checkpoint. While a snapshot remains incomplete, retain current content and show recovery state instead of treating partial results as final.
#Cancellation and confirmation
/api/sessions/{session_id}/runs/cancelCall GET /api/capabilities first. The current .env.example enables IGRAPH_RUN_CANCEL_ENABLED; an unset variable falls back to false, and Backend also checks runtime and graph-service capabilities. run_cancel_v1 enables stopping a run, job_cancel_v1 enables stopping a job, and edit_latest_turn_v1 controls latest-turn editing. Cancellation specifies either target.run_id or target.start_request_id and a cancel_request_id, all valid UUIDs. Keep the same cancel_request_id when retrying one cancellation.
{
"target": {
"run_id": "4d227ea8-c8ca-4f0d-b5e4-81a44de7bd4c"
},
"cancel_request_id": "f186c422-5eed-4d0c-a4b9-e7d459124fd0"
}After cancelling, query GET /api/sessions/{sid}/runs/control?run_id={rid}. execution_stopped reports stopped execution; terminal_persisted reports a saved terminal state. Resume editing only when both hold and the server permits sending. AbortController disconnects the observer; it does not cancel server execution.
HTTP 200 from cancellation indicates execution_stopped is true; otherwise the endpoint returns 202. Still check terminal_persisted and can_send before allowing the client to continue.
To cancel a job, POST to /api/sessions/{sid}/jobs/{jid}/cancel with cancel_request_id, then read that job’s /control endpoint. Cancelling a run and cancelling an individual job target different scopes.
#Human approval
/api/sessions/{session_id}/feedback/streamThe current UI offers approve and reject. The API decision also supports modify with patched_args. Requests contain run_id, request_id, and decision_id, with optional tool_call_id, tool_name, and comment. Take identities and tool metadata from the current paused request rather than an old card. A normal approve uses persisted arguments; only modify applies replacements.
Feedback continues the original run_id instead of creating a new chat request. The frontend blocks new messages while approval is pending or being submitted and resumes observation after acceptance. Stale, mismatched, or already handled paused requests may conflict; if a response is lost, read authoritative state before resubmitting a graph mutation. Tool execution approval and candidate skill approval use different endpoints.