Streaming

Stream completions over SSE. Standard OpenAI-style chunks, the dual reasoning/reasoning_content delta keys, and how to detect stalls and truncation.

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: true comes back as a single JSON body instead of SSE. Check the response Content-Type: if it is not text/event-stream, parse the body as a regular completion rather than failing.
  • SSE data: fields can span multiple lines. Accumulate all data: lines of an event before JSON-parsing, per the SSE spec. One-line-one-JSON parsers will break.
  • A clean end is [DONE] or a finish_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.