Справочник описывает три WebSocket приложения: чат, статусы фоновых задач и уведомления. События обновления дашборда используют отдельную аутентификацию и формат; они описаны в WebSocket API дашборда.
Граница аутентификации
В production клиент передаёт заголовок HTTP handshake:
Authorization: Bearer <access-token>
Токен в URL запрещён. Если в query string есть token, сервер закрывает соединение кодом 1008 и причиной “Query token transport is not allowed”.
Для доступа в контексте проекта добавьте его постоянный идентификатор:
X-Project-Id: <project-uuid>
Сервер проверяет текущее состояние пользователя, отзыв токена, доступ к проекту, владение задачей там, где оно требуется, а также квоты соединений и сообщений. Клиент с loopback-адреса может работать без токена только при явно включённом локальном режиме и локальных адресах клиента и запрошенного хоста.
Стандартный браузерный конструктор WebSocket не позволяет установить Authorization header. В браузерном приложении используйте аутентифицированный same-origin gateway либо отдельный контракт WebSocket дашборда. Не переносите bearer-токен в query string.
Маршруты
| Маршрут | Сообщения клиента | Назначение |
|---|---|---|
| /api/v1/ws/chat | chat.query, ping | Поток выбора сценария, фрагментов, полного ответа, завершения и ошибок чата |
| /api/v1/ws/jobs/{job_id} | ping | Текущее и последующие состояния принадлежащей пользователю фоновой задачи |
| /api/v1/ws/notifications | ping | Уведомления аутентифицированного пользователя |
Если задача не существует, job-маршрут закрывается кодом 4004. Существующая задача за пределами области пользователя отклоняется кодом политики 1008.
Формат сообщения
Каждое сообщение приложения — JSON следующей формы:
{
"type": "chat.query",
"payload": {},
"timestamp": "2026-08-24T00:00:00Z",
"request_id": "optional-correlation-id"
}
Модель требует type и payload. Сервер подставляет timestamp, если он не передан. request_id необязателен; сохраняйте его для сопоставления сообщений одного потокового ответа.
Актуальные типы сообщений
| Тип | Обычное направление | Назначение |
|---|---|---|
| chat.query | клиент → сервер | Начать запрос чата |
| chat.scenario | сервер → клиент | Сообщить выбранный сценарий |
| chat.chunk | сервер → клиент | Передать часть ответа |
| chat.response | сервер → клиент | Передать собранный ответ |
| chat.done | сервер → клиент | Завершить запрос |
| chat.error | сервер → клиент | Сообщить ошибку чата |
| job.started | сервер → клиент | Передать начальное состояние задачи |
| job.progress | сервер → клиент | Сообщить прогресс задачи |
| job.completed | сервер → клиент | Сообщить успешное завершение |
| job.failed | сервер → клиент | Сообщить ошибку или отмену |
| notification | сервер → клиент | Передать уведомление |
| error | сервер → клиент | Сообщить ошибку формата, политики или обработки |
| ping | клиент → сервер | Запросить прикладной keep-alive |
| pong | сервер → клиент | Ответить на ping |
| cpg.update.complete | сервер → клиент | Сообщить об обновлении CPG |
| connected | сервер → клиент | Подтвердить соединение и вернуть идентификаторы |
| disconnected | сервер → клиент | Сообщить об управляемом разрыве |
| authenticated | сервер → клиент | Подтвердить поддерживаемый переход аутентификации |
| auth_required | сервер → клиент | Запросить поддерживаемый переход аутентификации |
Не каждый тип создаётся на каждом маршруте. Клиент должен игнорировать нерелевантные для текущего процесса известные сообщения и не считать неизвестное сообщение подтверждением успеха.
Запрос чата
Отправляйте chat.query только в маршрут чата:
{
"type": "chat.query",
"payload": {
"query": "Покажи вызывающие символы",
"session_id": "optional-session",
"scenario_id": "optional-scenario",
"language": "ru"
},
"request_id": "req-123"
}
Нормальный поток может содержать chat.scenario, несколько chat.chunk, затем chat.response и chat.done. Сообщение error отменяет успешную интерпретацию запроса, даже если соединение осталось открытым.
Статус задачи
Подключайтесь к точному маршруту задачи, принадлежащей аутентифицированному пользователю. Сервер передаёт job.started с текущим состоянием, а для завершённой задачи — job.completed или job.failed. HTTP/REST-ответ остаётся постоянным источником; WebSocket — прерываемый канал уведомлений.
Уведомления
Маршрут уведомлений предназначен преимущественно для получения данных. Клиент отправляет только ping. Payload уведомления может включать title, message, level и action_url. Перед переходом проверяйте action_url по навигационной политике приложения.
Пример handshake
Сервисный клиент должен уметь передавать пользовательские HTTP-заголовки. Пример на Node.js использует пакет ws:
import WebSocket from "ws";
const socket = new WebSocket(
"wss://codegraph.example/api/v1/ws/notifications",
{
headers: {
Authorization: "Bearer " + process.env.CODEGRAPH_ACCESS_TOKEN,
"X-Project-Id": process.env.CODEGRAPH_PROJECT_ID
}
}
);
socket.on("message", (raw) => {
const message = JSON.parse(raw.toString());
if (message.type === "notification") {
console.log(message.payload);
}
});
socket.on("open", () => {
socket.send(JSON.stringify({ type: "ping", payload: {} }));
});
Не записывайте токен и полный Authorization header в логи.
Коды закрытия и восстановление
| Код | Значение | Действие |
|---|---|---|
| 1008 | Нарушение политики query-токена, авторизации, владения, области проекта или rate limit | Исправить условие; не повторять запрос в тесном цикле |
| 4001 | Токен отсутствует, недействителен, истёк или отозван | Получить новый access token и подключиться заново |
| 4004 | Задача не найдена | Проверить идентификатор через REST API |
Для временных разрывов используйте ограниченный exponential backoff с jitter. После 4001 обновите токен. Не повторяйте 1008 автоматически, пока причина отказа не устранена.
Исходные контракты
- src/api/websocket/routes.py — маршруты, bearer-аутентификация, проверки области и закрытие
- src/api/websocket/models.py — envelope, payload-модели и enum сообщений
- src/api/websocket/authorization.py — решения по пользователю, проекту, токену и задаче
- src/api/websocket/rate_limiter.py — квоты соединений и сообщений
WebSocket-маршруты не входят в набор REST-операций OpenAPI.