Hubris
API Reference

Streaming

Server-Sent Events формат для chat completions stream.

Streaming

При stream: true ответ от /v1/chat/completions приходит как Server-Sent Events: каждый chunk — отдельная строка data: <json> с разделителем \n\n. Поток завершается строкой data: [DONE].

Заголовки ответа

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no

Формат chunk-а

Каждый chunk — JSON-объект chat.completion.chunk:

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion.chunk",
  "created": 1714000000,
  "model": "anthropic/claude-haiku-4.5",
  "choices": [
    {
      "index": 0,
      "delta": { "role": "assistant", "content": "О" },
      "finish_reason": null
    }
  ]
}

В первом chunk-е delta обычно содержит role: "assistant". Следующие — только инкремент content. Последний chunk перед [DONE] имеет finish_reason: "stop" (или length, tool_calls, и т.д.) и поле usage с итоговыми токенами:

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion.chunk",
  "created": 1714000000,
  "model": "anthropic/claude-haiku-4.5",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 1,
    "total_tokens": 13
  }
}

После usage-chunk-а поток завершается:

data: [DONE]

Hubris автоматически добавляет stream_options: { include_usage: true } ко всем stream-запросам, поэтому usage приходит всегда.

Парсинг

Парсите построчно с буфером: один chunk может прийти разорванным на несколько TCP-сегментов. Псевдокод:

buffer = ""
for raw_bytes in response.iter_content():
    buffer += raw_bytes.decode("utf-8")
    while "\n\n" in buffer:
        line, buffer = buffer.split("\n\n", 1)
        if not line.startswith("data: "):
            continue
        payload = line[len("data: "):]
        if payload == "[DONE]":
            return
        chunk = json.loads(payload)
        # обработка delta

Не парсьте [DONE] как JSON — это литерал-маркер, не JSON.

Дисконнект

Если клиент закрыл соединение до окончания стрима, Hubris всё равно дочитывает ответ от провайдера и списывает деньги — это защищает от «бесплатных токенов» через abort. Если вы намеренно прерываете запрос (например, по timeout-у), ожидайте полное списание стоимости.

Что дальше