1119 lines
46 KiB
Markdown
1119 lines
46 KiB
Markdown
# Архитектура подключения AI-агентов к Team Board Tracker
|
||
|
||
> Исследовательский документ | Февраль 2026
|
||
|
||
---
|
||
|
||
## Содержание
|
||
|
||
1. [Обзор текущей архитектуры](#1-обзор-текущей-архитектуры)
|
||
2. [Долгосрочные сессии агентов](#2-долгосрочные-сессии-агентов)
|
||
3. [Работа агентов с задачами](#3-работа-агентов-с-задачами)
|
||
4. [Чат и коммуникация](#4-чат-и-коммуникация)
|
||
5. [Работа с кодом через Git](#5-работа-с-кодом-через-git)
|
||
6. [Паттерны из индустрии](#6-паттерны-из-индустрии)
|
||
7. [Рекомендуемая архитектура](#7-рекомендуемая-архитектура)
|
||
|
||
---
|
||
|
||
## 1. Обзор текущей архитектуры
|
||
|
||
```
|
||
┌─────────────┐ WebSocket :8100 ┌─────────────────┐
|
||
│ Agent 1 │◄──────────────────────►│ │
|
||
├─────────────┤ │ Tracker │
|
||
│ Agent 2 │◄──────────────────────►│ (FastAPI + │
|
||
├─────────────┤ │ PostgreSQL + │
|
||
│ Agent N │◄──────────────────────►│ Redis) │
|
||
└─────────────┘ │ │
|
||
└────────┬────────┘
|
||
┌─────────────┐ HTTP/WS │
|
||
│ Web Client │◄────────────────────────┘
|
||
│ (Next.js) │ via BFF
|
||
└─────────────┘
|
||
```
|
||
|
||
### Текущий протокол (baseline)
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `auth` | Agent → Tracker | Аутентификация по токену |
|
||
| `auth.ok` | Tracker → Agent | Подтверждение + init context |
|
||
| `agent.heartbeat` | Agent → Tracker | Keep-alive |
|
||
| `agent.heartbeat.ack` | Tracker → Agent | Подтверждение |
|
||
| `chat.send` | Agent → Tracker | Отправка сообщения |
|
||
| `chat.message` | Tracker → Agent | Входящее сообщение |
|
||
| `task.assigned` | Tracker → Agent | Назначение задачи |
|
||
| `task.take` | Agent → Tracker | Взятие задачи |
|
||
| `task.complete` | Agent → Tracker | Завершение задачи |
|
||
| `task.comment` | Agent → Tracker | Комментарий к задаче |
|
||
|
||
### Модель агента в БД
|
||
|
||
```sql
|
||
CREATE TABLE agents (
|
||
id UUID PRIMARY KEY,
|
||
name VARCHAR(100),
|
||
slug VARCHAR(50) UNIQUE,
|
||
token VARCHAR(256),
|
||
capabilities TEXT[], -- ['code', 'review', 'test', 'deploy']
|
||
subscription_mode VARCHAR(20), -- all | mentions | assigned
|
||
max_concurrent INT DEFAULT 3,
|
||
timeout_seconds INT DEFAULT 3600,
|
||
status VARCHAR(20) -- online | offline | busy
|
||
);
|
||
```
|
||
|
||
**Проблемы текущей архитектуры:**
|
||
- Нет персистентных сессий — при реконнекте контекст теряется
|
||
- Нет механизма зависимостей между задачами
|
||
- Нет конкурентного контроля при взятии задач
|
||
- Отсутствует контекстное окно / история для агента
|
||
- Нет интеграции с Git/CI
|
||
|
||
---
|
||
|
||
## 2. Долгосрочные сессии агентов
|
||
|
||
### 2.1 Проблема
|
||
|
||
AI-агент работает над задачей часами или днями. WebSocket соединение может оборваться. LLM имеет ограниченное контекстное окно. Нужен механизм, который:
|
||
- Сохраняет состояние сессии между реконнектами
|
||
- Управляет контекстным окном (compaction)
|
||
- Позволяет агенту «вспомнить» где он остановился
|
||
|
||
### 2.2 Модель сессии
|
||
|
||
```sql
|
||
CREATE TABLE agent_sessions (
|
||
id UUID PRIMARY KEY,
|
||
agent_id UUID REFERENCES agents(id),
|
||
task_id UUID REFERENCES tasks(id) NULL, -- привязка к задаче (опционально)
|
||
status VARCHAR(20), -- active | suspended | completed | expired
|
||
context_summary TEXT, -- compacted summary текущего контекста
|
||
created_at TIMESTAMPTZ,
|
||
updated_at TIMESTAMPTZ,
|
||
expires_at TIMESTAMPTZ,
|
||
metadata JSONB -- произвольные данные сессии
|
||
);
|
||
|
||
CREATE TABLE session_messages (
|
||
id UUID PRIMARY KEY,
|
||
session_id UUID REFERENCES agent_sessions(id),
|
||
role VARCHAR(20), -- agent | tracker | user | system
|
||
content TEXT,
|
||
created_at TIMESTAMPTZ,
|
||
seq BIGINT -- порядковый номер для восстановления
|
||
);
|
||
```
|
||
|
||
### 2.3 Протокол управления сессиями
|
||
|
||
**Создание/возобновление сессии при подключении:**
|
||
|
||
```json
|
||
// Agent → Tracker
|
||
{
|
||
"type": "session.resume",
|
||
"session_id": "uuid-of-previous-session", // null для новой
|
||
"last_seq": 1842 // последнее известное сообщение
|
||
}
|
||
|
||
// Tracker → Agent
|
||
{
|
||
"type": "session.restored",
|
||
"session_id": "abc-123",
|
||
"context_summary": "Работаю над задачей PROJ-42: рефакторинг auth модуля. Создал ветку feat/proj-42, изменил 3 файла...",
|
||
"missed_messages": [...], // сообщения после last_seq
|
||
"active_tasks": [...]
|
||
}
|
||
```
|
||
|
||
### 2.4 Compaction (сжатие контекста)
|
||
|
||
Аналогия с OpenClaw persistent sessions: когда история сессии превышает порог (например, 50K токенов), Tracker выполняет compaction:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ Session History │
|
||
│ │
|
||
│ [msg1][msg2]...[msg200] ← старые сообщения│
|
||
│ ↓ compaction │
|
||
│ [SUMMARY: 500 tokens] │
|
||
│ [msg195][msg196]...[msg210] ← свежие │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
**Два подхода к compaction:**
|
||
|
||
| Подход | Где выполняется | Плюсы | Минусы |
|
||
|--------|----------------|-------|--------|
|
||
| Server-side | Tracker вызывает LLM | Единообразие, контроль | Нагрузка на сервер, нужен LLM API |
|
||
| Agent-side | Агент присылает summary | Агент лучше знает контекст | Доверие к агенту |
|
||
|
||
**Рекомендация:** гибридный подход — агент периодически отправляет `session.checkpoint` со своим пониманием контекста, Tracker сохраняет:
|
||
|
||
```json
|
||
// Agent → Tracker
|
||
{
|
||
"type": "session.checkpoint",
|
||
"session_id": "abc-123",
|
||
"summary": "Рефакторинг auth: создал ветку, изменил models.py и routes.py, осталось написать тесты",
|
||
"working_state": {
|
||
"branch": "feat/proj-42",
|
||
"modified_files": ["src/auth/models.py", "src/auth/routes.py"],
|
||
"next_steps": ["write tests", "update docs"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.5 Reconnect и State Recovery
|
||
|
||
```
|
||
Agent disconnect (сеть упала)
|
||
│
|
||
▼
|
||
Tracker: помечает agent.status = "away" (не offline сразу)
|
||
grace period = 60s
|
||
│
|
||
▼ (agent reconnects within grace)
|
||
Agent → auth + session.resume(session_id, last_seq)
|
||
│
|
||
▼
|
||
Tracker → session.restored (missed messages + context_summary)
|
||
│
|
||
▼
|
||
Agent продолжает работу
|
||
```
|
||
|
||
**Если grace period истёк:**
|
||
- Статус → offline
|
||
- Незавершённые задачи → возвращаются в очередь (или ждут, зависит от политики)
|
||
- Сессия → suspended (можно возобновить позже)
|
||
|
||
---
|
||
|
||
## 3. Работа агентов с задачами
|
||
|
||
### 3.1 Жизненный цикл задачи
|
||
|
||
```
|
||
┌──────────┐
|
||
│ BACKLOG │
|
||
└────┬─────┘
|
||
│ task.assigned / task.available
|
||
▼
|
||
┌──────────┐
|
||
┌────────│ TODO │
|
||
│ └────┬─────┘
|
||
│ │ task.take
|
||
│ ▼
|
||
│ ┌──────────────┐
|
||
│ │ IN_PROGRESS │
|
||
│ └──┬───────┬───┘
|
||
│ │ │ task.blocked
|
||
│ │ ▼
|
||
│ │ ┌─────────┐
|
||
│ │ │ BLOCKED │──► (dependency resolved) → IN_PROGRESS
|
||
│ │ └─────────┘
|
||
│ │
|
||
│ │ task.review_request
|
||
│ ▼
|
||
│ ┌──────────┐
|
||
│ │ IN_REVIEW│
|
||
│ └────┬─────┘
|
||
│ │ task.complete / task.reject
|
||
│ ▼
|
||
│ ┌──────────┐
|
||
└───────►│ DONE │
|
||
└──────────┘
|
||
```
|
||
|
||
### 3.2 Расширенный протокол задач
|
||
|
||
**Взятие задачи (с атомарной блокировкой):**
|
||
|
||
```json
|
||
// Agent → Tracker
|
||
{
|
||
"type": "task.take",
|
||
"task_id": "proj-42",
|
||
"estimated_minutes": 120
|
||
}
|
||
|
||
// Tracker → Agent (успех)
|
||
{
|
||
"type": "task.take.ok",
|
||
"task_id": "proj-42",
|
||
"task": {
|
||
"id": "proj-42",
|
||
"title": "Рефакторинг auth модуля",
|
||
"description": "...",
|
||
"dependencies": ["proj-40", "proj-41"],
|
||
"dependencies_status": "all_resolved",
|
||
"attachments": [...],
|
||
"comments": [...],
|
||
"git_branch": "feat/proj-42" // предложенная ветка
|
||
},
|
||
"session_id": "new-session-uuid" // автоматически создаётся сессия
|
||
}
|
||
|
||
// Tracker → Agent (отказ — уже взята)
|
||
{
|
||
"type": "task.take.conflict",
|
||
"task_id": "proj-42",
|
||
"taken_by": "agent-coder-1",
|
||
"taken_at": "2026-02-15T10:30:00Z"
|
||
}
|
||
```
|
||
|
||
**Конкурентность — реализация в Tracker:**
|
||
|
||
```python
|
||
# Атомарная операция через PostgreSQL advisory lock
|
||
async def take_task(agent_id: str, task_id: str) -> bool:
|
||
async with db.transaction():
|
||
# Advisory lock по task_id
|
||
await db.execute(
|
||
"SELECT pg_advisory_xact_lock(hashtext($1))", task_id
|
||
)
|
||
task = await db.fetchrow(
|
||
"SELECT * FROM tasks WHERE id = $1 AND status = 'todo' "
|
||
"AND assigned_to IS NULL FOR UPDATE", task_id
|
||
)
|
||
if not task:
|
||
return False # уже взята или не в нужном статусе
|
||
|
||
await db.execute(
|
||
"UPDATE tasks SET assigned_to = $1, status = 'in_progress' "
|
||
"WHERE id = $2", agent_id, task_id
|
||
)
|
||
return True
|
||
```
|
||
|
||
**Обновление прогресса:**
|
||
|
||
```json
|
||
// Agent → Tracker
|
||
{
|
||
"type": "task.progress",
|
||
"task_id": "proj-42",
|
||
"progress_pct": 60,
|
||
"status_text": "Написал модели и роуты, пишу тесты",
|
||
"artifacts": [
|
||
{"type": "commit", "ref": "abc123", "message": "refactor auth models"}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Перемещение по канбану:**
|
||
|
||
```json
|
||
// Agent → Tracker
|
||
{
|
||
"type": "task.move",
|
||
"task_id": "proj-42",
|
||
"to_status": "in_review",
|
||
"comment": "Готово к ревью. PR: https://git.example.com/repo/pulls/15"
|
||
}
|
||
```
|
||
|
||
### 3.3 Зависимости задач
|
||
|
||
```sql
|
||
CREATE TABLE task_dependencies (
|
||
task_id UUID REFERENCES tasks(id),
|
||
depends_on UUID REFERENCES tasks(id),
|
||
PRIMARY KEY (task_id, depends_on)
|
||
);
|
||
```
|
||
|
||
**Уведомление о разблокировке:**
|
||
|
||
```json
|
||
// Tracker → Agent (когда все зависимости resolved)
|
||
{
|
||
"type": "task.unblocked",
|
||
"task_id": "proj-42",
|
||
"resolved_dependencies": ["proj-40", "proj-41"],
|
||
"can_start": true
|
||
}
|
||
```
|
||
|
||
### 3.4 Очередь задач и автоназначение
|
||
|
||
```
|
||
┌──────────────┐ task.available ┌──────────┐
|
||
│ Task Queue │────────────────────────►│ Agent │
|
||
│ (Redis) │◄────────────────────────│ Pool │
|
||
│ │ task.take │ │
|
||
└──────────────┘ └──────────┘
|
||
|
||
Стратегии назначения:
|
||
1. PULL: агент сам берёт из очереди (task.available → task.take)
|
||
2. PUSH: Tracker назначает по capabilities (task.assigned)
|
||
3. HYBRID: Tracker предлагает, агент подтверждает (task.offer → task.accept/decline)
|
||
```
|
||
|
||
**Рекомендация:** HYBRID модель — Tracker предлагает задачу наиболее подходящему агенту (по capabilities, загрузке, специализации), но агент может отклонить:
|
||
|
||
```json
|
||
// Tracker → Agent
|
||
{
|
||
"type": "task.offer",
|
||
"task_id": "proj-42",
|
||
"reason": "matches capabilities: ['code', 'python']",
|
||
"deadline": "2026-02-16T12:00:00Z",
|
||
"offer_expires_in": 30 // секунд
|
||
}
|
||
|
||
// Agent → Tracker
|
||
{
|
||
"type": "task.accept",
|
||
"task_id": "proj-42"
|
||
}
|
||
// или
|
||
{
|
||
"type": "task.decline",
|
||
"task_id": "proj-42",
|
||
"reason": "at max concurrent capacity"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Чат и коммуникация
|
||
|
||
### 4.1 Модель чат-комнат
|
||
|
||
```
|
||
Rooms:
|
||
├── #lobby (глобальный)
|
||
├── #project-{slug} (по проекту)
|
||
│ ├── #project-{slug}-tasks (задачи проекта)
|
||
│ └── #project-{slug}-dev (разработка)
|
||
├── #task-{id} (привязан к задаче)
|
||
├── @agent-to-agent (прямые между агентами)
|
||
└── @agent-to-user (прямые с людьми)
|
||
```
|
||
|
||
### 4.2 Подписки
|
||
|
||
```json
|
||
// Agent → Tracker (при подключении или динамически)
|
||
{
|
||
"type": "chat.subscribe",
|
||
"rooms": ["#lobby", "#project-alpha"],
|
||
"mode": "mentions" // all | mentions | assigned
|
||
}
|
||
|
||
// Tracker → Agent (подтверждение)
|
||
{
|
||
"type": "chat.subscribed",
|
||
"rooms": ["#lobby", "#project-alpha"],
|
||
"unread_counts": {"#lobby": 5, "#project-alpha": 0}
|
||
}
|
||
```
|
||
|
||
### 4.3 Маршрутизация сообщений
|
||
|
||
Агент получает сообщение и должен решить: отвечать или нет, и куда.
|
||
|
||
```json
|
||
// Tracker → Agent
|
||
{
|
||
"type": "chat.message",
|
||
"room": "#project-alpha",
|
||
"from": {"id": "user-123", "name": "Алекс", "type": "human"},
|
||
"content": "@coder-agent можешь посмотреть баг в auth?",
|
||
"mentions": ["coder-agent"],
|
||
"reply_to": null,
|
||
"thread_id": "thread-456",
|
||
"context": {
|
||
"recent_messages": 3, // кол-во недавних сообщений в треде
|
||
"related_tasks": ["proj-42"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**Логика принятия решения агентом:**
|
||
|
||
```
|
||
Получено сообщение
|
||
│
|
||
├─ Прямое упоминание (@agent)? → ОТВЕЧАТЬ (в тот же room/thread)
|
||
│
|
||
├─ subscription_mode == "all" и room подписан? → АНАЛИЗИРОВАТЬ контент
|
||
│ └─ Могу помочь? → ОТВЕЧАТЬ
|
||
│ └─ Не моя тема → МОЛЧАТЬ
|
||
│
|
||
├─ Связано с моей активной задачей? → ОТВЕЧАТЬ
|
||
│
|
||
└─ Иначе → МОЛЧАТЬ
|
||
```
|
||
|
||
### 4.4 Межагентная коммуникация
|
||
|
||
Агенты общаются через те же чат-комнаты, но с дополнительным протоколом для структурированных запросов:
|
||
|
||
```json
|
||
// Agent A → Tracker
|
||
{
|
||
"type": "agent.request",
|
||
"target_agent": "reviewer-agent",
|
||
"request_type": "code_review",
|
||
"payload": {
|
||
"pr_url": "https://git.example.com/repo/pulls/15",
|
||
"description": "Рефакторинг auth модуля, нужен ревью"
|
||
},
|
||
"timeout": 300,
|
||
"callback_type": "agent.response"
|
||
}
|
||
|
||
// Tracker → Agent B (reviewer)
|
||
{
|
||
"type": "agent.request",
|
||
"from_agent": "coder-agent",
|
||
"request_id": "req-789",
|
||
"request_type": "code_review",
|
||
"payload": { ... }
|
||
}
|
||
|
||
// Agent B → Tracker
|
||
{
|
||
"type": "agent.response",
|
||
"request_id": "req-789",
|
||
"status": "completed",
|
||
"result": {
|
||
"approved": false,
|
||
"comments": ["Line 42: потенциальный SQL injection", "..."]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Работа с кодом через Git
|
||
|
||
### 5.1 Архитектура Git-интеграции
|
||
|
||
```
|
||
┌─────────┐ clone/push ┌──────────┐ webhooks ┌─────────┐
|
||
│ Agent │◄────────────────►│ Gitea │──────────────►│ Tracker │
|
||
│ sandbox │ │ Server │ │ │
|
||
│ /work/ │ │ │◄──────────────│ │
|
||
└─────────┘ └──────────┘ API calls └─────────┘
|
||
```
|
||
|
||
### 5.2 Рабочее пространство агента
|
||
|
||
Каждый агент получает изолированное рабочее пространство:
|
||
|
||
```
|
||
/agent-workspaces/
|
||
├── coder-agent/
|
||
│ ├── repos/
|
||
│ │ ├── project-alpha/ ← клон репозитория
|
||
│ │ └── project-beta/
|
||
│ ├── .ssh/ ← deploy keys
|
||
│ └── .gitconfig
|
||
└── reviewer-agent/
|
||
└── repos/
|
||
└── project-alpha/ ← свой клон для ревью
|
||
```
|
||
|
||
### 5.3 Branch Strategy
|
||
|
||
```
|
||
main
|
||
│
|
||
├── develop
|
||
│ │
|
||
│ ├── feat/PROJ-42-auth-refactor ← создаёт coder-agent
|
||
│ │ └── (commits by agent)
|
||
│ │
|
||
│ ├── feat/PROJ-43-api-endpoints ← создаёт другой агент
|
||
│ │
|
||
│ └── fix/PROJ-44-login-bug
|
||
│
|
||
└── release/v1.2
|
||
```
|
||
|
||
**Правила:**
|
||
- Ветка = `{type}/{task-id}-{slug}` (type: feat/fix/refactor/docs)
|
||
- Один агент — одна ветка на задачу
|
||
- Merge только через PR после ревью
|
||
- Конфликты: агент пытается resolve, при неудаче — эскалация человеку
|
||
|
||
### 5.4 Git-протокол в WebSocket
|
||
|
||
```json
|
||
// Tracker → Agent (при назначении задачи с git-контекстом)
|
||
{
|
||
"type": "task.take.ok",
|
||
"task_id": "proj-42",
|
||
"task": { ... },
|
||
"git_context": {
|
||
"repo_url": "git@gitea.example.com:team/project-alpha.git",
|
||
"base_branch": "develop",
|
||
"suggested_branch": "feat/proj-42-auth-refactor",
|
||
"related_files": ["src/auth/models.py", "src/auth/routes.py"]
|
||
}
|
||
}
|
||
|
||
// Agent → Tracker (после создания PR)
|
||
{
|
||
"type": "git.pr.created",
|
||
"task_id": "proj-42",
|
||
"pr": {
|
||
"url": "https://gitea.example.com/team/project-alpha/pulls/15",
|
||
"number": 15,
|
||
"branch": "feat/proj-42-auth-refactor",
|
||
"base": "develop",
|
||
"title": "PROJ-42: Рефакторинг auth модуля",
|
||
"files_changed": 5,
|
||
"additions": 120,
|
||
"deletions": 45
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.5 Code Review Flow
|
||
|
||
```
|
||
coder-agent Tracker reviewer-agent
|
||
│ │ │
|
||
│── git.pr.created ─────────►│ │
|
||
│ │── task.offer (review) ────►│
|
||
│ │◄── task.accept ────────────│
|
||
│ │ │
|
||
│ │ (reviewer клонирует, │
|
||
│ │ читает diff, анализирует)│
|
||
│ │ │
|
||
│ │◄── git.review.complete ────│
|
||
│◄── git.review.result ──────│ {approved: false, │
|
||
│ (с комментариями) │ comments: [...]} │
|
||
│ │ │
|
||
│ (агент исправляет) │ │
|
||
│── git.pr.updated ─────────►│ │
|
||
│ │── (notify reviewer) ──────►│
|
||
│ │ │
|
||
│ │◄── git.review.complete ────│
|
||
│◄── git.review.result ──────│ {approved: true} │
|
||
│ │ │
|
||
│── task.move(in_review→done)│ │
|
||
```
|
||
|
||
### 5.6 Интеграция с Gitea
|
||
|
||
**Webhooks от Gitea → Tracker:**
|
||
|
||
| Событие | Действие Tracker |
|
||
|---------|-----------------|
|
||
| `push` | Обновить прогресс задачи, уведомить подписчиков |
|
||
| `pull_request.opened` | Создать задачу на ревью или назначить reviewer |
|
||
| `pull_request.reviewed` | Уведомить автора о результате |
|
||
| `pull_request.merged` | Переместить задачу в DONE |
|
||
| `issues.opened` | Создать задачу в Tracker |
|
||
|
||
**Tracker → Gitea API:**
|
||
|
||
```python
|
||
# Создание ветки
|
||
POST /api/v1/repos/{owner}/{repo}/branches
|
||
{"new_branch_name": "feat/proj-42", "old_branch_name": "develop"}
|
||
|
||
# Создание PR
|
||
POST /api/v1/repos/{owner}/{repo}/pulls
|
||
{"title": "PROJ-42: ...", "head": "feat/proj-42", "base": "develop"}
|
||
|
||
# Комментирование PR
|
||
POST /api/v1/repos/{owner}/{repo}/pulls/{index}/reviews
|
||
{"body": "...", "event": "REQUEST_CHANGES"}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Паттерны из индустрии
|
||
|
||
### 6.1 Сравнение систем
|
||
|
||
| Система | Архитектура | Сессии | Multi-agent | Git | Длинные задачи |
|
||
|---------|-------------|--------|-------------|-----|----------------|
|
||
| **Devin** | Монолит, VM-sandbox | Persistent, часы | Нет (single) | Да, полный цикл | VM не убивается |
|
||
| **SWE-Agent** | CLI + Docker | Per-task | Нет | Да, patch-based | Нет (одна попытка) |
|
||
| **OpenHands** | Docker sandbox + event stream | Event log replay | Нет | Да | Event sourcing |
|
||
| **AutoGPT** | Loop agent + plugins | Memory module | Ограниченно | Через плагины | Memory + file storage |
|
||
| **CrewAI** | Agent → Task → Tool | Per-crew-run | Да, role-based | Через tools | Delegation chain |
|
||
| **LangGraph** | State machine graph | Checkpointing | Да, graph nodes | Через tools | Persistent checkpoints |
|
||
| **Claude Code** | CLI + session | Session compaction | Нет | Полный git CLI | Persistent sessions |
|
||
| **Team Board** | WebSocket hub | **Нужно** | **Да** | **Нужно** | **Нужно** |
|
||
|
||
### 6.2 Ключевые паттерны
|
||
|
||
#### Паттерн 1: Event Sourcing (OpenHands)
|
||
|
||
Вся работа агента — поток событий. Воспроизведя события, можно восстановить состояние.
|
||
|
||
```
|
||
Event Stream: [FileRead, CodeEdit, CmdRun, FileRead, CodeEdit, CmdRun, ...]
|
||
│
|
||
Checkpoint (snapshot)
|
||
│
|
||
Resume: load snapshot + replay events after it
|
||
```
|
||
|
||
**Применимость для Team Board:** ★★★★★ — отлично подходит для восстановления сессий. Каждое действие агента = событие в `session_messages`.
|
||
|
||
#### Паттерн 2: Persistent Checkpointing (LangGraph)
|
||
|
||
Граф состояний с возможностью сохранения checkpoint в любой точке. При сбое — восстановление с последнего checkpoint.
|
||
|
||
```python
|
||
# LangGraph-style checkpoint
|
||
checkpoint = {
|
||
"state": {"task": "proj-42", "step": "writing_tests"},
|
||
"channel_values": {"messages": [...last_5...]},
|
||
"metadata": {"step_count": 42}
|
||
}
|
||
```
|
||
|
||
**Применимость для Team Board:** ★★★★☆ — модель `session.checkpoint` в нашем протоколе реализует этот паттерн.
|
||
|
||
#### Паттерн 3: Role-Based Delegation (CrewAI)
|
||
|
||
Агенты имеют роли (coder, reviewer, tester, PM). Задачи маршрутизируются по ролям. Агент может делегировать подзадачу другому.
|
||
|
||
```
|
||
PM Agent: "Нужно реализовать фичу X"
|
||
│
|
||
├──► Coder Agent: "Напиши код"
|
||
│ └──► Tester Agent: "Напиши тесты"
|
||
│
|
||
└──► Reviewer Agent: "Проверь когда будет PR"
|
||
```
|
||
|
||
**Применимость для Team Board:** ★★★★★ — capabilities + agent.request протокол реализуют это.
|
||
|
||
#### Паттерн 4: Sandbox Isolation (Devin, SWE-Agent)
|
||
|
||
Каждый агент работает в изолированном окружении (Docker/VM), где может безопасно выполнять код.
|
||
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ Agent Sandbox │
|
||
│ ┌─────────┐ ┌──────────────┐ │
|
||
│ │ Git │ │ Shell/Code │ │
|
||
│ │ clone │ │ execution │ │
|
||
│ └─────────┘ └──────────────┘ │
|
||
│ ┌─────────┐ ┌──────────────┐ │
|
||
│ │ Files │ │ Network │ │
|
||
│ │ /work/ │ │ (filtered) │ │
|
||
│ └─────────┘ └──────────────┘ │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
**Применимость для Team Board:** ★★★★☆ — важно для безопасности, но можно реализовать позже. На первом этапе — Docker containers per agent.
|
||
|
||
#### Паттерн 5: Tool-Use Protocol (Claude, GPT Function Calling)
|
||
|
||
Агент не выполняет действия напрямую — он запрашивает выполнение «инструментов» у среды. Среда выполняет и возвращает результат.
|
||
|
||
```json
|
||
// Agent → Tracker
|
||
{"type": "tool.call", "tool": "git.diff", "args": {"branch": "feat/proj-42"}}
|
||
|
||
// Tracker → Agent
|
||
{"type": "tool.result", "result": "diff --git a/..."}
|
||
```
|
||
|
||
**Применимость для Team Board:** ★★★☆☆ — полезно для агентов без собственного sandbox. Tracker может проксировать инструменты. Но увеличивает нагрузку на Tracker.
|
||
|
||
### 6.3 Подходы к долгим задачам
|
||
|
||
| Подход | Как работает | Пример |
|
||
|--------|-------------|--------|
|
||
| **Checkpoint + Resume** | Периодическое сохранение состояния, возобновление после сбоя | LangGraph, OpenHands |
|
||
| **Plan → Execute → Verify** | Агент сначала планирует, потом выполняет шаги, проверяет результат | Devin, SWE-Agent |
|
||
| **Hierarchical Decomposition** | Большая задача разбивается на подзадачи, каждая — отдельный цикл | CrewAI, AutoGPT |
|
||
| **Event Sourcing + Replay** | Все действия записываются, состояние воспроизводимо | OpenHands |
|
||
| **Session Compaction** | Длинная история сжимается в summary + recent window | Claude Code, OpenClaw |
|
||
|
||
**Рекомендация для Team Board:** комбинация Checkpoint + Resume и Session Compaction с Hierarchical Decomposition для сложных задач.
|
||
|
||
---
|
||
|
||
## 7. Рекомендуемая архитектура
|
||
|
||
### 7.1 Целевая архитектура
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ TRACKER v2 │
|
||
│ │
|
||
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
|
||
│ │ WS Hub │ │ Session │ │ Task │ │
|
||
│ │ :8100 │ │ Manager │ │ Engine │ │
|
||
│ └────┬─────┘ └─────┬─────┘ └────┬─────┘ │
|
||
│ │ │ │ │
|
||
│ ┌────┴──────────────┴──────────────┴─────┐ │
|
||
│ │ Event Bus (Redis Streams) │ │
|
||
│ └────┬──────────────┬──────────────┬─────┘ │
|
||
│ │ │ │ │
|
||
│ ┌────┴─────┐ ┌─────┴─────┐ ┌────┴──────┐ │
|
||
│ │ Chat │ │ Git │ │ Agent │ │
|
||
│ │ Router │ │Integration│ │ Registry │ │
|
||
│ └──────────┘ └───────────┘ └───────────┘ │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ PostgreSQL + Redis │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
▲ ▲ ▲
|
||
│ WS │ WS │ Webhooks
|
||
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
|
||
│ Agent 1 │ │ Agent 2 │ │ Gitea │
|
||
│(sandbox)│ │(sandbox)│ │ │
|
||
└─────────┘ └─────────┘ └─────────┘
|
||
```
|
||
|
||
### 7.2 Полный протокол v2
|
||
|
||
#### Lifecycle
|
||
|
||
```
|
||
CONNECT → auth → auth.ok
|
||
│
|
||
├── session.resume / session.create
|
||
│ → session.restored / session.created
|
||
│
|
||
├── chat.subscribe → chat.subscribed
|
||
│
|
||
├── task.offer → task.accept/decline
|
||
│ task.take → task.take.ok/conflict
|
||
│
|
||
│ (работа над задачей)
|
||
│ task.progress
|
||
│ session.checkpoint
|
||
│ git.pr.created
|
||
│ agent.request → agent.response
|
||
│
|
||
├── task.move → task.moved
|
||
├── task.complete → task.completed
|
||
│
|
||
├── agent.heartbeat → agent.heartbeat.ack
|
||
│
|
||
DISCONNECT → (grace period) → session.suspend
|
||
```
|
||
|
||
#### Полный список событий
|
||
|
||
**Аутентификация и сессии:**
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `auth` | A→T | Аутентификация |
|
||
| `auth.ok` | T→A | Подтверждение с init context |
|
||
| `auth.error` | T→A | Ошибка аутентификации |
|
||
| `session.create` | A→T | Создать новую сессию |
|
||
| `session.resume` | A→T | Возобновить существующую |
|
||
| `session.created` | T→A | Сессия создана |
|
||
| `session.restored` | T→A | Сессия восстановлена |
|
||
| `session.checkpoint` | A→T | Сохранить контрольную точку |
|
||
| `session.checkpoint.ok` | T→A | Контрольная точка сохранена |
|
||
|
||
**Задачи:**
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `task.available` | T→A | Доступна новая задача (broadcast) |
|
||
| `task.offer` | T→A | Предложение задачи конкретному агенту |
|
||
| `task.accept` | A→T | Принятие предложенной задачи |
|
||
| `task.decline` | A→T | Отклонение предложенной задачи |
|
||
| `task.take` | A→T | Взятие задачи из очереди |
|
||
| `task.take.ok` | T→A | Задача назначена |
|
||
| `task.take.conflict` | T→A | Конфликт — задача уже взята |
|
||
| `task.progress` | A→T | Обновление прогресса |
|
||
| `task.move` | A→T | Перемещение по канбану |
|
||
| `task.moved` | T→A | Подтверждение перемещения |
|
||
| `task.complete` | A→T | Завершение задачи |
|
||
| `task.completed` | T→A | Подтверждение завершения |
|
||
| `task.comment` | A→T | Комментарий к задаче |
|
||
| `task.blocked` | A→T | Агент заблокирован зависимостью |
|
||
| `task.unblocked` | T→A | Зависимость разрешена |
|
||
| `task.assigned` | T→A | Задача назначена (push) |
|
||
| `task.release` | A→T | Агент отказывается от задачи |
|
||
|
||
**Чат:**
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `chat.subscribe` | A→T | Подписка на комнаты |
|
||
| `chat.subscribed` | T→A | Подтверждение подписки |
|
||
| `chat.unsubscribe` | A→T | Отписка |
|
||
| `chat.send` | A→T | Отправка сообщения |
|
||
| `chat.message` | T→A | Входящее сообщение |
|
||
| `chat.history` | A→T | Запрос истории |
|
||
| `chat.history.result` | T→A | История сообщений |
|
||
|
||
**Межагентная коммуникация:**
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `agent.request` | A→T / T→A | Запрос к другому агенту |
|
||
| `agent.response` | A→T / T→A | Ответ на запрос |
|
||
| `agent.broadcast` | A→T | Широковещательное сообщение агентам |
|
||
|
||
**Git:**
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `git.pr.created` | A→T | PR создан |
|
||
| `git.pr.updated` | A→T | PR обновлён |
|
||
| `git.review.request` | T→A | Запрос на ревью |
|
||
| `git.review.complete` | A→T | Ревью завершено |
|
||
| `git.review.result` | T→A | Результат ревью |
|
||
| `git.webhook` | External→T | Webhook от Gitea |
|
||
|
||
**Системные:**
|
||
|
||
| Событие | Направление | Описание |
|
||
|---------|-------------|----------|
|
||
| `agent.heartbeat` | A→T | Keep-alive |
|
||
| `agent.heartbeat.ack` | T→A | Подтверждение |
|
||
| `agent.status` | A→T | Обновление статуса |
|
||
| `error` | T→A | Ошибка |
|
||
|
||
### 7.3 Что добавить в Tracker
|
||
|
||
**Приоритет 1 (MVP):**
|
||
1. `agent_sessions` + `session_messages` таблицы
|
||
2. `session.resume` / `session.restored` протокол
|
||
3. `task.take` с advisory lock (конкурентность)
|
||
4. `task_dependencies` таблица + `task.unblocked`
|
||
5. `task.offer` / `task.accept` / `task.decline`
|
||
6. `task.progress` с progress_pct
|
||
|
||
**Приоритет 2 (Git):**
|
||
7. Gitea webhook handler
|
||
8. `git.pr.created` / `git.review.request` протокол
|
||
9. Автоматическое создание веток при task.take
|
||
|
||
**Приоритет 3 (Advanced):**
|
||
10. `session.checkpoint` + compaction
|
||
11. `agent.request` / `agent.response` (inter-agent)
|
||
12. Redis Streams для event bus
|
||
13. Rate limiting per agent
|
||
|
||
### 7.4 Agent SDK
|
||
|
||
Минимальный SDK на Python:
|
||
|
||
```python
|
||
from team_board_sdk import Agent, TaskHandler
|
||
|
||
class CoderAgent(Agent):
|
||
name = "coder-agent"
|
||
capabilities = ["code", "python", "javascript"]
|
||
subscription_mode = "mentions"
|
||
max_concurrent = 3
|
||
|
||
async def on_task_offer(self, task):
|
||
"""Вызывается при предложении задачи"""
|
||
if self.active_tasks_count < self.max_concurrent:
|
||
await self.accept_task(task)
|
||
else:
|
||
await self.decline_task(task, reason="busy")
|
||
|
||
async def on_task_assigned(self, task):
|
||
"""Вызывается при назначении задачи"""
|
||
# Автоматически создаётся сессия
|
||
session = self.current_session
|
||
|
||
# Клонируем/обновляем репо
|
||
repo = await self.git.ensure_repo(task.git_context.repo_url)
|
||
branch = await repo.create_branch(task.git_context.suggested_branch)
|
||
|
||
# Работаем
|
||
await self.update_progress(task, 10, "Анализирую задачу")
|
||
plan = await self.llm.plan(task.description, repo.get_context())
|
||
|
||
for i, step in enumerate(plan.steps):
|
||
await self.execute_step(step)
|
||
pct = int((i + 1) / len(plan.steps) * 80) + 10
|
||
await self.update_progress(task, pct, step.description)
|
||
|
||
# Checkpoint каждые 5 шагов
|
||
if i % 5 == 0:
|
||
await self.session.checkpoint(
|
||
summary=f"Выполнено {i+1}/{len(plan.steps)} шагов",
|
||
working_state={"step": i, "branch": branch.name}
|
||
)
|
||
|
||
# Создаём PR
|
||
pr = await self.git.create_pr(
|
||
repo, branch, task.git_context.base_branch,
|
||
title=f"{task.id}: {task.title}"
|
||
)
|
||
await self.notify_pr_created(task, pr)
|
||
await self.move_task(task, "in_review")
|
||
|
||
async def on_chat_message(self, message):
|
||
"""Вызывается при упоминании в чате"""
|
||
if self.is_mentioned(message):
|
||
response = await self.llm.respond(message, self.current_context)
|
||
await self.chat.send(message.room, response, reply_to=message.id)
|
||
|
||
async def on_reconnect(self, session):
|
||
"""Вызывается при восстановлении сессии"""
|
||
print(f"Resumed: {session.context_summary}")
|
||
# SDK автоматически восстанавливает состояние
|
||
|
||
agent = CoderAgent(token="agent-token-xxx")
|
||
agent.run("ws://tracker:8100")
|
||
```
|
||
|
||
**Структура SDK:**
|
||
|
||
```
|
||
team-board-sdk/
|
||
├── team_board_sdk/
|
||
│ ├── __init__.py
|
||
│ ├── agent.py # Базовый класс Agent
|
||
│ ├── connection.py # WebSocket connection + reconnect
|
||
│ ├── session.py # Session management + checkpoints
|
||
│ ├── task.py # Task lifecycle helpers
|
||
│ ├── chat.py # Chat routing
|
||
│ ├── git.py # Git operations (clone, branch, PR)
|
||
│ ├── llm.py # LLM interface (pluggable)
|
||
│ └── types.py # Pydantic models для протокола
|
||
├── examples/
|
||
│ ├── coder_agent.py
|
||
│ ├── reviewer_agent.py
|
||
│ └── pm_agent.py
|
||
└── pyproject.toml
|
||
```
|
||
|
||
### 7.5 Production Requirements
|
||
|
||
**Логирование:**
|
||
- Structured logging (JSON) для всех событий
|
||
- Отдельный лог-стрим на агента
|
||
- Retention: 30 дней events, 7 дней debug
|
||
|
||
**Мониторинг:**
|
||
- Метрики: active agents, tasks/hour, avg task duration, session count
|
||
- Alerting: agent offline > 5min, task stuck > timeout, error rate > threshold
|
||
- Dashboard: Grafana с WS connections, task flow, agent utilization
|
||
|
||
**Rate Limiting:**
|
||
```python
|
||
RATE_LIMITS = {
|
||
"chat.send": "30/min per agent",
|
||
"task.progress": "10/min per task",
|
||
"session.checkpoint": "5/min per session",
|
||
"agent.request": "20/min per agent",
|
||
"git.*": "10/min per agent"
|
||
}
|
||
```
|
||
|
||
**Security:**
|
||
- Token rotation (30 дней)
|
||
- Per-agent capability enforcement (агент с capabilities=["code"] не может делать review)
|
||
- Audit log всех действий
|
||
- Sandbox isolation (Docker) для агентов с code execution
|
||
|
||
**Масштабирование:**
|
||
- Tracker горизонтально масштабируется через Redis pub/sub (sticky sessions по agent_id)
|
||
- WebSocket connections: ~1000 на инстанс (с nginx upstream)
|
||
- PostgreSQL: partitioning session_messages по дате
|
||
|
||
---
|
||
|
||
## Приложение A: Миграции БД
|
||
|
||
```sql
|
||
-- Сессии агентов
|
||
CREATE TABLE agent_sessions (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
agent_id UUID NOT NULL REFERENCES agents(id),
|
||
task_id UUID REFERENCES tasks(id),
|
||
status VARCHAR(20) NOT NULL DEFAULT 'active',
|
||
context_summary TEXT,
|
||
metadata JSONB DEFAULT '{}',
|
||
created_at TIMESTAMPTZ DEFAULT now(),
|
||
updated_at TIMESTAMPTZ DEFAULT now(),
|
||
expires_at TIMESTAMPTZ
|
||
);
|
||
|
||
CREATE INDEX idx_sessions_agent ON agent_sessions(agent_id, status);
|
||
CREATE INDEX idx_sessions_task ON agent_sessions(task_id);
|
||
|
||
-- Сообщения сессий
|
||
CREATE TABLE session_messages (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE,
|
||
role VARCHAR(20) NOT NULL,
|
||
content TEXT NOT NULL,
|
||
seq BIGSERIAL,
|
||
created_at TIMESTAMPTZ DEFAULT now()
|
||
);
|
||
|
||
CREATE INDEX idx_session_msgs ON session_messages(session_id, seq);
|
||
|
||
-- Зависимости задач
|
||
CREATE TABLE task_dependencies (
|
||
task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||
depends_on UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||
PRIMARY KEY (task_id, depends_on)
|
||
);
|
||
|
||
-- Межагентные запросы
|
||
CREATE TABLE agent_requests (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
from_agent_id UUID NOT NULL REFERENCES agents(id),
|
||
to_agent_id UUID REFERENCES agents(id),
|
||
request_type VARCHAR(50) NOT NULL,
|
||
payload JSONB NOT NULL,
|
||
status VARCHAR(20) DEFAULT 'pending',
|
||
result JSONB,
|
||
created_at TIMESTAMPTZ DEFAULT now(),
|
||
resolved_at TIMESTAMPTZ,
|
||
timeout_at TIMESTAMPTZ
|
||
);
|
||
```
|
||
|
||
## Приложение B: Roadmap внедрения
|
||
|
||
```
|
||
Phase 1 (2 недели): Sessions + Task Concurrency
|
||
├── agent_sessions таблица
|
||
├── session.resume/restore протокол
|
||
├── task.take с advisory lock
|
||
└── task_dependencies + task.unblocked
|
||
|
||
Phase 2 (2 недели): Enhanced Tasks + Chat
|
||
├── task.offer/accept/decline
|
||
├── task.progress
|
||
├── chat.subscribe с modes
|
||
└── agent.request/response
|
||
|
||
Phase 3 (3 недели): Git Integration
|
||
├── Gitea webhook handler
|
||
├── git.pr.created/review протокол
|
||
├── Auto branch creation
|
||
└── Agent SDK v0.1
|
||
|
||
Phase 4 (2 недели): Production Hardening
|
||
├── Rate limiting
|
||
├── Monitoring + alerting
|
||
├── Session compaction
|
||
└── Agent SDK v1.0
|
||
```
|
||
|
||
---
|
||
|
||
*Документ подготовлен: Февраль 2026*
|
||
*Автор: AI Research Agent*
|
||
*Версия: 1.0*
|