Skip to content

Streaming events

With "stream": true, chat completions return Server-Sent Events. Each event is a data: line with a JSON object. The stream ends with data: [DONE].

The stream mixes standard chat.completion.chunk objects with additional events. Additional events have a type field.

EventMeaningWhat your client should do
chat.completion.chunkPart of the answer text or of an external tool callAppend it to the answer
statusProgress of the requestShow it as progress. Ignore events with hidden: true.
citationA source used in the answerShow it as a reference
notificationMessage for the user (info, success, warning, error)Show it, for example as a toast
replaceReplaces the text already shownReplace the displayed answer with data.content
confirmationA tool call needs approval from the userAsk the user and send the answer, see below

Ignore event types your client does not know. New event types may be added.

data: {"type":"status","data":{"description":"Processing your request...","done":false,"hidden":true}}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"Please check"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" the camera mount bolts first."},"finish_reason":null}]}
data: {"type":"citation","data":{"document":["The alignment drifts after startup when the mount bolts loosen."],"metadata":[{"source":"Inspection Camera Maintenance Manual","score":0.91}],"source":{"name":"Inspection Camera Maintenance Manual","url":"https://docs.example.com/camera-maintenance"}}}
data: {"type":"status","data":{"description":"Done in 1.4s","done":true,"hidden":false}}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
{ "type": "status", "data": { "description": "Searching maintenance records...", "done": false, "hidden": false } }
{
"type": "citation",
"data": {
"document": ["The alignment drifts after startup when the mount bolts loosen."],
"metadata": [{ "source": "Inspection Camera Maintenance Manual", "score": 0.91 }],
"source": { "name": "Inspection Camera Maintenance Manual", "url": "https://docs.example.com/camera-maintenance" }
}
}
{ "type": "notification", "data": { "type": "error", "content": "You have exceeded the rate limit. Please try again later." } }

Errors that occur during streaming are delivered as notifications of type error, followed by [DONE].

{ "type": "replace", "data": { "content": "I cannot provide that response." } }

Sent mainly by guardrails. Replace all answer text shown for the current response with data.content, and store the replacement instead of the original text.

If an agent wants to run a tool that requires approval, the stream pauses and sends a confirmation event:

{
"type": "confirmation",
"data": {
"event_id": "evt_123",
"title": "Confirm: create_service_ticket",
"message": "Category: hardware\nPriority: high\nShort Description: Inspection camera misalignment",
"function_name": "create_service_ticket",
"arguments": { "category": "hardware", "priority": "high", "short_description": "Inspection camera misalignment" }
}
}

Show title and message to the user, then send the user’s decision while keeping the stream open:

POST ${RUNTIME_BASE_URL}/v1/events/evt_123/response
Authorization: Bearer ${RUNTIME_TOKEN}
X-Tenant-ID: ${TENANT_ID}
Content-Type: application/json
{ "confirmed": true }

The response is {"status": "ok"}. The stream then continues. If the user rejects, or if no answer arrives within 5 minutes, the tool does not run and the agent is told so.