docs: add Agent Management and OpenClaw Webhooks integration

- Agent Registry schema
- OpenClaw Webhooks API documentation
- Team Board → OpenClaw architecture
- Python client example
- Task execution flow
This commit is contained in:
Markov 2026-02-15 15:41:37 +01:00
parent 35907c0e0f
commit 4209bc26fd

View File

@ -354,4 +354,313 @@ class AgentSessionManager:
---
## Agent Management System
### Agent Registry (БД)
```sql
CREATE TABLE agents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL, -- "Coder", "Analyst"
slug TEXT UNIQUE NOT NULL, -- "coder", "analyst"
-- Настройки
model TEXT, -- "claude-opus-4-5", "claude-sonnet"
system_prompt TEXT, -- роль/персона
max_concurrent INT DEFAULT 1, -- макс параллельных задач
-- Статус
status TEXT DEFAULT 'idle', -- idle, working, error, disabled
current_tasks INT DEFAULT 0,
-- Мета
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
### Web UI: Agent Config
```
┌─────────────────────────────────────────────┐
│ Agents [+ Add] │
├─────────────────────────────────────────────┤
│ 🟢 Coder claude-opus idle [⚙] │
│ 🟢 Reviewer claude-sonnet idle [⚙] │
│ 🟡 Analyst claude-opus working[⚙] │
│ ⚫ Tester claude-sonnet disabled[⚙] │
└─────────────────────────────────────────────┘
```
### Task Assignment Flow
```
1. User создаёт задачу в Web UI
2. Назначает агента (или Auto → Lead решает)
3. Team Board → POST /hooks/agent → OpenClaw
4. OpenClaw проверяет лимиты, спавнит субагента
5. Субагент работает, результат → callback
6. Team Board обновляет задачу в БД
```
---
## OpenClaw Webhooks API
### Конфигурация
```json
{
"hooks": {
"enabled": true,
"token": "${OPENCLAW_HOOKS_TOKEN}",
"path": "/hooks",
"defaultSessionKey": "hook:team-board",
"allowRequestSessionKey": true,
"allowedSessionKeyPrefixes": ["hook:", "task:"],
"allowedAgentIds": ["main", "coder", "reviewer"]
}
}
```
### Эндпоинты
#### POST /hooks/wake — Разбудить основную сессию
```bash
curl -X POST http://localhost:18789/hooks/wake \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "Новая задача в Team Board", "mode": "now"}'
```
**Параметры:**
- `text` (required) — описание события
- `mode``now` (сразу) или `next-heartbeat` (при след. проверке)
#### POST /hooks/agent — Запустить изолированную сессию
```bash
curl -X POST http://localhost:18789/hooks/agent \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Напиши функцию сортировки на Python",
"name": "TeamBoard",
"agentId": "main",
"sessionKey": "task:abc123",
"deliver": true,
"channel": "telegram",
"timeoutSeconds": 300
}'
```
**Параметры:**
- `message` (required) — промпт для агента
- `name` — название хука для логов
- `agentId` — ID агента (main, coder, etc.)
- `sessionKey` — ключ сессии для отслеживания
- `deliver` — отправить ответ в канал
- `channel` — канал для ответа (telegram, discord, etc.)
- `model` — переопределение модели
- `thinking` — уровень размышлений (low, medium, high)
- `timeoutSeconds` — таймаут выполнения
### Аутентификация
```
Authorization: Bearer <token>
# или
x-openclaw-token: <token>
```
⚠️ Query-string токены (`?token=...`) запрещены.
---
## Team Board → OpenClaw Integration
### Архитектура
```
┌─────────────────────────────────────────────────────────────┐
│ Team Board │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Web UI │ │ Tasks │ │ Agents │ │
│ │ (Next.js) │ │ Service │ │ Service │ │
│ └─────────────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ OpenClaw │ │
│ │ Client │ │
│ └────────┬────────┘ │
└───────────────────────────────────┼─────────────────────────┘
│ HTTP
┌───────────────────────────────────────────────────────────────┐
│ OpenClaw Gateway │
│ localhost:18789 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ /hooks/wake │ │/hooks/agent │ │ Sessions │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Agent: main (Марков) │ │
│ │ - sessions_spawn → субагенты │ │
│ │ - sessions_send → коммуникация │ │
│ │ - sessions_history → история │ │
│ └─────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
```
### OpenClaw Client (Python)
```python
import httpx
from typing import Optional
class OpenClawClient:
def __init__(self, base_url: str, token: str):
self.base_url = base_url
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
async def wake(self, text: str, mode: str = "now"):
"""Разбудить основную сессию"""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/hooks/wake",
headers=self.headers,
json={"text": text, "mode": mode}
)
return response.json()
async def run_agent(
self,
message: str,
session_key: str,
agent_id: str = "main",
deliver: bool = False,
timeout: int = 300
):
"""Запустить задачу в изолированной сессии"""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/hooks/agent",
headers=self.headers,
json={
"message": message,
"name": "TeamBoard",
"agentId": agent_id,
"sessionKey": session_key,
"deliver": deliver,
"timeoutSeconds": timeout
}
)
return response.json()
```
### Task Execution Flow
```python
async def execute_task(task: Task, agent: Agent):
client = OpenClawClient(
base_url="http://localhost:18789",
token=settings.OPENCLAW_TOKEN
)
# Формируем промпт
prompt = f"""
Задача: {task.title}
Описание: {task.description}
Контекст проекта: {task.project.brief}
Выполни задачу и верни результат.
"""
# Запускаем агента
result = await client.run_agent(
message=prompt,
session_key=f"task:{task.id}",
agent_id=agent.slug,
timeout=600
)
# Обновляем статус
task.status = "in_progress"
task.openclaw_session = result.get("sessionKey")
await task.save()
return result
```
### Получение результатов
**Вариант 1: Polling**
```python
async def poll_task_result(task: Task):
client = OpenClawClient(...)
# Получаем историю сессии
history = await client.get_session_history(task.openclaw_session)
# Парсим последний ответ
last_message = history["messages"][-1]
if last_message["role"] == "assistant":
task.result = last_message["content"]
task.status = "completed"
await task.save()
```
**Вариант 2: Callback Webhook**
```python
# Team Board получает callback от OpenClaw
@app.post("/api/callbacks/openclaw")
async def openclaw_callback(data: dict):
session_key = data.get("sessionKey")
result = data.get("result")
# Находим задачу по session_key
task = await Task.find_by_session(session_key)
task.result = result
task.status = "completed"
await task.save()
```
---
## Текущий статус OpenClaw
```bash
# Gateway endpoint
http://localhost:18789
# Текущий токен
cat ~/.openclaw/openclaw.json | jq '.gateway.auth.token'
# Webhooks пока не настроены — нужно включить
```
### Для активации webhooks:
```json
// ~/.openclaw/openclaw.json
{
"hooks": {
"enabled": true,
"token": "team-board-secret-token",
"path": "/hooks"
}
}
```
---
*Документ обновляется по мере исследования.*