При stream: true сервер возвращает Server-Sent Events. Каждый frame — часть ответа, а не самостоятельный завершённый результат.
Chat Completions#
Собирайте текст из choices[].delta.content. Tool-call arguments также приходят частями и должны быть объединены до JSON parsing.
Usage может прийти в отдельном финальном chunk без обычных choices. Код вида chunk.choices[0] без проверки может упасть именно на корректном usage-кадре.
Messages#
Обрабатывайте именованные события начала сообщения, начала блока, delta блока, завершения блока и завершения сообщения. Тип delta определяет, содержит ли он текст, thinking или JSON аргументов.
Responses#
Ветвитесь по event.type. Для текста, function arguments, завершения и ошибки используются разные события.
Надёжный цикл#
Проверяйте HTTP-статус до чтения SSE.
Читайте поток построчно и разделяйте события.
Игнорируйте heartbeat и пустые строки.
Обрабатывайте error event как завершение с ошибкой.
Сохраняйте финальный статус отдельно от накопленного текста.
Считайте ответ успешным только после корректного события завершения.
Не выполняйте tool call до получения полного JSON.
Показывать частичный текст пользователю можно. Использовать его как завершённый машинный результат без финального статуса нельзя.