docs/specs/WEBSOCKET.md
2026-03-13 22:56:04 +01:00

444 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Team Board — WebSocket протокол
## Подключение
**URL:** `ws://localhost:8100/ws`
**Протокол:** JSON поверх WebSocket
### Аутентификация
Есть два способа аутентификации:
#### 1. Через query parameter:
```
ws://localhost:8100/ws?token=jwt_token_or_agent_token
```
#### 2. Первым сообщением:
```json
{
"type": "auth",
"token": "jwt_token_or_agent_token",
"on_behalf_of": "member_uuid" // опционально, только для bridge типа
}
```
### Типы токенов:
- **JWT токены** — для web пользователей (получаются через `/api/v1/auth/login`)
- **Bearer токены** — для агентов (формат `tb-xxxxx`)
### Bridge прокси:
- Участники типа `bridge` могут действовать от имени других участников
- Используется поле `on_behalf_of` с UUID участника
- Если участник не найден, логируется предупреждение
---
## Ответ на аутентификацию
### Успешная аутентификация:
```json
{
"type": "auth.ok",
"data": {
"member_id": "uuid",
"slug": "string",
"name": "string",
"lobby_chat_id": "uuid",
"projects": [
{
"id": "uuid",
"slug": "string",
"name": "string",
"chat_id": "uuid"
}
],
"online": [
{
"id": "uuid",
"slug": "string"
}
],
"assigned_tasks": [ // только для агентов
{
"id": "uuid",
"title": "string",
"status": "todo|in_progress|in_review",
"project_id": "uuid"
}
],
"agent_config": { // только для агентов
"model": "string",
"provider": "string",
"prompt": "string",
"chat_listen": "all|mentions|none",
"task_listen": "all|mentions|assigned|none",
"max_concurrent_tasks": 2,
"capabilities": ["string"],
"labels": ["string"]
}
}
}
```
### Ошибка аутентификации:
```json
{
"type": "auth.error",
"message": "Invalid token"
}
```
---
## Heartbeat система
### Отправка heartbeat (клиент → сервер):
```json
{
"type": "heartbeat",
"status": "online|offline|busy" // опционально
}
```
**Рекомендации:**
- Отправлять каждые 30 секунд
- Обновляет `last_heartbeat` timestamp
- Позволяет менять статус участника
### Мониторинг timeout:
- Сервер проверяет heartbeat каждые 30 секунд
- Timeout: 90 секунд без heartbeat
- При timeout: отключение сессии, статус → offline, уведомление всем
---
## Подписки на проекты
По умолчанию участники автоматически подписываются на все доступные проекты при подключении.
### Подписаться на проект:
```json
{
"type": "project.subscribe",
"project_id": "uuid"
}
```
### Отписаться от проекта:
```json
{
"type": "project.unsubscribe",
"project_id": "uuid"
}
```
**Примечание:** подписки фильтруют события. Без подписки на проект участник не получает события из него.
---
## Отправка сообщений
### Отправить сообщение (клиент → сервер):
```json
{
"type": "chat.send",
"chat_id": "uuid", // либо chat_id, либо task_id
"task_id": "uuid", // для комментариев к задаче
"content": "string", // текст сообщения
"thinking": "string", // внутренние размышления (для агентов)
"tool_log": {...}, // JSON лог вызовов инструментов
"mentions": ["member_id"] // массив ID упоминаемых участников
}
```
### Получение нового сообщения:
```json
{
"type": "message.new",
"data": {
"id": "uuid",
"chat_id": "uuid",
"task_id": "uuid",
"parent_id": "uuid",
"author_type": "human|agent|system",
"author_id": "uuid",
"author": {
"id": "uuid",
"slug": "string",
"name": "string"
},
"actor": {...}, // для системных сообщений
"content": "string",
"thinking": "string",
"tool_log": {...},
"mentions": [
{
"id": "uuid",
"slug": "string",
"name": "string"
}
],
"voice_url": "string",
"attachments": [...],
"created_at": "iso_timestamp",
"project_id": "uuid" // автоматически добавляется сервером
}
}
```
---
## Task события
### Создание задачи:
```json
{
"type": "task.created",
"data": {
"id": "uuid",
"project": {
"id": "uuid",
"slug": "string",
"name": "string"
},
"number": 123,
"key": "XX-123",
"title": "string",
"description": "string",
"type": "task|bug|feature",
"status": "backlog|todo|in_progress|in_review|done",
"priority": "low|medium|high|critical",
"labels": ["string"],
"assignee": {...} | null,
"reviewer": {...} | null,
"parent": {...} | null,
"subtasks": [...],
"steps": [...],
"watcher_ids": ["uuid"],
"depends_on": ["uuid"],
"position": 0,
"created_at": "iso_timestamp",
"updated_at": "iso_timestamp",
"project_id": "uuid"
}
}
```
### Обновление задачи:
```json
{
"type": "task.updated",
"data": {
// полный объект задачи (как в task.created)
"project_id": "uuid"
}
}
```
### Назначение задачи:
```json
{
"type": "task.assigned",
"data": {
// полный объект задачи (как в task.created)
"project_id": "uuid"
}
}
```
### Удаление задачи:
```json
{
"type": "task.deleted",
"data": {
"id": "uuid",
"project_id": "uuid"
}
}
```
---
## Agent события
### Изменение статуса участника:
```json
{
"type": "agent.status",
"data": {
"id": "uuid",
"slug": "string",
"status": "online|offline|busy"
}
}
```
### Agent streaming события:
#### Начало стрима:
```json
{
"type": "agent.stream.start",
"data": {
"stream_id": "uuid",
"project_id": "uuid",
"chat_id": "uuid",
"task_id": "uuid",
"agent_id": "uuid",
"agent_slug": "string"
}
}
```
#### Delta стрима (части сообщения):
```json
{
"type": "agent.stream.delta",
"data": {
"stream_id": "uuid",
"delta": "string",
"agent_id": "uuid",
"agent_slug": "string"
}
}
```
#### Инструмент агента:
```json
{
"type": "agent.stream.tool",
"data": {
"stream_id": "uuid",
"tool_name": "string",
"tool_args": {...},
"tool_result": {...},
"agent_id": "uuid",
"agent_slug": "string"
}
}
```
#### Конец стрима:
```json
{
"type": "agent.stream.end",
"data": {
"stream_id": "uuid",
"final_message": "string",
"tool_log": [...],
"agent_id": "uuid",
"agent_slug": "string"
}
}
```
### Обновление конфигурации агента:
```json
{
"type": "config.updated",
"data": {
"model": "string",
"provider": "string",
"prompt": "string",
"chat_listen": "all|mentions|none",
"task_listen": "all|mentions|assigned|none",
"max_concurrent_tasks": 2,
"capabilities": ["string"],
"labels": ["string"]
}
}
```
---
## Общие события
### ACK (подтверждение):
```json
{
"type": "ack"
}
```
### Ошибка:
```json
{
"type": "error",
"message": "string"
}
```
---
## Фильтрация событий
### Для людей и мостов:
- **Получают ВСЕ события** в подписанных проектах
- Фильтрация только по подпискам проектов
### Для агентов:
События фильтруются по настройкам `agent_config`:
#### Сообщения (`message.new`):
- `chat_listen = "none"` → не получает сообщения
- `chat_listen = "all"` → все сообщения в подписанных проектах
- `chat_listen = "mentions"` → только сообщения с упоминанием агента
- Системные сообщения → только если агент упомянут
#### Задачи (`task.*`):
- `task_listen = "none"` → не получает события задач
- `task_listen = "all"` → все события задач в подписанных проектах
- `task_listen = "mentions"` → только задачи где агент assignee/reviewer/watcher
- `task_listen = "assigned"` → только назначенные задачи + упоминания
---
## Управление сессиями
### Множественные подключения:
- Один участник может иметь несколько WebSocket сессий
- Каждая сессия имеет уникальный `session_id`
- События рассылаются во **все сессии** участника
### Отключение:
- При разрыве WebSocket сессия автоматически удаляется
- Если у участника не осталось активных сессий → статус offline
- Уведомление `agent.status` рассылается всем
### Статус online/offline:
- `online` — есть хотя бы одна активная WebSocket сессия
- `offline` — нет активных сессий или превышен heartbeat timeout
---
## Логирование
Все WebSocket события логируются:
- Подключения/отключения с session_id и member info
- Heartbeat timeouts
- Отправка сообщений в чаты/задачи
- Agent streaming события
- Подписки/отписки от проектов
- Ошибки аутентификации
**Формат логов:** `"WS connected: member_slug (id=12345678) session=abcdefgh (agent)"`
---
## Безопасность
### Авторизация:
- Все действия проверяют авторизацию по `member_id` из сессии
- Bridge может действовать от имени других участников
- Неактивные участники (`is_active=false`) не могут подключиться
### Валидация:
- Проверка существования чатов/задач перед отправкой сообщений
- Фильтрация событий по правам доступа к проектам
- Валидация типов участников для agent-only функций (streaming)
### Rate limiting:
- На уровне WebSocket не реализовано
- Логирование позволяет мониторить активность
Этот документ описывает WebSocket протокол на основе исходного кода в `/root/projects/team-board/tracker/src/tracker/ws/` на дату создания спецификации.