150 lines
7.9 KiB
Markdown
150 lines
7.9 KiB
Markdown
# Multi-Agent Orchestrator
|
||
|
||
FastAPI-сервис для оркестрации мульти-агентного пайплайна разработки. Принимает webhooks от Plane и Gitea, управляет жизненным циклом задач через Quality Gates, запускает Claude CLI агентов на каждой стадии.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Plane (task mgmt) ──webhook──┐
|
||
├──► Orchestrator (FastAPI) ──► Quality Gates ──► Agent Launcher
|
||
Gitea (git events) ─webhook──┘ │ │
|
||
▼ ▼
|
||
SQLite DB Claude CLI
|
||
(events, tasks, (analyst, architect,
|
||
agent_runs) developer, reviewer, tester)
|
||
```
|
||
|
||
## Стадии пайплайна
|
||
|
||
```
|
||
created → analysis → architecture → development → review → testing → deploy → done
|
||
↑ │
|
||
└─── REQUEST_CHANGES ─┘ (max 3 retries)
|
||
```
|
||
|
||
| Стадия | Агент | Quality Gate (выход) | Триггер перехода |
|
||
|--------|-------|---------------------|------------------|
|
||
| created | — | — | Plane webhook (work_item.created) |
|
||
| analysis | analyst | Файлы BRD/TRZ/AC/TestPlan | Push docs/ |
|
||
| architecture | architect | ADR или infra-requirements | Push docs/ |
|
||
| development | developer | check_tests_local (орк сам гоняет `make test`) | Auto-advance после developer |
|
||
| review | reviewer | check_reviewer_verdict (`verdict:` во frontmatter 12-review.md) | Auto-advance после reviewer |
|
||
| testing | tester | Test report с PASS | Auto-advance после tester |
|
||
| deploy | deployer | — | SSH deploy-hook |
|
||
| done | — | — | — |
|
||
|
||
## API Endpoints
|
||
|
||
| Method | Path | Описание |
|
||
|--------|------|----------|
|
||
| GET | `/health` | Health check |
|
||
| GET | `/status` | Активные задачи (stage != done) |
|
||
| POST | `/webhook/plane` | Plane webhook receiver |
|
||
| POST | `/webhook/gitea` | Gitea webhook receiver |
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
src/
|
||
├── main.py # FastAPI app, lifespan (orphan recovery)
|
||
├── config.py # Pydantic settings (env vars)
|
||
├── db.py # SQLite: init, get_db, update_task_stage
|
||
├── stages.py # State machine (transitions, agents, QG)
|
||
├── notifications.py # Уведомления (логирование)
|
||
├── plane_sync.py # Синхронизация статусов с Plane API
|
||
├── agents/
|
||
│ └── launcher.py # AgentLauncher: launch, monitor, watchdog, auto-advance
|
||
├── webhooks/
|
||
│ ├── plane.py # Plane webhook handler
|
||
│ └── gitea.py # Gitea webhook handler (push, PR, CI status)
|
||
└── qg/
|
||
└── checks.py # Quality Gate checks (filesystem + Gitea API)
|
||
data/
|
||
├── orchestrator.db # SQLite database
|
||
└── runs/ # Agent output logs ({run_id}.log)
|
||
docs/
|
||
├── ARCHITECTURE.md # Подробная архитектура
|
||
├── LESSONS_ET006.md # Lessons learned из ET-006
|
||
├── BUGFIXES_2026-05-21.md # Багфиксы
|
||
└── SETUP_WEBHOOKS.md # Настройка webhooks
|
||
docker-compose.yml # Deployment config
|
||
Dockerfile # Python 3.12 + Docker CLI + tini
|
||
```
|
||
|
||
## Запуск
|
||
|
||
### Docker (production)
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
### Dev
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
uvicorn src.main:app --reload --port 8500
|
||
```
|
||
|
||
## Конфигурация
|
||
|
||
Все переменные с префиксом `ORCH_`:
|
||
|
||
| Переменная | Описание | Default |
|
||
|-----------|----------|---------|
|
||
| `ORCH_PLANE_API_URL` | Plane API URL | `http://localhost:8091` |
|
||
| `ORCH_PLANE_API_TOKEN` | Plane API token | — |
|
||
| `ORCH_PLANE_WEBHOOK_SECRET` | Webhook secret | — |
|
||
| `ORCH_PLANE_WORKSPACE_SLUG` | Workspace slug | — |
|
||
| `ORCH_PLANE_PROJECT_ID` | Project UUID | — |
|
||
| `ORCH_GITEA_URL` | Gitea URL | `http://localhost:3000` |
|
||
| `ORCH_GITEA_TOKEN` | Gitea API token | — |
|
||
| `ORCH_GITEA_WEBHOOK_SECRET` | Gitea webhook secret | — |
|
||
| `ORCH_GITEA_OWNER` | Gitea repo owner | `admin` |
|
||
| `ORCH_DEFAULT_REPO` | Default repository | `enduro-trails` |
|
||
| `ORCH_CLAUDE_BIN` | Путь к Claude CLI | `/opt/claude-code/bin/claude.exe` |
|
||
| `ORCH_REPOS_DIR` | Repos dir (container) | `/repos` |
|
||
| `ORCH_HOST_REPOS_DIR` | Repos dir (host) | `/home/slin/repos` |
|
||
| `ORCH_DB_PATH` | SQLite path | `/app/data/orchestrator.db` |
|
||
|
||
## Ключевые механизмы
|
||
|
||
### Auto-advance
|
||
После успешного завершения агента (exit_code=0), `_try_advance_stage()` проверяет QG и автоматически продвигает задачу + запускает следующего агента.
|
||
|
||
### Review bounce
|
||
При REQUEST_CHANGES от reviewer задача откатывается в development, developer перезапускается (до 3 попыток). При исчерпании — эскалация.
|
||
|
||
### Orphan recovery (M-1)
|
||
При старте контейнера каждый run с `finished_at IS NULL` старше 35 минут помечается exit_code=-1, логируется per-run warning и отправляется Telegram-уведомление «нужна ручная проверка/перезапуск» (не молча).
|
||
|
||
### Запись task-файлов (B-1)
|
||
Task-файлы `.task-*.md` пишутся **прямой записью в смонтированный volume `/repos/<repo>/`** (без docker). При ошибке записи — RuntimeError (не молчит). В `.gitignore` проекта.
|
||
|
||
### Логи агентов (B-2)
|
||
stdout/stderr агента перенаправляются СРАЗУ в `/app/data/runs/{id}.log` на уровне ОС (без PIPE). monitor-поток делает `proc.wait()` → реальный exit_code, нет зомби.
|
||
|
||
### Watchdog
|
||
Каждый агент имеет timeout 30 минут. При превышении — SIGKILL + запись exit_code=-9.
|
||
|
||
### Event routing
|
||
Gitea events роутятся по типу:
|
||
- `push` → проверка файлов, advance architecture/development
|
||
- `pull_request*` (wildcard) → review approved/rejected, PR merge
|
||
- `status` → (legacy) Gitea CI; С-1: больше не authoritative, `failure` логируется на debug и не блокирует/не алертит (QG развития = локальный `check_tests_local`)
|
||
|
||
## Тесты
|
||
|
||
```bash
|
||
pytest tests/ -v
|
||
```
|
||
|
||
## Известные ограничения
|
||
|
||
1. **Single-task / shared `/repos` checkout** — одновременно безопасно обрабатывается одна задача: все агенты и `check_tests_local` делают `git checkout` в одном `/repos/<repo>` → гонки при параллельных задачах. Исправление — git worktree per task (S-4, отдельно).
|
||
2. **Plane sync** — маппинг issue ID может быть некорректным (P3, в работе)
|
||
3. **In-process daemon-потоки** — агенты живут в потоках uvicorn; при рестарте ловит orphan-recovery. Целевое — очередь задач (F-2b)
|
||
4. **Gitea CI не настроен** — тесты гоняет сам оркестратор локально
|
||
3. **Tester timeout** — e2e тесты с Playwright могут занимать >25 мин на тяжёлых фичах
|
||
4. **No retry on API errors** — httpx вызовы к Gitea/Plane без retry logic
|