Chat Stream
Answer as SSE — including thinking and tools.
/api/v1/chat/streamSame request body as /chat, but the response is a text/event-stream. Only this way do thinking, tool calls, and the answer arrive live token by token — always use this endpoint for the chat UI.
Frame format
Each frame is a line data: {json}, separated by blank lines. Each JSON carries a type. The stream always ends with data: [DONE].
Frame types
reasoning{ delta }Model is thinking (reasoning models only, comes first). Append delta, show it greyed out / collapsed.
content{ delta }A chunk of the actual answer. Append delta and render as Markdown.
tool_call{ tool, call_id, arguments }A tool is being called. arguments is an object for a readable line.
tool_result{ tool, call_id, ok, preview, length }Result. ok=false = failure (red), preview = message. Link to the tool_call by call_id, not by order.
errorevent: error · { error: { code, message } }Abort after the stream started — as its own event: error event.
Example stream
data: {"type":"reasoning","delta":"I should search first …"}
data: {"type":"tool_call","tool":"web_search","call_id":"call_01","arguments":{"query":"current SSE specification"}}
data: {"type":"tool_result","tool":"web_search","call_id":"call_01","ok":true,"preview":"1. WHATWG HTML Living Standard … 2. MDN …","length":1840}
data: {"type":"content","delta":"Server-Sent Events "}
data: {"type":"content","delta":"are a one-way channel …"}
data: [DONE]Errors mid-stream
The HTTP status is already 200, so the error arrives as event: error with the same error object as everywhere else.
event: error
data: {"type":"error","error":{"code":"provider_timeout","message":"The upstream provider did not respond in time."}}
data: [DONE]