:stream to the message endpoint:
text/event-stream. For scripts and batch jobs, the non-streaming endpoint returns the same answer in one response.
Events
Each event has anid (its sequence number), an event type and a single-line JSON data payload:
Field-level detail is on Stream a message.
Rules your client can rely on
- Exactly one terminal event ends every stream:
answer.completed,answer.interruptedoranswer.error. - Append
answer.deltatext in order. Each delta is an increment, not the answer so far. - On
answer.replaced, discard what you rendered and show itstextinstead. It is sent when the final checks withdraw or rewrite streamed text, for example when an answer becomes an abstention. Later deltas append to it. - Replace, don’t append, citations.
answer.sourcesis sent each time the answer first cites another source, before the delta that contains its[n]marker, so markers can be linked as soon as they appear. When the answer has citations, one moreanswer.sourceswith the complete list arrives just beforeanswer.completed. The last one is authoritative; an empty list means the assistant abstained. - The
event:line is the type. It is not repeated insidedata. idincreases by one. A gap means an event was lost.- Ignore event types you don’t recognise. New non-terminal events may be added.
A 200 is not success
Authentication, validation and the one-question-at-a-time check all happen before the stream opens, so those failures arrive as ordinary HTTP errors. Once the stream has opened with200, a failure arrives as answer.error. Always read the terminal event before treating an answer as complete.
An abstention streams like any answer: its sentence arrives as answer.delta text, or as answer.replaced when it withdraws text that was already streamed, and answer.completed carries abstained: true. Render it as a normal reply.
answer.completed also carries abstention_reason — why the assistant declined, or null. Use it to tell “nothing in your sources covers this” apart from “something does, but not confidently enough”: those call for different actions. Treat it as an open string — match the values you know, fall back to a generic notice for one you do not. The values, and the shorter set the widget receives, are on Stream a message.
answer.interrupted means generation stopped part-way after producing some text, and that partial text is saved. Its reason says why: an error code such as provider_failure when generation failed after text had streamed, or incomplete_stream when generation ended without finishing. Show the partial answer with a notice that it is incomplete. A failure before any text arrives is answer.error instead.
Disconnects and retries
If the client disconnects, the answer is saved with the text produced so far, marked interrupted, and the conversation is freed. Streams cannot be resumed. If you retry with the sameidempotency_key after a turn has finished, the stored turn is replayed as a stream and the model is not asked again. Read an answer back at any time with List messages.
Proxies
Streaming requires every proxy between your client and MITHUNAI to pass events through unbuffered. Responses carryX-Accel-Buffering: no; make sure your proxies honour it and do not buffer text/event-stream. A buffering proxy makes the answer appear all at once at the end.