294 lines
8.9 KiB
Markdown
294 lines
8.9 KiB
Markdown
# Agent Protocol v1.0 — Source of Truth
|
||
|
||
**Дата**: 2026-02-23
|
||
**Статус**: Действующий. Все агенты и Tracker ДОЛЖНЫ соответствовать этому документу.
|
||
|
||
---
|
||
|
||
## 1. Подключение
|
||
|
||
### URLs
|
||
|
||
**Напрямую к Tracker** (для локальной разработки):
|
||
- REST: `http://localhost:8100`
|
||
- WS: `ws://localhost:8100/ws`
|
||
|
||
**Через nginx** (для удалённых агентов):
|
||
- REST: `https://dev.team.uix.su/agent-api` → проксирует к Tracker
|
||
- WS: `wss://dev.team.uix.su/agent-ws` → проксирует к `ws://localhost:8100/ws`
|
||
|
||
### Авторизация
|
||
|
||
Токен агента (из UI Settings → Агенты или `POST /api/v1/members`).
|
||
|
||
- WS: передаётся в первом сообщении `auth`
|
||
- REST: заголовок `Authorization: Bearer <token>` (TODO: проверка не реализована)
|
||
|
||
---
|
||
|
||
## 2. WebSocket Protocol
|
||
|
||
### 2.1 Формат сообщений
|
||
|
||
Все сообщения — JSON. Поле определяющее тип: **`type`**.
|
||
|
||
```json
|
||
{"type": "event_name", ...payload}
|
||
```
|
||
|
||
### 2.2 Auth (Agent → Tracker)
|
||
|
||
Первое сообщение после подключения:
|
||
|
||
```json
|
||
{"type": "auth", "token": "tb-xxxxx"}
|
||
```
|
||
|
||
**Ответ — успех:**
|
||
```json
|
||
{
|
||
"type": "auth.ok",
|
||
"data": {
|
||
"slug": "coder",
|
||
"lobby_chat_id": "uuid",
|
||
"projects": [
|
||
{"id": "uuid", "slug": "team-board", "name": "Team Board"}
|
||
],
|
||
"online": ["admin", "other-agent"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**Ответ — ошибка:**
|
||
```json
|
||
{"type": "auth.error", "message": "Invalid token"}
|
||
```
|
||
Соединение закрывается.
|
||
|
||
### 2.3 Heartbeat (Agent → Tracker)
|
||
|
||
Каждые 30 секунд:
|
||
|
||
```json
|
||
{"type": "heartbeat", "status": "online"}
|
||
```
|
||
|
||
Допустимые status: `online`, `busy`, `idle`.
|
||
Timeout: 90 секунд без heartbeat → status=offline, уведомление `agent.status`.
|
||
|
||
Tracker **НЕ отвечает** на heartbeat (нет ack).
|
||
|
||
### 2.4 Project Subscribe (Agent → Tracker)
|
||
|
||
Подписка на события проекта (сообщения, задачи):
|
||
|
||
```json
|
||
{"type": "project.subscribe", "project_id": "uuid"}
|
||
```
|
||
|
||
Отписка:
|
||
```json
|
||
{"type": "project.unsubscribe", "project_id": "uuid"}
|
||
```
|
||
|
||
**Без подписки агент НЕ получает `message.new` и task-события проекта.**
|
||
Lobby-сообщения приходят всем без подписки.
|
||
|
||
Tracker **НЕ отвечает** на subscribe (нет ack).
|
||
|
||
### 2.5 Chat Send (Agent → Tracker)
|
||
|
||
Сообщение в чат:
|
||
```json
|
||
{"type": "chat.send", "chat_id": "uuid", "content": "text", "mentions": []}
|
||
```
|
||
|
||
Комментарий к задаче:
|
||
```json
|
||
{"type": "chat.send", "task_id": "uuid", "content": "text", "mentions": []}
|
||
```
|
||
|
||
### 2.6 Ack (Agent → Tracker)
|
||
|
||
```json
|
||
{"type": "ack"}
|
||
```
|
||
Принимается, ничего не делает. Опционально.
|
||
|
||
---
|
||
|
||
## 3. Входящие события (Tracker → Agent)
|
||
|
||
### 3.1 message.new
|
||
|
||
```json
|
||
{
|
||
"type": "message.new",
|
||
"data": {
|
||
"id": "uuid",
|
||
"chat_id": "uuid | null",
|
||
"task_id": "uuid | null",
|
||
"author_type": "human | agent | system",
|
||
"author_slug": "admin",
|
||
"content": "Текст",
|
||
"mentions": ["coder"],
|
||
"created_at": "ISO-8601"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Фильтрация** (по AgentConfig.chat_listen):
|
||
- `all` — все сообщения в подписанных проектах
|
||
- `mentions` — только если slug агента в `mentions`
|
||
- `none` — не получает
|
||
|
||
### 3.2 agent.status
|
||
|
||
```json
|
||
{
|
||
"type": "agent.status",
|
||
"data": {"slug": "other-agent", "status": "online | offline"}
|
||
}
|
||
```
|
||
|
||
### 3.3 task.assigned / task.created / task.updated (TODO)
|
||
|
||
Пока НЕ реализовано. Будет:
|
||
```json
|
||
{
|
||
"type": "task.assigned",
|
||
"data": { ...TaskOut }
|
||
}
|
||
```
|
||
|
||
**Фильтрация** (по AgentConfig.task_listen):
|
||
- `all` — все task-события в подписанных проектах
|
||
- `assigned` — только если агент = assignee, reviewer или watcher
|
||
- `none` — не получает
|
||
|
||
---
|
||
|
||
## 4. REST API
|
||
|
||
Base: `http://localhost:8100/api/v1` (прямой) или `https://dev.team.uix.su/agent-api/api/v1` (через nginx)
|
||
|
||
### 4.1 Projects
|
||
|
||
| Method | Path | Description |
|
||
|--------|------|-------------|
|
||
| GET | `/api/v1/projects` | Список проектов |
|
||
| GET | `/api/v1/projects/{slug}` | Проект по slug |
|
||
|
||
### 4.2 Tasks
|
||
|
||
| Method | Path | Description |
|
||
|--------|------|-------------|
|
||
| GET | `/api/v1/tasks?project_id=X` | Список (фильтры: project_id, status, assignee) |
|
||
| GET | `/api/v1/tasks/{id}` | Задача по ID |
|
||
| POST | `/api/v1/tasks?project_slug=X` | Создать |
|
||
| PATCH | `/api/v1/tasks/{id}` | Обновить |
|
||
| DELETE | `/api/v1/tasks/{id}` | Удалить |
|
||
| POST | `/api/v1/tasks/{id}/take?slug=X` | Взять (атомарно, 409 если занята) |
|
||
| POST | `/api/v1/tasks/{id}/reject` | Отклонить `{"slug":"x","reason":"..."}` |
|
||
| POST | `/api/v1/tasks/{id}/assign` | Назначить `{"assignee_slug":"x"}` |
|
||
| POST | `/api/v1/tasks/{id}/watch?slug=X` | Подписаться |
|
||
| DELETE | `/api/v1/tasks/{id}/watch?slug=X` | Отписаться |
|
||
|
||
**Task statuses**: `backlog` | `todo` | `in_progress` | `in_review` | `done`
|
||
**Task types**: `task` | `bug` | `epic` | `story`
|
||
**Task priorities**: `low` | `medium` | `high` | `critical`
|
||
|
||
### 4.3 Steps
|
||
|
||
| Method | Path | Description |
|
||
|--------|------|-------------|
|
||
| GET | `/api/v1/tasks/{id}/steps` | Список |
|
||
| POST | `/api/v1/tasks/{id}/steps` | Создать `{"title":"..."}` |
|
||
| PATCH | `/api/v1/tasks/{tid}/steps/{sid}` | Обновить `{"done":true}` |
|
||
| DELETE | `/api/v1/tasks/{tid}/steps/{sid}` | Удалить |
|
||
|
||
### 4.4 Messages
|
||
|
||
| Method | Path | Description |
|
||
|--------|------|-------------|
|
||
| GET | `/api/v1/messages?chat_id=X&limit=50` | Сообщения чата |
|
||
| GET | `/api/v1/messages?task_id=X` | Комментарии задачи |
|
||
| POST | `/api/v1/messages` | Отправить |
|
||
| GET | `/api/v1/messages/{id}/replies` | Тред |
|
||
|
||
**Send message:**
|
||
```json
|
||
{
|
||
"chat_id": "uuid (или null)",
|
||
"task_id": "uuid (или null)",
|
||
"content": "text",
|
||
"author_type": "agent",
|
||
"author_slug": "coder",
|
||
"mentions": []
|
||
}
|
||
```
|
||
|
||
⚠️ Поля `author_type` и `author_slug` обязательны (default: `human`/`admin`). Агент ДОЛЖЕН указывать свой slug и type=agent.
|
||
|
||
### 4.5 Members
|
||
|
||
| Method | Path | Description |
|
||
|--------|------|-------------|
|
||
| GET | `/api/v1/members` | Список |
|
||
| GET | `/api/v1/members/{slug}` | По slug |
|
||
|
||
---
|
||
|
||
### 4.6 Attachments (файлы)
|
||
|
||
Файлы — это аттачменты к сообщениям (Message). Чтобы прикрепить файл к задаче, отправляется сообщение с `task_id` + attachment.
|
||
|
||
| Method | Path | Description | Status |
|
||
|--------|------|-------------|--------|
|
||
| POST | `/api/v1/messages/{id}/attachments` | Загрузить файл | **TODO** |
|
||
| GET | `/api/v1/attachments/{id}` | Скачать файл | **TODO** |
|
||
| GET | `/api/v1/attachments?task_id=X` | Список файлов задачи | **TODO** |
|
||
|
||
Модель `Attachment` в БД уже есть: `id, message_id, filename, mime_type, size, storage_path`.
|
||
|
||
---
|
||
|
||
## 5. НЕсуществующие эндпоинты
|
||
|
||
Следующих эндпоинтов **НЕТ** в Tracker:
|
||
|
||
- ❌ `POST /api/v1/agents/register` — регистрация через UI или `POST /api/v1/members`
|
||
- ❌ `POST /api/v1/agents/heartbeat` — heartbeat только через WS
|
||
- ❌ `POST /api/v1/tasks/{id}/files` — файлы пока не реализованы
|
||
- ❌ `GET /api/v1/tasks/{id}/files` — файлы пока не реализованы
|
||
|
||
---
|
||
|
||
## 6. Типичный flow агента
|
||
|
||
```
|
||
1. Connect WS: ws://localhost:8100/ws
|
||
2. Send: {"type": "auth", "token": "tb-xxx"}
|
||
3. Receive: auth.ok → save projects, lobby_chat_id
|
||
4. For each project: {"type": "project.subscribe", "project_id": "uuid"}
|
||
5. Start heartbeat loop: {"type": "heartbeat", "status": "online"} every 30s
|
||
6. Listen for events:
|
||
- message.new → parse, run LLM, reply via REST POST /api/v1/messages
|
||
- task.assigned → take task, work, update status, comment result
|
||
7. All mutations via REST (не через WS)
|
||
```
|
||
|
||
---
|
||
|
||
## 7. AgentConfig
|
||
|
||
| Поле | Тип | Описание |
|
||
|------|-----|----------|
|
||
| `name` | string | Отображаемое имя |
|
||
| `slug` | string | Уникальный ID (a-z, 0-9, -) |
|
||
| `capabilities` | string[] | Что умеет (code, review, ...) |
|
||
| `chat_listen` | `all` \| `mentions` \| `none` | Фильтр чат-сообщений |
|
||
| `task_listen` | `all` \| `assigned` \| `none` | Фильтр task-событий |
|
||
| `prompt` | string? | Системный промпт |
|
||
| `model` | string? | LLM модель |
|