surfaces/README.md

243 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
Команда поверхностей. Telegram и Matrix боты для взаимодействия пользователя с AI-агентом Lambda.
## Статус
| Поверхность | Статус |
|---|---|
| Telegram | 🔨 В разработке, отдельный worktree `feat/telegram-adapter` |
| Matrix | ✅ Рабочий прототип, запускается через root `docker compose` вместе с `platform-agent` |
---
## Концепция
Пользователь получает персонального AI-агента через привычный мессенджер.
Агент выполняет реальные задачи: разбирает почту, ищет информацию, работает с файлами, управляет календарём.
**Поверхности** — тонкие клиенты. Вся бизнес-логика на стороне платформы.
Задача команды: сделать интерфейс удобным, надёжным и легко расширяемым.
---
## Архитектура
```
surfaces-bot/
core/ — общее ядро, не зависит от транспорта
protocol.py — унифицированные структуры (IncomingMessage, OutgoingUI, ...)
handler.py — EventDispatcher: IncomingEvent → OutgoingEvent
handlers/ — обработчики по типам событий
store.py — StateStore Protocol + InMemoryStore + SQLiteStore
chat.py — ChatManager: метаданные чатов C1/C2/C3
auth.py — AuthManager: аутентификация
settings.py — SettingsManager: коннекторы, скиллы, SOUL, безопасность
adapter/
telegram/ — aiogram 3.x адаптер
matrix/ — matrix-nio адаптер
sdk/
interface.py — PlatformClient Protocol (контракт к SDK)
mock.py — MockPlatformClient (заглушка)
docs/ — документация
.claude/agents/ — агенты для Claude Code
```
**Ключевой принцип:** добавить новую поверхность = написать один адаптер-конвертер.
Ядро (`core/`) не трогается. Подробнее: [`docs/surface-protocol.md`](docs/surface-protocol.md)
---
## Функционал прототипа
### Telegram ([подробнее](docs/telegram-prototype.md))
- **Чаты** — основной Telegram UX сейчас развивается в отдельном worktree `feat/telegram-adapter`
- **Forum Topics mode** — бот умеет подключать forum-группу через `/forum`; чат может быть привязан к отдельной теме
- **DM-режим** — базовый диалог и переключение чатов сохраняются
- **Аутентификация** — привязка Telegram аккаунта к аккаунту платформы
- **Диалог** — typing indicator, передача файлов, подтверждение опасных действий через inline-кнопки
- **Настройки** через `/settings`: коннекторы (Gmail, GitHub, Notion...), скиллы, личность агента (SOUL), безопасность, подписка
### Matrix ([подробнее](docs/matrix-prototype.md))
- **Онбординг** — при первом invite бот создаёт private Space `Lambda — {display_name}` и первую комнату `Чат 1`, сразу приглашая туда пользователя
- **Чаты** — `!new`, `!chats`, `!rename`, `!archive`, `!help`; новые комнаты регистрируются в локальном `ChatManager`
- **Диалог** — сообщения, вложения, подтверждения `!yes` / `!no` и routing через `EventDispatcher`
- **Стабильность** — перед `sync_forever()` бот делает bootstrap sync и стартует с `since`, чтобы не переигрывать старую timeline после рестарта
- **Текущее ограничение** — encrypted DM официально не поддержан; ручное тестирование Matrix ведётся в незашифрованных комнатах и зависит от локального state-store бота
- **Backend selection** — `MATRIX_PLATFORM_BACKEND=mock` остаётся значением по умолчанию; `MATRIX_PLATFORM_BACKEND=real` использует `platform-agent` из compose и WebSocket contract `/v1/agent_ws/{chat_id}/`
- **Ограничения real backend** — локальный runtime использует shared `/workspace`, а файлы передаются как относительные пути в `attachments`
---
## Замена SDK
Вся работа с платформой идёт через `PlatformClient` Protocol:
```python
class PlatformClient(Protocol):
async def get_or_create_user(self, external_id: str, platform: str, ...) -> User: ...
async def send_message(self, user_id: str, chat_id: str, text: str, ...) -> MessageResponse: ...
async def get_settings(self, user_id: str) -> UserSettings: ...
async def update_settings(self, user_id: str, action: Any) -> None: ...
```
Бот не управляет lifecycle контейнеров — это делает Master (платформа).
Бот передаёт `user_id` + `chat_id` + сообщение; платформа сама решает нужно ли поднять контейнер.
Сейчас: `MockPlatformClient` в `sdk/mock.py`, а Matrix real backend собирается через `sdk/real.py` при `MATRIX_PLATFORM_BACKEND=real`.
Файловый контракт уже path-based: бот пишет файлы в shared `/workspace` и передаёт платформе относительные пути в `attachments`.
Когда SDK готов: добавляем `SdkPlatformClient`, меняем одну строку в DI. Адаптеры и ядро не трогаем.
---
## Запуск Matrix-поверхности
### 1. Зависимости и тесты
```bash
uv sync
pytest tests/ -v
```
### 2. Переменные окружения
```bash
cp .env.example .env
```
Обязательные переменные:
```env
# Matrix аккаунт бота
MATRIX_HOMESERVER=https://matrix.example.org
MATRIX_USER_ID=@lambda-bot:example.org
MATRIX_PASSWORD=... # или MATRIX_ACCESS_TOKEN=...
# Выбор backend: mock (по умолчанию) или real (подключение к platform-agent)
MATRIX_PLATFORM_BACKEND=real
# compose runtime: platform-agent service name + shared /workspace
AGENT_WS_URL=ws://platform-agent:8000/v1/agent_ws/
AGENT_BASE_URL=http://platform-agent:8000
SURFACES_WORKSPACE_DIR=/workspace
# platform-agent provider
PROVIDER_MODEL=openai/gpt-4o-mini
PROVIDER_URL=https://openrouter.ai/api/v1
PROVIDER_API_KEY=...
```
### 3. Compose runtime
Root `docker-compose.yml` теперь является основным локальным runtime для Matrix и platform-agent.
Он поднимает `matrix-bot`, `platform-agent` и общий volume `/workspace`.
```bash
docker compose up --build
```
Compose собирает `platform-agent` из актуального upstream `external/platform-agent` Dockerfile (`development` target),
монтирует live-код из `external/platform-agent/src` и `external/platform-agent_api`, и подготавливает shared `/workspace`
с правами для agent runtime.
Matrix бот подключается к `platform-agent` по service name, а не к отдельно запущенному `localhost`.
На `2026-04-21` локальный compose runtime использует vendored upstream-версии платформы без локальных патчей:
- `platform-agent`: `5e7c2df954cc3cd2f5bf8ae688e10a20038dde61`
- `platform-agent_api`: `aa480bbec5bbf8e006284dd03aed1c2754e9bbee`
### 4. Staged attachments в Matrix
Если Matrix-клиент отправляет файлы отдельными media events, бот не вызывает агента сразу.
Вместо этого он сохраняет файлы в shared `/workspace`, ставит их в очередь для конкретного чата и пользователя, и ждёт следующего обычного сообщения.
Команды:
- `!list` — показать staged вложения
- `!remove <n>` — удалить вложение по номеру
- `!remove all` — очистить все staged вложения
Следующее обычное сообщение пользователя уходит агенту вместе со всеми staged файлами.
### 5. Запуск бота вручную
```bash
# Первый запуск или сброс состояния
rm -f lambda_matrix.db && rm -rf matrix_store
PYTHONPATH=. uv run python -m adapter.matrix.bot
```
### 6. Онбординг пользователя
Напиши боту в **личные сообщения (DM)** на Matrix-сервере. Для поддерживаемого dev-сценария используй незашифрованную комнату: E2EE сейчас не считается поддержанным режимом для Matrix-поверхности.
Бот автоматически:
1. Создаст private Space `Lambda — {твоё имя}`
2. Создаст рабочую комнату `Чат 1` и пригласит туда
Дальнейшее общение ведётся в рабочей комнате, не в DM.
---
## Функционал Matrix MVP
### Работает
| Функция | Команда | Примечание |
|---|---|---|
| Онбординг | *(автоматически при invite)* | Создаёт Space + рабочую комнату |
| Новый чат | `!new` | Создаёт дополнительную комнату |
| Список чатов | `!chats` | Активные чаты пользователя |
| Переименование | `!rename <название>` | |
| Архивация | `!archive` | |
| Диалог с агентом | *(любое сообщение)* | Стриминг ответа через WebSocket |
| Изоляция контекста | *(автоматически)* | Каждая комната получает отдельный `platform_chat_id` |
| Сохранение контекста | `!save [имя]` | Агент сохраняет краткое резюме разговора |
| Список сохранений | `!load` | Выбор по номеру |
| Состояние контекста | `!context` | Текущая сессия и список сохранений |
| Справка | `!help` | |
| Подтверждения | `!yes` / `!no` | Для опасных действий |
| Staged вложения | `!list`, `!remove <n>`, `!remove all` | Файлы без текстовой инструкции ставятся в очередь до следующего сообщения |
### Не работает — блокеры на стороне platform-agent
| Функция | Почему не работает |
|---|---|
| `!load` в другом чате | platform-agent использует `StateBackend` — файлы живут в памяти отдельно для каждого `thread_id`. Файл, сохранённый в чате A, не виден в чате B. Фикс: переключить platform-agent на `FilesystemBackend` с общим хранилищем. |
| Счётчик токенов в `!context` | platform-agent отдаёт `tokens_used=0` хардкодом в `MsgEventEnd`. Наш код перехватывает значение корректно. |
| `!reset` | platform-agent не имеет endpoint `/reset`. Задокументировано в ТЗ к платформе. |
| Персистентность между рестартами | platform-agent использует `MemorySaver` (in-memory). Все разговоры теряются при рестарте процесса. |
| E2EE комнаты | `python-olm` не собирается на macOS/ARM. Ограничение инфраструктуры. |
### Не работает — пока не реализовано нами
| Функция | Статус |
|---|---|
| `!settings`, `!skills`, `!soul`, `!safety` | Заглушки MVP. Требуют готового SDK платформы. |
| Вложения без текстовой инструкции | Поддержан staged UX только для Matrix. Для других поверхностей ещё не перенесено. |
---
## Документация
| Файл | Содержание |
|---|---|
| [`docs/surface-protocol.md`](docs/surface-protocol.md) | Унификация поверхностей — все структуры, как добавить новую поверхность |
| [`docs/telegram-prototype.md`](docs/telegram-prototype.md) | Функционал Telegram прототипа |
| [`docs/matrix-prototype.md`](docs/matrix-prototype.md) | Функционал Matrix прототипа |
| [`docs/api-contract.md`](docs/api-contract.md) | Контракт к SDK платформы |
| [`docs/user-flow.md`](docs/user-flow.md) | FSM и user journey |
| [`docs/claude-code-guide.md`](docs/claude-code-guide.md) | Гайд по работе с Claude Code |
---
## Команда
Поверхности и интеграции
Lambda Lab 3.0, МАИ