Set "stream": true on POST /v1/chat/completions to receive the response
as server-sent events. The chunks are standard OpenAI
chat.completion.chunk objects, with a few network realities worth handling
deliberately.
Basic streaming#
curl https://api.ambient.xyz/v1/chat/completions \
-H "Authorization: Bearer $AMBIENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"model": "ambient/large",
"messages": [
{"role": "user", "content": "Write a short poem about verification."}
],
"max_tokens": 512,
"stream": true,
"stream_options": {"include_usage": true}
}'Give max_tokens headroom. It caps reasoning and answer combined, and
reasoning models can spend a small budget entirely on thinking deltas.
Dual reasoning delta keys#
Different models on the network emit their thinking trace under different
delta keys: some stream it as reasoning_content (OpenAI-style), others as
reasoning. Read both keys. A client that only watches one of them will
silently drop the entire reasoning channel for models that use the other.
With a reasoning model, that dropped channel can be most of the tokens you
paid for.
Realities to handle#
- The endpoint may answer non-streamed anyway. Occasionally a request
with
stream: truecomes back as a single JSON body instead of SSE. Check the responseContent-Type: if it is nottext/event-stream, parse the body as a regular completion rather than failing. - SSE
data:fields can span multiple lines. Accumulate alldata:lines of an event before JSON-parsing, per the SSE spec. One-line-one-JSON parsers will break. - A clean end is
[DONE]or afinish_reason. A stream that hits EOF without either is a truncation. Treat the partial output as salvageable data rather than a failure, and treat a dropped connection mid-stream the same way. - Stalls and keep-alives. A wedged worker can hold the socket open with empty deltas or keep-alives while producing no content. Run a no-progress timer (time since the last delta that actually carried text) alongside an overall deadline, and abandon the stream when it trips. Don't rely on the connection closing on its own.