- Agent Registry schema - OpenClaw Webhooks API documentation - Team Board → OpenClaw architecture - Python client example - Task execution flow
21 KiB
Team Board — Research: Agent Integration
Исследование возможностей подключения AI-агентов к Team Board.
Текущие возможности OpenClaw
1. sessions_spawn — спавн изолированных субагентов
Task → Spawn → Isolated Session → Result → Announce back
Параметры:
task(required) — задача для агентаlabel— метка для логовagentId— ID агента (если разрешён в allowlist)model— переопределение моделиrunTimeoutSeconds— таймаутcleanup—delete|keep
Поведение:
- Создаёт новую сессию
agent:<agentId>:subagent:<uuid> - Субагенты имеют полный набор инструментов минус session tools
- Не блокирует: возвращает
{ status: "accepted", runId, childSessionKey } - После завершения — announce в исходный чат
2. sessions_send — отправка между сессиями
Agent A → sessions_send → Agent B → Response
Параметры:
sessionKey(required)message(required)timeoutSeconds— 0 = fire-and-forget
Поведение:
- Поддерживает ping-pong между агентами (до 5 итераций)
- Контекст сохраняется
- Провenance маркируется как
inter_session
3. sessions_list / sessions_history
- Список активных сессий
- История сообщений сессии
- Фильтры по типу, времени, каналу
4. Multi-Agent Routing
Несколько агентов в одном gateway:
agents:
list:
- id: main
workspace: ~/.openclaw/workspace
- id: coder
workspace: ~/projects/coder-workspace
- id: reviewer
workspace: ~/projects/reviewer-workspace
Каждый агент имеет:
- Свой workspace (файлы, AGENTS.md, SOUL.md)
- Свой state directory
- Своё хранилище сессий
- Свои auth profiles
5. ACP (Agent Client Protocol)
Стандартный протокол для подключения внешних агентов.
External Agent ↔ ACP ↔ OpenClaw Gateway
Реализация в OpenClaw:
src/acp/server.ts— ACP серверsrc/acp/client.ts— ACP клиент- Использует
@agentclientprotocol/sdk
Dangerous tools требуют approval:
- exec, spawn, shell
- sessions_spawn, sessions_send
- gateway
- fs_write, fs_delete, fs_move
Варианты интеграции для Team Board
Вариант 1: OpenClaw Multi-Agent (рекомендуется)
Team Board API
↓
OpenClaw Gateway
↓
┌─────────────────────────────────┐
│ Agent: main (Lead) │
│ Agent: coder (Developer) │
│ Agent: reviewer (QA) │
│ Agent: analyst (Research) │
└─────────────────────────────────┘
Плюсы:
- Готовая инфраструктура
- Сохранение контекста через сессии
- Единый API
- Безопасность (sandbox, permissions)
- Инструменты (exec, browser, files)
Реализация:
- Добавить агентов в
openclaw.json - Team Board вызывает
sessions_spawn/sessions_sendчерез Gateway API - Результаты через webhook или polling
Конфиг:
{
"agents": {
"list": [
{
"id": "main",
"workspace": "~/.openclaw/workspace"
},
{
"id": "coder",
"workspace": "~/workspaces/coder",
"model": "anthropic/claude-sonnet-4-20250514"
}
],
"defaults": {
"subagents": {
"allowAgents": ["main", "coder", "reviewer"]
}
}
}
}
Вариант 2: ACP Bridge для CLI агентов
Для подключения Claude Code CLI без траты API токенов.
Claude Code CLI (Max subscription)
↓
ACP Client Wrapper
↓
OpenClaw Gateway
↓
Team Board
Компоненты:
- PTY Session Manager
import pexpect
class CliSession:
def __init__(self, command="claude"):
self.child = pexpect.spawn(command)
def send(self, message: str) -> str:
self.child.sendline(message)
self.child.expect(r'\n>') # wait for prompt
return self.child.before.decode()
- ACP Translator
class AcpCliBridge:
def handle_request(self, request):
response = self.cli_session.send(request.message)
return AcpResponse(content=response)
Сложности:
- CLI интерактивный, не headless
- Нужно парсить вывод
- Контекст внутри CLI сессии
Вариант 3: Direct API + Context Store
Прямые вызовы API с хранением контекста в БД.
Team Board
↓
Agent Service
↓
┌──────────────────────────────────┐
│ Claude API │ Codex │ Gemini │
└──────────────────────────────────┘
↓
Context Store (PostgreSQL)
Схема контекста:
CREATE TABLE agent_contexts (
id UUID PRIMARY KEY,
agent_id UUID REFERENCES agents(id),
session_id UUID REFERENCES sessions(id),
messages JSONB, -- история сообщений
metadata JSONB, -- system prompt, tools, etc.
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ
);
При каждом запросе:
- Загрузить контекст из БД
- Добавить новое сообщение
- Вызвать API с полным контекстом
- Сохранить ответ в БД
Web Terminal Interface
Архитектура
Browser (xterm.js)
↓ WebSocket
Team Board Frontend
↓ WebSocket
Team Board Backend (Session Manager)
↓ PTY / API
Agent (OpenClaw / CLI / API)
Компоненты
Frontend:
- xterm.js — терминальный эмулятор
- WebSocket клиент
- Session selector UI
Backend:
- WebSocket сервер
- Session Manager
- PTY spawner (для CLI агентов)
- OpenClaw Gateway client (для OpenClaw агентов)
Пример кода (Backend)
from fastapi import WebSocket
import asyncio
class AgentSessionManager:
def __init__(self):
self.sessions = {}
async def create_session(self, agent_type: str, config: dict):
if agent_type == "openclaw":
return OpenClawSession(config)
elif agent_type == "cli":
return CliSession(config)
elif agent_type == "api":
return ApiSession(config)
async def handle_websocket(self, ws: WebSocket, session_id: str):
session = self.sessions[session_id]
async for message in ws.iter_text():
response = await session.send(message)
await ws.send_text(response)
Сравнение вариантов
| Критерий | OpenClaw Multi-Agent | ACP CLI Bridge | Direct API |
|---|---|---|---|
| Сложность | Низкая | Высокая | Средняя |
| Контекст | ✓ Автоматический | ✓ В CLI | Ручной |
| Инструменты | ✓ Полный набор | ✓ CLI tools | ✗ Нет |
| API токены | Нужны | Не нужны (Max) | Нужны |
| Готовность | Сейчас | Требует разработки | Требует разработки |
Рекомендуемый план
Фаза 1: OpenClaw Multi-Agent (быстрый старт)
- Добавить агентов в конфиг OpenClaw
- Team Board API вызывает Gateway
- Использовать
sessions_spawnдля задач - Использовать
sessions_sendдля коммуникации
Результат: Рабочая система с несколькими агентами
Фаза 2: Web Terminal UI
- xterm.js на фронте
- WebSocket сервер
- Прямое взаимодействие с агентами
Результат: Terminal-like опыт в браузере
Фаза 3: ACP CLI Bridge (опционально)
- PTY wrapper для Claude Code CLI
- ACP транслятор
- Интеграция с Gateway
Результат: CLI агенты без API токенов
Открытые вопросы
-
Headless mode в Claude Code CLI?
- Нужно проверить
claude --help - Возможно есть
--messageили--non-interactive
- Нужно проверить
-
Как шарить файлы между агентами?
- Общий workspace?
- Git как source of truth?
- Копирование через API?
-
Rate limiting для API агентов?
- Очередь задач
- Приоритеты
- Backoff при ошибках
-
Мониторинг агентов?
- Статус (idle/working/error)
- Использование токенов
- Время выполнения
Agent Management System
Agent Registry (БД)
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
Конфигурация
{
"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 — Разбудить основную сессию
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 — Запустить изолированную сессию
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)
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
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
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
# 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
# Gateway endpoint
http://localhost:18789
# Текущий токен
cat ~/.openclaw/openclaw.json | jq '.gateway.auth.token'
# Webhooks пока не настроены — нужно включить
Для активации webhooks:
// ~/.openclaw/openclaw.json
{
"hooks": {
"enabled": true,
"token": "team-board-secret-token",
"path": "/hooks"
}
}
Документ обновляется по мере исследования.