"stream": true returns the reply as server-sent events
in the OpenAI chat.completion.chunk format.
Stream a reply
Stream every request that can take longer than 100 s: a non-streamed request without a response after about 100 s
fails with 524.
curl
curl -N https://api.albastov.com/v1/chat/completions \
-H "Authorization: Bearer $ALBASTOV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8-27b",
"stream": true,
"max_tokens": 80,
"messages": [{"role": "user", "content": "Explain prefix caching in two sentences."}],
"chat_template_kwargs": {"enable_thinking": false}
}'Python
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.albastov.com/v1", api_key=os.environ["ALBASTOV_API_KEY"])
stream = client.chat.completions.create(
model="qwen3.8-27b",
messages=[{"role": "user", "content": "Explain prefix caching in two sentences."}],
stream=True,
stream_options={"include_usage": True},
max_tokens=80,
extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\n", chunk.usage)JavaScript
const res = await fetch("https://api.albastov.com/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ALBASTOV_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "qwen3.8-27b",
stream: true,
stream_options: { include_usage: true },
max_tokens: 80,
messages: [{ role: "user", content: "Explain prefix caching in two sentences." }],
chat_template_kwargs: { enable_thinking: false },
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const decoder = new TextDecoder();
let buffer = "";
for await (const bytes of res.body) {
buffer += decoder.decode(bytes, { stream: true });
let end;
while ((end = buffer.indexOf("\n\n")) >= 0) {
const event = buffer.slice(0, end);
buffer = buffer.slice(end + 2);
for (const line of event.split("\n")) {
if (!line.startsWith("data:")) continue; // ": loading ..." comments
const data = line.slice(5).trim();
if (data === "[DONE]") continue;
const chunk = JSON.parse(data);
if (chunk.error) throw new Error(`${chunk.error.type}: ${chunk.error.message}`);
const text = chunk.choices?.[0]?.delta?.content;
if (text) process.stdout.write(text);
if (chunk.usage) console.log("\n", chunk.usage);
}
}
}Call the API from a server. A key in browser code is visible to every visitor.
Read the stream
Each event is one data: line and a blank line. Answer text arrives in choices[0].delta.content, reasoning in
choices[0].delta.reasoning, tool calls in choices[0].delta.tool_calls. The last choice chunk carries
finish_reason; data: [DONE] ends the stream. Lines that start with : are comments: skip them.
data: {"id":"chatcmpl-a1fb7d45","object":"chat.completion.chunk","created":1793305229,"model":"qwen3.8-27b","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-a1fb7d45","object":"chat.completion.chunk","created":1793305229,"model":"qwen3.8-27b","choices":[{"index":0,"delta":{"content":"One"},"finish_reason":null}]}
data: {"id":"chatcmpl-a1fb7d45","object":"chat.completion.chunk","created":1793305229,"model":"qwen3.8-27b","choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-a1fb7d45","object":"chat.completion.chunk","created":1793305229,"model":"qwen3.8-27b","choices":[],"usage":{"prompt_tokens":22,"completion_tokens":11,"total_tokens":33}}
data: [DONE]Token usage
"stream_options": {"include_usage": true} adds a final chunk with usage and an empty choices list, before
data: [DONE]. Without include_usage, the stream has no usage chunk.
Model loading
A streamed request for a model that is not loaded waits for the load, up to 1800 s:
- After 10 s without a reply, the response starts:
200,text/event-stream, and the comment: loading <model>, repeated every 15 s. - After the load, the model's events follow on the same connection.
- If the load fails, the stream sends one
data: {"error": {...}}event, thendata: [DONE].
With X-LLM-Wait: 0, a model that is not loaded returns 503 model_loading or 503 queued before the stream starts.
Load times and the queue: Language models.
Stream failures
A failure before the first event is an HTTP error with a JSON body. A failure after the stream has started arrives as
an event; check every data: event for an error key.
| Event | Next |
|---|---|
data: {"error": {"code": "model_loading", ...}} | data: [DONE] |
data: {"error": {"code": "gpu-busy", ...}} | data: [DONE] |
data: {"error": {"type": "engine_restarted", "code": 502, ...}} | The connection closes |
In an engine_restarted event, code is the number 502: read type. A model restarted after a stalled reply
answers the next request after a reload.
Reference
- Chat completions reference: chunk fields, headers and error codes.