| .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, МАИ