281 lines
14 KiB
Markdown
281 lines
14 KiB
Markdown
# Lambda Lab 3.0 — Surfaces
|
||
|
||
Matrix-бот для взаимодействия пользователя с AI-агентом Lambda.
|
||
|
||
## Интеграция для платформы
|
||
|
||
Бот — это один Docker-контейнер (`matrix-bot`), который вы добавляете в свою инфраструктуру рядом с агентами. Production target — один surface container на 25-30 внешних agent containers/services.
|
||
|
||
### Что бот ожидает от вас
|
||
|
||
**1. HTTP-эндпоинт агента**
|
||
Бот подключается к агенту через `lambda_agent_api.AgentApi` по адресу `AGENT_BASE_URL`.
|
||
Протокол — WebSocket поверх HTTP, контракт описан в `docs/deploy-architecture.md`.
|
||
|
||
**2. Shared volume с per-agent поддиректориями**
|
||
Shared volume монтируется в бот как `/agents`. Каждый агент видит свою поддиректорию.
|
||
|
||
```
|
||
Bot container Agent containers
|
||
/agents/0/ ←── volume ──→ agent_0: /workspace/
|
||
/agents/1/ ←── volume ──→ agent_1: /workspace/
|
||
/agents/N/ ←── volume ──→ agent_N: /workspace/
|
||
```
|
||
|
||
- Бот сохраняет входящий файл прямо в `{workspace_path}/{file}` и передаёт агенту `attachments=["{file}"]`
|
||
- Если файл с таким именем уже есть, бот сохраняет следующий как `file (1).ext`, `file (2).ext`, как в Windows
|
||
- Агент пишет исходящий файл прямо в свой `/workspace/file`, бот читает его из `{workspace_path}/file`
|
||
- `workspace_path` для каждого агента задаётся в `config/matrix-agents.yaml`
|
||
|
||
**3. Конфиг агентов**
|
||
Файл `config/matrix-agents.yaml` — маппинг Matrix-пользователей на агентов. Вы заполняете его под свою инфраструктуру. Пример в `config/matrix-agents.example.yaml`.
|
||
|
||
### Что бот не делает
|
||
|
||
- Не управляет lifecycle агент-контейнеров (запуск/остановка — на вашей стороне)
|
||
- Не хранит историю разговоров (это в памяти агента)
|
||
- Не обрабатывает аутентификацию пользователей — любой Matrix-пользователь, который пишет боту, получает доступ
|
||
|
||
### Минимальный чеклист
|
||
|
||
- [ ] Взять опубликованный image `SURFACES_BOT_IMAGE` или собрать production image из этого репозитория
|
||
- [ ] Заполнить `config/matrix-agents.yaml` — ID агентов, `base_url` каждого, `workspace_path`, маппинг пользователей
|
||
- [ ] Задать переменные окружения (см. `.env.example`): Matrix credentials, `MATRIX_PLATFORM_BACKEND=real`, `MATRIX_AGENT_REGISTRY_PATH=/app/config/matrix-agents.yaml`
|
||
- [ ] Смонтировать в бот-контейнер shared volume как `/agents` — каждый агент должен видеть свою поддиректорию как `/workspace`
|
||
- [ ] Добавить bot-only service в свой compose; агенты в этот compose не входят и управляются платформой
|
||
|
||
---
|
||
|
||
## Статус
|
||
|
||
Matrix MVP готов к деплою. Telegram — в отдельном worktree, не входит в этот handoff.
|
||
|
||
---
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
surfaces-bot/
|
||
core/ — общее ядро, не зависит от транспорта
|
||
protocol.py — унифицированные структуры (IncomingMessage, OutgoingUI, ...)
|
||
handler.py — EventDispatcher: IncomingEvent → OutgoingEvent
|
||
store.py — StateStore Protocol + InMemoryStore + SQLiteStore
|
||
chat.py — ChatManager
|
||
auth.py — AuthManager
|
||
settings.py — SettingsManager
|
||
|
||
adapter/
|
||
matrix/ — matrix-nio адаптер
|
||
|
||
sdk/
|
||
interface.py — PlatformClient Protocol (контракт к SDK)
|
||
real.py — RealPlatformClient (через AgentApi)
|
||
mock.py — MockPlatformClient (заглушка для тестов)
|
||
|
||
config/
|
||
matrix-agents.yaml — реестр агентов
|
||
|
||
docs/ — документация
|
||
```
|
||
|
||
Подробнее: [`docs/surface-protocol.md`](docs/surface-protocol.md)
|
||
|
||
---
|
||
|
||
## Деплой
|
||
|
||
### Переменные окружения
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
| Переменная | Обязательна | Описание |
|
||
|---|---|---|
|
||
| `MATRIX_HOMESERVER` | ✓ | URL Matrix-сервера |
|
||
| `MATRIX_USER_ID` | ✓ | `@bot:example.org` |
|
||
| `MATRIX_PASSWORD` | ✓ | пароль (или `MATRIX_ACCESS_TOKEN`) |
|
||
| `MATRIX_PLATFORM_BACKEND` | ✓ | `real` для продакшна |
|
||
| `SURFACES_BOT_IMAGE` | ✓ | Docker image поверхности: `mput1/surfaces-bot:latest` |
|
||
| `AGENT_BASE_URL` | | Fallback URL агента если `base_url` не задан в `matrix-agents.yaml` |
|
||
| `MATRIX_AGENT_REGISTRY_PATH` | ✓ | путь к реестру внутри контейнера: `/app/config/matrix-agents.yaml` |
|
||
| `SURFACES_WORKSPACE_DIR` | | путь к shared volume в контейнере (по умолчанию `/agents`) |
|
||
| `SURFACES_SHARED_VOLUME` | | имя Docker volume (по умолчанию `surfaces-agents`) |
|
||
|
||
### Реестр агентов
|
||
|
||
`config/matrix-agents.yaml` — статический маппинг пользователей на агентов:
|
||
|
||
```yaml
|
||
user_agents:
|
||
"@user0:matrix.lambda.coredump.ru": agent-0
|
||
"@user1:matrix.lambda.coredump.ru": agent-1
|
||
|
||
agents:
|
||
- id: agent-0
|
||
label: "Agent 0"
|
||
base_url: "http://lambda.coredump.ru:7000/agent_0/"
|
||
workspace_path: "/agents/0"
|
||
- id: agent-1
|
||
label: "Agent 1"
|
||
base_url: "http://lambda.coredump.ru:7000/agent_1/"
|
||
workspace_path: "/agents/1"
|
||
- id: agent-2
|
||
label: "Agent 2"
|
||
base_url: "http://lambda.coredump.ru:7000/agent_2/"
|
||
workspace_path: "/agents/2"
|
||
```
|
||
|
||
- `user_agents` — маппинг Matrix user_id → agent_id. Если пользователь не найден — используется первый агент.
|
||
- `base_url` — HTTP URL агент-эндпоинта (path-based routing через reverse proxy).
|
||
- `workspace_path` — путь к воркспейсу агента внутри бот-контейнера на shared volume.
|
||
Бот сохраняет входящие файлы прямо в `{workspace_path}/`, агент пишет исходящие прямо в свой `/workspace/`.
|
||
- Для 25-30 агентов продолжайте тот же паттерн: `/agent_17/` + `/agents/17`, `/agent_29/` + `/agents/29`.
|
||
|
||
Полный пример с комментариями: `config/matrix-agents.example.yaml`
|
||
|
||
### Production (bot-only)
|
||
|
||
`docker-compose.prod.yml` — bot-only handoff через published image. Платформа добавляет этот сервис в свой compose рядом с agent containers, монтирует shared volume и задаёт переменные окружения. Этот compose не создаёт и не собирает агент-контейнеры.
|
||
|
||
Перед redeploy можно проверить реальные agent routes из той же сети, где будет работать бот:
|
||
```bash
|
||
PYTHONPATH=. uv run python -m tools.check_matrix_agents \
|
||
--config config/matrix-agents.yaml \
|
||
--timeout 5
|
||
```
|
||
|
||
Проверка открывает фактический WebSocket URL каждого агента (`.../v1/agent_ws/{chat_id}/`) и ждёт первый `STATUS`. Для проверки полного запроса к агенту добавьте `--message "ping"`.
|
||
|
||
Для запуска опубликованного image:
|
||
```bash
|
||
export SURFACES_BOT_IMAGE=mput1/surfaces-bot:latest
|
||
docker compose --env-file .env -f docker-compose.prod.yml up -d
|
||
```
|
||
|
||
Опубликованный image:
|
||
|
||
```text
|
||
mput1/surfaces-bot:latest
|
||
sha256:2f135f3535f7765d4377b440cdabe41195ad2efbc3e175def159ae4689ef90bd
|
||
```
|
||
|
||
Для сборки и публикации surface image:
|
||
```bash
|
||
docker login
|
||
export SURFACES_BOT_IMAGE=mput1/surfaces-bot:latest
|
||
|
||
docker build --target production \
|
||
--build-arg LAMBDA_AGENT_API_REF=master \
|
||
-t "$SURFACES_BOT_IMAGE" .
|
||
docker push "$SURFACES_BOT_IMAGE"
|
||
```
|
||
|
||
Если push возвращает `insufficient_scope`, текущий Docker login не имеет доступа к namespace/repository. Создайте repository в нужном Docker Hub namespace или перетегируйте image в namespace пользователя, под которым выполнен `docker login`.
|
||
|
||
### Fullstack E2E (bot + agent)
|
||
|
||
```bash
|
||
docker compose --env-file .env -f docker-compose.fullstack.yml up --build
|
||
```
|
||
|
||
Поднимает `matrix-bot` вместе с локальным `platform-agent`. Это internal harness, не production topology на 25-30 агентов. `matrix-bot` собирается через Dockerfile target `development` и локальный `external/platform-agent_api` context, как в dev-сборке `platform-agent`. `AGENT_BASE_URL` перекрывается на `http://platform-agent:8000`. Shared volume виден как `/agents` в боте и `/workspace` в агенте.
|
||
|
||
### Сброс состояния (локально)
|
||
|
||
```bash
|
||
rm -f lambda_matrix.db && rm -rf matrix_store
|
||
```
|
||
|
||
---
|
||
|
||
## Shared volume: передача файлов
|
||
|
||
```
|
||
Bot (/agents) Agent (/workspace = /agents/N/)
|
||
/agents/0/report.pdf ←──── одно и то же хранилище ────→ /workspace/report.pdf
|
||
/agents/0/result.txt ←────────────────────────────────→ /workspace/result.txt
|
||
```
|
||
|
||
- **Входящий файл** (пользователь → агент): бот сохраняет в `{workspace_path}/{file}`, например `/agents/17/report.pdf`, и передаёт агенту `attachments=["report.pdf"]`
|
||
- **Коллизии имён**: если `/agents/17/report.pdf` уже существует, бот сохранит следующий файл как `/agents/17/report (1).pdf`, затем `/agents/17/report (2).pdf`
|
||
- **Исходящий файл** (агент → пользователь): агент пишет в `/workspace/file`, бот читает из `{workspace_path}/file`, например `/agents/17/result.txt`, и отправляет пользователю как Matrix file message
|
||
- `workspace_path` для каждого агента задаётся в `config/matrix-agents.yaml`
|
||
|
||
---
|
||
|
||
## Онбординг пользователя
|
||
|
||
1. Пользователь приглашает бота в личные сообщения (DM) на Matrix-сервере
|
||
2. Бот создаёт private Space `Lambda — {display_name}` и комнату `Чат 1`
|
||
3. Дальнейшее общение — в рабочих комнатах, не в DM
|
||
|
||
**Требование:** незашифрованные комнаты. E2EE не поддержан.
|
||
|
||
---
|
||
|
||
## Команды Matrix
|
||
|
||
### Работающие
|
||
|
||
| Команда | Действие |
|
||
|---|---|
|
||
| *(любое сообщение)* | Диалог с агентом, стриминг ответа |
|
||
| `!new [название]` | Создать новый чат |
|
||
| `!chats` | Список активных чатов |
|
||
| `!rename <название>` | Переименовать текущую комнату |
|
||
| `!archive` | Архивировать чат |
|
||
| `!clear` | Сбросить контекст текущего чата |
|
||
| `!yes` / `!no` | Подтвердить / отменить действие агента |
|
||
| `!list` | Файлы в очереди вложений |
|
||
| `!remove <n>` / `!remove all` | Удалить вложение из очереди |
|
||
| `!help` | Справка |
|
||
|
||
### Не работают / заглушки
|
||
|
||
| Команда | Статус |
|
||
|---|---|
|
||
| `!save` / `!load` / `!context` | Нестабильны: зависят от агента, сессии теряются при рестарте |
|
||
| `!settings` и подкоманды | Заглушки MVP, требуют готового SDK платформы |
|
||
|
||
---
|
||
|
||
## Отправка файлов агенту
|
||
|
||
Matrix-клиент отправляет файлы и текст отдельными событиями. Файл без текстовой инструкции ставится в очередь.
|
||
|
||
```
|
||
[отправил файл]
|
||
!list
|
||
1. report.pdf
|
||
|
||
прочитай и сделай summary ← файл уйдёт агенту вместе с этим текстом
|
||
```
|
||
|
||
---
|
||
|
||
## Известные ограничения
|
||
|
||
| Проблема | Причина |
|
||
|---|---|
|
||
| История теряется при рестарте агента | `platform-agent` использует `MemorySaver` (in-memory) |
|
||
| E2EE | `python-olm` не собирается на macOS/ARM |
|
||
|
||
---
|
||
|
||
## Разработка
|
||
|
||
```bash
|
||
uv sync
|
||
pytest tests/ -v
|
||
pytest tests/adapter/matrix/ -v # только Matrix
|
||
```
|
||
|
||
## Документация
|
||
|
||
| Файл | Содержание |
|
||
|---|---|
|
||
| [`docs/deploy-architecture.md`](docs/deploy-architecture.md) | **Читать первым.** Топология деплоя, volume-контракт, AgentApi, конфигурация |
|
||
| [`docs/matrix-prototype.md`](docs/matrix-prototype.md) | Команды бота, UX, передача файлов |
|
||
| [`docs/known-limitations.md`](docs/known-limitations.md) | Известные ограничения и обходные пути |
|
||
| [`docs/surface-protocol.md`](docs/surface-protocol.md) | Внутренний протокол событий (для расширения) |
|