surfaces/README.md

282 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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) | Внутренний протокол событий (для расширения) |
| [`docs/new-surface-guide.md`](docs/new-surface-guide.md) | Руководство по созданию новой поверхности (Discord, Slack и др.) |