Users can now list available agents with !agent and select one by number. Selection persists in user metadata (selected_agent_id). If the current room has no agent binding yet, selecting an agent binds it immediately so the user can start messaging without !new. Also updates the dispatcher test to reflect that real-mode platform is now RoutedPlatformClient, not a bare RealPlatformClient. |
||
|---|---|---|
| .planning | ||
| adapter | ||
| bot-examples | ||
| config | ||
| core | ||
| docs | ||
| sdk | ||
| tests | ||
| .dockerignore | ||
| .DS_Store | ||
| .env.example | ||
| .gitignore | ||
| conftest.py | ||
| docker-compose.yml | ||
| Dockerfile | ||
| forum_topics_research.md | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
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
Функционал прототипа
Telegram (подробнее)
- Чаты — основной Telegram UX сейчас развивается в отдельном worktree
feat/telegram-adapter - Forum Topics mode — бот умеет подключать forum-группу через
/forum; чат может быть привязан к отдельной теме - DM-режим — базовый диалог и переключение чатов сохраняются
- Аутентификация — привязка Telegram аккаунта к аккаунту платформы
- Диалог — typing indicator, передача файлов, подтверждение опасных действий через inline-кнопки
- Настройки через
/settings: коннекторы (Gmail, GitHub, Notion...), скиллы, личность агента (SOUL), безопасность, подписка
Matrix (подробнее)
- Онбординг — при первом 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 и upstreamAgentApiпо contract/v1/agent_ws/{chat_id}/ - Ограничения real backend — локальный runtime использует shared
/workspace, файлы передаются как относительные пути вattachments, а transport layer со стороныsurfacesиспользует прямой upstreamplatform-agent_api.AgentApiбез локального subclass; prod-default lifecycle открывает отдельное соединение на каждый запрос, но после tool/file flow всё ещё остаётся подтверждённый upstream streaming bug, из-за которого начало ответа может пропадать
Замена SDK
Вся работа с платформой идёт через PlatformClient Protocol:
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. Зависимости и тесты
uv sync
pytest tests/ -v
2. Переменные окружения
cp .env.example .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_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. Registry агентов
- Скопируй
config/matrix-agents.example.yamlвconfig/matrix-agents.yaml - Если готовишься к multi-agent routing, добавь
MATRIX_AGENT_REGISTRY_PATH=config/matrix-agents.yamlв.env - Этот registry сейчас является конфигурационным артефактом Task 1; текущий Matrix runtime его ещё не читает
4. Compose runtime
Root docker-compose.yml теперь является основным локальным runtime для Matrix и platform-agent.
Он поднимает matrix-bot, platform-agent и общий volume /workspace.
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:5e7c2df954cc3cd2f5bf8ae688e10a20038dde61platform-agent_api:8a4f4db6d36786fe8af7feefffe506d4a54ac6bd
4. Staged attachments в Matrix
Если Matrix-клиент отправляет файлы отдельными media events, бот не вызывает агента сразу.
Вместо этого он сохраняет файлы в shared /workspace, ставит их в очередь для конкретного чата и пользователя, и ждёт следующего обычного сообщения.
Как отправить файлы агенту:
- Отправь один или несколько файлов в рабочую Matrix-комнату.
- При необходимости проверь очередь командой
!list. - Напиши обычное текстовое сообщение, например:
что на изображении?прочитай pdf и сделай summaryсравни эти два файла
- Это сообщение уйдёт агенту вместе со всеми staged файлами из очереди.
Команды:
!list— показать staged вложения!remove <n>— удалить вложение по номеру!remove all— очистить все staged вложения
Следующее обычное сообщение пользователя уходит агенту вместе со всеми staged файлами.
Пример:
[отправил 2 изображения]
!list
1. IMG_3183.png
2. minion.jpeg
что изображено на фото
В этом сценарии вопрос что изображено на фото будет отправлен агенту вместе с обоими файлами.
Важно:
- если после файлов отправить
!listили!remove, агент не вызывается - если платформа вернула ошибку на этих вложениях, они остаются в staged-очереди
- в таком случае следующее обычное сообщение снова попытается отправить те же файлы
- чтобы разорвать этот цикл, используй
!remove <n>или!remove all
Известное ограничение текущего platform-agent:
- большие изображения могут не пройти в provider из-за лимита на размер data URI
- в таком случае Matrix-бот ответит
Сервис временно недоступен..., а проблемные файлы останутся в очереди до явного удаления
5. Запуск бота вручную
# Первый запуск или сброс состояния
rm -f lambda_matrix.db && rm -rf matrix_store
PYTHONPATH=. uv run python -m adapter.matrix.bot
6. Онбординг пользователя
Напиши боту в личные сообщения (DM) на Matrix-сервере. Для поддерживаемого dev-сценария используй незашифрованную комнату: E2EE сейчас не считается поддержанным режимом для Matrix-поверхности.
Бот автоматически:
- Создаст private Space
Lambda — {твоё имя} - Создаст рабочую комнату
Чат 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 с общим хранилищем. |
| Стриминг после tool/file flow | В текущем upstream platform-agent первый MsgEventTextChunk иногда рождается уже обрезанным до попадания в websocket-клиент. Наш transport layer после cleanup максимально близок к upstream и больше не пытается локально “лечить” этот поток. Подробности и raw evidence: docs/reports/2026-04-22-platform-streaming-final-bug-report-ru.md. |
Счётчик токенов в !context |
pinned platform-agent_api.AgentApi потребляет MsgEventEnd внутри клиента и не публикует tokens_used наружу. Сейчас surfaces честно показывает 0, пока upstream не добавит поддержанный способ получить это значение. |
!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/telegram-prototype.md |
Функционал Telegram прототипа |
docs/matrix-prototype.md |
Функционал Matrix прототипа |
docs/api-contract.md |
Контракт к SDK платформы |
docs/user-flow.md |
FSM и user journey |
docs/claude-code-guide.md |
Гайд по работе с Claude Code |
docs/reports/2026-04-22-platform-streaming-final-bug-report-ru.md |
Финальный аудит platform streaming bug после cleanup transport layer |
Команда
Поверхности и интеграции Lambda Lab 3.0, МАИ