354 lines
14 KiB
Markdown
354 lines
14 KiB
Markdown
# picogent
|
||
|
||
Минимальный AI-агент с in-process agentic loop на базе Pi Agent Core. Два режима работы: WebSocket-чат и интеграция с Team Board Tracker.
|
||
|
||
## Требования
|
||
|
||
- Node.js 22+
|
||
- npm
|
||
|
||
## Установка
|
||
|
||
```bash
|
||
npm install
|
||
npm run build
|
||
```
|
||
|
||
## Режимы работы
|
||
|
||
Picogent автоматически определяет режим по наличию конфигурации:
|
||
|
||
### 1. WebSocket-режим (чат)
|
||
|
||
Без конфига запускается как WebSocket-сервер для прямого общения через браузерный клиент.
|
||
|
||
```bash
|
||
npm run dev
|
||
# или
|
||
npm start
|
||
```
|
||
|
||
Откройте `client.html` в браузере, подключение к `ws://localhost:3100`.
|
||
|
||
Настройка через переменные окружения (или `.env` файл):
|
||
|
||
| Переменная | Описание | Default |
|
||
|---|---|---|
|
||
| `PICOGENT_PORT` | Порт WebSocket-сервера | `3100` |
|
||
| `PICOGENT_WORK_DIR` | Рабочая директория агента | `cwd` |
|
||
| `PICOGENT_MODEL` | Модель LLM | `sonnet` |
|
||
| `PICOGENT_PROVIDER` | Провайдер LLM | `anthropic` |
|
||
| `PICOGENT_API_KEY` | API ключ | — |
|
||
| `ANTHROPIC_API_KEY` | API ключ (альтернатива) | — |
|
||
|
||
### 2. Agent-режим (Team Board Tracker)
|
||
|
||
Агент регистрируется в трекере, получает задачи и выполняет их. Поддерживает два транспорта:
|
||
|
||
- **`http`** (по умолчанию) — агент поднимает HTTP-сервер, трекер шлёт события через POST. Требует открытый порт (`listen_port`).
|
||
- **`ws`** — агент сам подключается к трекеру по WebSocket. Не требует открытого порта и callback_url. Автоматический reconnect с exponential backoff.
|
||
|
||
Активируется при наличии `agent.json`, директории с конфигом, или переменной `TRACKER_URL`.
|
||
|
||
## Параметры запуска
|
||
|
||
```bash
|
||
# Режим директории — папка с agent.json, skills/, sessions/
|
||
npm run dev -- ./agents/coder/
|
||
|
||
# Режим файла — путь к JSON-конфигу
|
||
npm run dev -- ./my-agent.json
|
||
|
||
# Через переменную окружения
|
||
PICOGENT_CONFIG=./agent.json npm run dev
|
||
|
||
# Только через env (без файла конфига)
|
||
TRACKER_URL=http://localhost:8100 AGENT_TOKEN=tb-xxx npm run dev
|
||
|
||
# Production
|
||
npm start -- ./agents/coder/
|
||
```
|
||
|
||
### Приоритет конфигурации
|
||
|
||
1. CLI аргумент (директория или файл)
|
||
2. Переменная `PICOGENT_CONFIG`
|
||
3. `./agent.json` в текущей директории (если существует)
|
||
4. Env-переменные (`TRACKER_URL` + `AGENT_TOKEN`)
|
||
|
||
Env-переменные всегда имеют приоритет над значениями из JSON-файла.
|
||
|
||
## Конфигурация агента (`agent.json`)
|
||
|
||
Все поля опциональны (кроме `tracker_url` и `token` для agent-режима). Полный пример с описаниями — `agent.example.json`.
|
||
|
||
```json
|
||
{
|
||
"name": "Кодер",
|
||
"slug": "coder",
|
||
"prompt": "Ты опытный Go-разработчик...",
|
||
"tracker_url": "http://localhost:8100",
|
||
"token": "tb-agent-abc123",
|
||
"transport": "http",
|
||
"listen_port": 3200,
|
||
"work_dir": "/projects/my-app",
|
||
"model": "sonnet",
|
||
"provider": "anthropic",
|
||
"capabilities": ["coding", "review"],
|
||
"max_concurrent_tasks": 2,
|
||
"heartbeat_interval_sec": 30,
|
||
"allowed_paths": []
|
||
}
|
||
```
|
||
|
||
| Поле | Env | Default | Описание |
|
||
|---|---|---|---|
|
||
| `name` | `AGENT_NAME` | `Agent` | Имя агента в трекере |
|
||
| `slug` | `AGENT_SLUG` | `agent` | Уникальный ID (латиница) |
|
||
| `prompt` | `AGENT_PROMPT` | — | Системный промпт — роль агента |
|
||
| `tracker_url` | `TRACKER_URL` | — | URL Team Board Tracker (**обязательно**) |
|
||
| `token` | `AGENT_TOKEN` | — | Bearer-токен для Tracker API (**обязательно**) |
|
||
| `transport` | `AGENT_TRANSPORT` | `http` | Транспорт: `http` или `ws` |
|
||
| `listen_port` | `AGENT_PORT` | `3200` | Порт HTTP (только transport=http) |
|
||
| `work_dir` | `PICOGENT_WORK_DIR` | `agentHome` / `cwd` | Рабочая директория |
|
||
| `model` | `PICOGENT_MODEL` | `sonnet` | Модель LLM |
|
||
| `provider` | `PICOGENT_PROVIDER` | `anthropic` | Провайдер LLM |
|
||
| `api_key` | `PICOGENT_API_KEY` / `ANTHROPIC_API_KEY` | — | API ключ провайдера |
|
||
| `capabilities` | — | `["coding"]` | Возможности для трекера |
|
||
| `max_concurrent_tasks` | — | `2` | Макс. параллельных задач |
|
||
| `heartbeat_interval_sec` | — | `30` | Интервал heartbeat (сек.) |
|
||
| `allowed_paths` | — | `[]` (без ограничений) | Ограничение доступа к FS |
|
||
|
||
### Алиасы моделей
|
||
|
||
| Алиас | Полный ID |
|
||
|---|---|
|
||
| `sonnet` | `claude-sonnet-4-6` |
|
||
| `opus` | `claude-opus-4-6` |
|
||
| `haiku` | `claude-haiku-4-5` |
|
||
| `sonnet-4` | `claude-sonnet-4-6` |
|
||
| `opus-4` | `claude-opus-4-6` |
|
||
| `sonnet-3.5` | `claude-3-5-sonnet-20241022` |
|
||
|
||
## Режим директории (рекомендуется)
|
||
|
||
Самый удобный способ — создать папку со всем необходимым:
|
||
|
||
```
|
||
agents/coder/
|
||
agent.json # конфиг
|
||
skills/ # скилы агента
|
||
review/
|
||
SKILL.md
|
||
sessions/ # сессии (создаётся автоматически)
|
||
```
|
||
|
||
Запуск:
|
||
|
||
```bash
|
||
npm run dev -- ./agents/coder/
|
||
```
|
||
|
||
В этом режиме:
|
||
- `agentHome` = путь к директории
|
||
- `workDir` = то же (если не переопределён через `work_dir` или env)
|
||
- Скилы загружаются из `agentHome/skills/`
|
||
- Сессии сохраняются в `agentHome/sessions/`
|
||
|
||
## Скилы (Skills)
|
||
|
||
Агент поддерживает скилы — специализированные инструкции в формате `SKILL.md`.
|
||
|
||
### Структура скила
|
||
|
||
```
|
||
skills/
|
||
review/
|
||
SKILL.md
|
||
refactor/
|
||
SKILL.md
|
||
```
|
||
|
||
### Формат `SKILL.md`
|
||
|
||
```markdown
|
||
---
|
||
name: review
|
||
description: "Code review — анализ кода на ошибки, стиль, производительность"
|
||
---
|
||
|
||
# Code Review
|
||
|
||
Инструкции для агента...
|
||
```
|
||
|
||
### Как работает
|
||
|
||
Используется **progressive loading** (как в Claude Code):
|
||
1. В системный промпт попадают только XML-сводки скилов (имя + описание + путь)
|
||
2. Агент читает полный `SKILL.md` через инструмент `Read` только когда скил нужен
|
||
3. Контекст не засоряется лишним текстом
|
||
|
||
Скилы загружаются из двух мест:
|
||
- `agentHome/skills/` (или `workDir/skills/`) — скилы конкретного агента
|
||
- `~/.picogent/skills/` — глобальные скилы
|
||
|
||
## Ограничение доступа к файлам (`allowed_paths`)
|
||
|
||
По умолчанию агент может читать и писать файлы без ограничений. Для ограничения укажите список разрешённых директорий:
|
||
|
||
```json
|
||
{
|
||
"allowed_paths": [
|
||
"/projects/my-app/src",
|
||
"/projects/my-app/tests"
|
||
]
|
||
}
|
||
```
|
||
|
||
Что защищено:
|
||
- **Read** — проверка пути перед чтением
|
||
- **Write** — проверка перед записью и созданием директорий
|
||
- **Edit** — проверка перед чтением и записью
|
||
- **Bash** — проверка, что рабочая директория команды внутри allowed_paths
|
||
|
||
Что **не** защищено:
|
||
- **Grep/Find/Ls** — read-only инструменты, не ограничиваются
|
||
- **Bash-команды** — содержимое команд не парсится (агент может выполнить `cat /etc/passwd`). Для полной изоляции bash используйте контейнеры
|
||
|
||
## `.env` файл
|
||
|
||
API ключи и секреты удобно хранить в `.env` файле в корне проекта:
|
||
|
||
```env
|
||
ANTHROPIC_API_KEY=sk-ant-...
|
||
TRACKER_URL=http://localhost:8100
|
||
AGENT_TOKEN=tb-agent-abc123
|
||
```
|
||
|
||
Node 22 загружает `.env` автоматически через флаг `--env-file=.env` (прописан в `package.json`).
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
src/
|
||
index.ts # Точка входа, dual-mode wiring
|
||
config.ts # Загрузка конфигурации (JSON + env)
|
||
agent.ts # Pi Agent Core — agentic loop, skills, sessions
|
||
sandbox.ts # Sandboxed tools с проверкой путей
|
||
router.ts # Роутер событий трекера -> agent
|
||
logger.ts # Pino logger
|
||
transport/
|
||
websocket.ts # WebSocket-сервер (чат-режим)
|
||
http.ts # HTTP-сервер (agent-режим, transport=http)
|
||
ws-client.ts # WebSocket-клиент к трекеру (agent-режим, transport=ws)
|
||
types.ts # Общие типы транспорта
|
||
tracker/
|
||
client.ts # HTTP-клиент к Tracker API
|
||
registration.ts # Регистрация + heartbeat
|
||
types.ts # Типы Tracker API
|
||
```
|
||
|
||
### Поток данных
|
||
|
||
**WebSocket-режим:**
|
||
```
|
||
Browser (client.html) -> WebSocket -> index.ts -> runAgent() -> Pi Agent Core -> WebSocket -> Browser
|
||
```
|
||
|
||
**Agent-режим (transport=http):**
|
||
```
|
||
Tracker -> HTTP POST /events -> HttpTransport -> EventRouter -> runAgent() -> Pi Agent Core -> TrackerClient -> Tracker
|
||
```
|
||
|
||
**Agent-режим (transport=ws):**
|
||
```
|
||
Agent -> WebSocket -> Tracker (auth + heartbeat + events) -> WsClientTransport -> EventRouter -> runAgent() -> TrackerClient -> Tracker
|
||
```
|
||
|
||
### Ядро (`agent.ts`)
|
||
|
||
Использует Pi Agent Core (`@mariozechner/pi-coding-agent`) для in-process agentic loop:
|
||
- Модели через `ModelRegistry` с `models.json` в `~/.picogent/`
|
||
- API ключи через `AuthStorage` с runtime injection (`initAgent()`)
|
||
- Инструменты: Read, Write, Edit, Bash, Grep, Find, Ls (через `createSandboxedTools`)
|
||
- Сессии: JSONL-файлы через `SessionManager`
|
||
- Скилы: `loadSkills()` + `formatSkillsForPrompt()` для progressive loading
|
||
|
||
### Tracker интеграция
|
||
|
||
- **HTTP-транспорт** (по умолчанию): POST `/api/v1/agents/register` с callback_url, POST `/api/v1/agents/heartbeat`, события через HTTP POST
|
||
- **WS-транспорт**: агент подключается к `/ws?client_type=agent`, регистрация и heartbeat через WebSocket, события приходят через тот же канал
|
||
- **Задачи**: трекер отправляет `task.assigned` event -> агент выполняет -> результат как комментарий + статус `review`
|
||
- **Чат**: трекер отправляет `chat.message` -> агент отвечает -> комментарий к задаче
|
||
- **Устойчивость**: HTTP — retry регистрации каждые 5с. WS — reconnect с exponential backoff (1с → 30с)
|
||
|
||
## WebSocket-протокол
|
||
|
||
### Клиент -> Сервер
|
||
|
||
```json
|
||
{
|
||
"id": "msg-1",
|
||
"content": "Какие файлы есть в текущей директории?",
|
||
"sessionId": "my-session",
|
||
"workDir": "/projects/my-app",
|
||
"systemPrompt": "Ты помощник-разработчик"
|
||
}
|
||
```
|
||
|
||
| Поле | Обязательно | Описание |
|
||
|---|---|---|
|
||
| `id` | да | Уникальный ID сообщения |
|
||
| `content` | да | Текст промпта |
|
||
| `sessionId` | нет | Имя сессии (для сохранения контекста между сообщениями) |
|
||
| `workDir` | нет | Рабочая директория для этого запроса |
|
||
| `systemPrompt` | нет | Дополнительный системный промпт |
|
||
|
||
### Сервер -> Клиент (стрим)
|
||
|
||
```json
|
||
{
|
||
"id": "msg-1",
|
||
"type": "text",
|
||
"content": "В директории находятся...",
|
||
"sessionId": "abc-123"
|
||
}
|
||
```
|
||
|
||
Типы сообщений:
|
||
- **`text`** — фрагмент текстового ответа (стримится по мере генерации)
|
||
- **`tool_use`** — агент вызвал инструмент (формат: `ToolName: описание`)
|
||
- **`tool_result`** — результат инструмента с ошибкой
|
||
- **`error`** — ошибка агента или API
|
||
- **`done`** — запрос завершён
|
||
|
||
## Команды
|
||
|
||
```bash
|
||
npm install # Установка зависимостей
|
||
npm run build # Компиляция TypeScript
|
||
npm run dev # Dev-режим (tsx, .env)
|
||
npm start # Запуск из dist/ (.env)
|
||
npm test # Тесты (vitest)
|
||
```
|
||
|
||
## Файлы данных
|
||
|
||
| Путь | Описание |
|
||
|---|---|
|
||
| `~/.picogent/` | Домашняя директория picogent |
|
||
| `~/.picogent/models.json` | Конфигурация моделей (создаётся автоматически) |
|
||
| `~/.picogent/auth.json` | Хранилище API ключей |
|
||
| `~/.picogent/sessions/` | Сессии по умолчанию |
|
||
| `~/.picogent/skills/` | Глобальные скилы |
|
||
|
||
## Происхождение
|
||
|
||
Проект извлечён из двух соседних проектов:
|
||
|
||
- **OpenClaw** (`openclaw/`) — паттерн in-process agent loop через Pi Agent Core (`createAgentSession`, `AuthStorage`, `ModelRegistry`, `codingTools`, event subscription)
|
||
- **NanoClaw** (`nanoclaw/`) — паттерн pino-логгера, структура "получи сообщение -> запусти агента -> отправь результат"
|
||
|
||
Сознательно выброшено: каналы, контейнеры, плагины, auth profiles, MCP, subagents и прочая сложность. Picogent — это голый agent loop + транспорт.
|