Стриминг (SSE)

POST /v1/chat/completions с "stream": true стримит ответ агента по Server-Sent Events в формате OpenAI chat.completion.chunk. Стандартные OpenAI SDK читают его без изменений; поля запроса описаны на странице OpenAI-совместимый API.

bash
curl -N https://samreshuuu.ru/v1/chat/completions \ -H "Authorization: Bearer $SAMRESHUUU_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "samreshu", "stream": true, "messages": [{ "role": "user", "content": "Дай три коротких совета, как назвать карточку товара на маркетплейсе" }] }'

Чанки

Каждый фрейм это строка data: с одним чанком. Первый чанк несёт delta: {"role": "assistant", "content": ""}, дальше delta.content несёт следующий кусок текста; первый чанк с finish_reason завершает ответ, а data: [DONE] закрывает поток. model в каждом чанке это хэндл агента, который отвечает.

bash
data: {"id":"chatcmpl-5f1c2d3e4a6b7c8d9e0f1a2b","object":"chat.completion.chunk","created":1790000000,"model":"samreshu","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} data: {"id":"chatcmpl-5f1c2d3e4a6b7c8d9e0f1a2b","object":"chat.completion.chunk","created":1790000000,"model":"samreshu","choices":[{"index":0,"delta":{"content":"Ключевые пункты"},"finish_reason":null}]} data: {"id":"chatcmpl-5f1c2d3e4a6b7c8d9e0f1a2b","object":"chat.completion.chunk","created":1790000000,"model":"samreshu","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE]

Каждые 10 с, в том числе во время долгого вызова инструмента, приходит SSE-комментарий, начинающийся с : ping (за ним метка времени); парсер обязан пропускать строки, начинающиеся с :. Чанка с usage в потоке нет: счётчики токенов приходят только в ответе без стриминга.

Дельты это живой черновик

Агент иногда переписывает текст посреди хода, поэтому склеенные дельты могут отличаться от сохранённого ответа. Если нужен авторитетный текст, отправьте тот же запрос без stream.

События инструментов (по запросу)

С "tool_events": true поток несёт между чанками события samreshuuu.tool. Они приходят именованными SSE-событиями (event: samreshuuu.tool). Официальные SDK OpenAI не фильтруют события по имени и отдают такие кадры как чанки без choices, поэтому пропускайте их в цикле (if not chunk.choices: continue). В Node.js SDK читайте их только через for await по create({ stream: true }) или собственным SSE-парсером: хелперы .stream() и runTools ждут в каждом кадре чанк и ломаются на этих событиях. Собственный SSE-парсер может разбирать поток по имени события.

bash
event: samreshuuu.tool data: {"type":"tool_started","tool_id":"call_7Hq2mXc9LpR4tVb1NsK8eW3d","tool_name":"connector_execute","iteration":1,"label":"Вызов сервиса"} event: samreshuuu.tool data: {"type":"tool_completed","tool_id":"call_7Hq2mXc9LpR4tVb1NsK8eW3d","tool_name":"connector_execute","iteration":1,"success":true,"duration_ms":842,"label":"Вызов сервиса"}

tool_started несёт type, tool_id, tool_name, iteration и label (отображаемое имя инструмента); tool_completed добавляет success и duration_ms. tool_id связывает два события одного вызова. Вызов, на который ответ дан без запуска (повтор, отвеченный прежним результатом хода, вызов, отклонённый до запуска), присылает только tool_completed. Служебный инструмент завершения хода в этих событиях не появляется. Имена инструментов перечислены в разделе Агенты → Доступные инструменты.

Ошибки

Любая ошибка это один объект: {"type":"error","error":{"type","code","message","param"},"request_id"}. Отказ до старта хода это обычная HTTP-ошибка с таким телом (403 без chat:write, 404 для неизвестного model, 402 при исчерпанном недельном лимите, 429 при превышении частоты). После начала потока статус уже 200, поэтому сбой приходит последним чанком, который несёт объект error вместо choices; Python-клиент openai поднимает его как APIError. За ним идёт data: [DONE], закрывающий поток. См. Ошибки и лимиты.

bash
data: {"type":"error","error":{"type":"overloaded_error","code":"LLM_PROVIDER_UNAVAILABLE","message":"The model is temporarily unavailable. Please try again in a few minutes.","param":null},"request_id":"3f6c1b2a-8d4e-4f7a-9b0c-5e2d1a7c9f84"}

Обрывы и долгие ходы

Ход идёт внутри вашего запроса: закрытие потока его останавливает, и ход записывается как остановленный, а не как сбой. Курсора для продолжения оборванного потока нет; чтобы продолжить разговор, отправьте следующее сообщение с тем же session_id и model. EOF без data: [DONE] не означает законченный ответ.

Частые вопросы

Как получить ответ потоком?

Передайте stream: true в POST /v1/chat/completions. Ответ приходит фреймами OpenAI chat.completion.chunk по Server-Sent Events и заканчивается data: [DONE].

Как увидеть, какие инструменты вызывает агент?

Добавьте tool_events: true к потоковому запросу. Рядом с чанками придут именованные события samreshuuu.tool: одно на старте вызова и одно на его завершении.

Что будет, если соединение оборвётся?

Закрытие потока останавливает ход, и он записывается как остановленный, а не как сбой. Курсора для повторного чтения у /v1 нет: продолжайте разговор с тем же session_id и model.

Как отличить сбой от нормального окончания?

Сбой после начала потока приходит последним чанком, который несёт объект error вместо choices; Python-клиент openai поднимает его как APIError, затем data: [DONE] закрывает поток. Нормальное окончание несёт finish_reason stop, за ним data: [DONE].

Была ли страница полезна?