surfaces/docs/new-surface-guide.md

16 KiB
Raw Blame History

Руководство по созданию новой поверхности

Этот документ описывает, как написать новую новую поверхность (например, Discord, Slack или Custom Web) по образцу текущей Matrix-поверхности в ветке main.

Он основан на актуальной реализации Matrix surface в репозитории и отражает текущую продакшн-логику, а не устаревший легаси.


1. Общая архитектура

1.1. Что такое поверхность

Поверхность — это тонкий адаптер между конкретной платформой (Платформа) и общим ядром бота.

В репозитории есть разделение:

  • core/ — общее ядро и бизнес-логика
  • adapter/<platform>/ — реализация конкретной поверхности
  • sdk/real.py — работа с реальной платформой / агентом
  • config/ — статическая конфигурация агентов
  • docs/surface-protocol.md — общий контракт поверхностей

1.2. Как это работает

Поверхность должна:

  • принимать нативные события от Платформа
  • преобразовывать их в единый внутренний контракт (IncomingMessage, IncomingCommand, IncomingCallback)
  • передавать их в core
  • получать ответы из core (OutgoingMessage, OutgoingUI, OutgoingTyping, OutgoingNotification)
  • преобразовывать ответы обратно в нативные нативные сообщения

Поверхность не должна:

  • управлять жизненным циклом агентских контейнеров
  • хранить долгую историю бесед вне core/платформы
  • аутентифицировать пользователей сама (если это не часть Платформа API)

2. Структура новой поверхности

2.1. Основные каталоги

Рекомендуемая структура для новой платформы:

adapter/<platform>/
  bot.py
  converter.py
  agent_registry.py
  files.py
  handlers/
  store.py

2.2. Принцип reuse

По примеру Matrix surface, New surface должен переиспользовать общий core и общий sdk.

Не дублируйте бизнес-логику, а реализуйте только адаптер:

  • adapter/<platform>/converter.py — конвертация событий платформы ⇄ внутренние структуры
  • adapter/<platform>/bot.py — основной runtime, старт Платформа client, loop, отправка/прием
  • adapter/<platform>/agent_registry.py — загрузка config/<platform>-agents.yaml
  • adapter/<platform>/files.py — хранение входящих/исходящих вложений

3. Контракт входящих/исходящих событий

3.1. Внутренний формат

Смотрите core/protocol.py. Основные типы:

  • IncomingMessage — обычное текстовое сообщение + вложения
  • IncomingCommand — управляющая команда
  • IncomingCallback — подтверждение / интерактивные действия
  • OutgoingMessage — ответ пользователю
  • OutgoingUI — интерфейсные элементы (кнопки и т.п.)
  • OutgoingTyping — индикатор печати
  • OutgoingNotification — системное уведомление

3.2. Пример конверсии Matrix

В Matrix-реализации adapter/matrix/converter.py:

  • текст !yes / !no превращается в IncomingCallback с action: confirm/cancel
  • !list/!remove говорят не агенту, а surface-процессу
  • вложения m.file, m.image, m.audio, m.video нормализуются в Attachment

Для Платформа реализуйте аналогичную логику для native команд вашего клиента.


4. Реестр агентов и маршрутизация

4.1. Что хранит реестр

В текущей Matrix реализации есть config/matrix-agents.yaml и adapter/matrix/agent_registry.py.

Структура:

user_agents:
  "@user0:matrix.example.org": agent-0
  "@user1:matrix.example.org": agent-1

agents:
  - id: agent-0
    label: "Agent 0"
    base_url: "http://lambda.coredump.ru:7000/agent_0/"
    workspace_path: "/agents/0"

4.2. Логика выбора агента

  • user_agents маппит конкретного пользователя на agent_id
  • если user_id не найден, используется первый агент из списка
  • agents[].base_url определяет URL агента
  • agents[].workspace_path определяет путь внутри surface-контейнера для этого агента

Это важно: именно на этом контракте строится разделение агентов по рабочим каталогам.

4.3. Рекомендуемая Версия для новой платформы

Создайте config/<platform>-agents.yaml с тем же смыслом.

  • user_agents — маппинг external user_id → agent_id
  • agents — список агентов
  • workspace_path для каждого агента должен быть абсолютным путем внутри surface-контейнера, например /agents/0

5. Файловый контракт

5.1. Shared volume

Текущее Matrix-решение использует shared volume:

  • surface монтирует общий том как /agents
  • каждый агент видит свою поддиректорию как /workspace

Топология:

Bot (/agents)              Agent (/workspace = /agents/N/)
  /agents/0/report.pdf  ←──→  /workspace/report.pdf

5.2. Правила записи файлов

В adapter/matrix/files.py реализовано:

  • входящий файл сохраняется прямо в {workspace_root}/{filename}
  • возвращается путь workspace_path относительный внутри рабочего каталога агента
  • при коллизии имен создаётся file (1).ext, file (2).ext
  • Attachment.workspace_path передаётся агенту

Для исходящих файлов:

  • surface читает файл из workspace_root / workspace_path
  • загружает его в платформу

5.3. Пример поведения

  • Пользователь отправляет файл → surface скачивает файл и кладёт его в agent workspace
  • Агент получает attachments=["report.pdf"] и работает с относительным workspace_path
  • Агент пишет результат в /workspace/result.txt
  • surface читает /agents/{N}/result.txt и отправляет файл пользователю

6. Чат-менеджмент и контекст

6.1. platform_chat_id

Matrix-реализация использует platform_chat_id как стабильный идентификатор чата на стороне агента.

  • room_meta.platform_chat_id определяется и сохраняется в adapter/matrix/store.py
  • reconcile_startup_state() восстанавливает отсутствующие platform_chat_id при рестарте
  • RoutedPlatformClient перенаправляет запросы агенту по agent_id + platform_chat_id

Для New surface тот же принцип:

  • каждая внешняя беседа должна привязываться к одному внутреннему chat_id
  • этот chat_id используется для вызовов агента
  • если в Платформа есть несколько комнат/топиков, каждая должна иметь свой surface_ref

6.2. Команды управления чатами

Matrix поддерживает следующие команды, которые нужно сохранить в Платформа:

  • !new [название] — создать новый чат
  • !chats — список активных чатов
  • !rename <название> — переименовать текущий чат
  • !archive — архивировать чат
  • !clear / !reset — сбросить контекст текущего чата
  • !yes / !no — подтвердить или отменить действие агента
  • !list — показать очередь вложений
  • !remove <n> / !remove all — удалить вложение из очереди
  • !help — справка

Эти команды реализованы в Matrix через adapter/matrix/handlers/.

6.3. Очередь вложений

Matrix surface поддерживает staged attachments:

  • файл может быть отправлен без текста
  • surface сохраняет файл в staged_attachments для конкретного room_id + user_id
  • следующий текст отправляется агенту вместе со всеми файлами из очереди

В Платформа можно реализовать ту же модель:

  • !list показывает текущую очередь
  • !remove удаляет файл из очереди
  • команда-индикатор или следующее текстовое сообщение отправляет queued attachments агенту

7. Runtime и окружение

7.1. Переменные среды

Для Matrix surface текущий runtime ожидает:

  • MATRIX_HOMESERVER — URL Matrix-сервера
  • MATRIX_USER_ID@bot:example.org
  • MATRIX_PASSWORD или MATRIX_ACCESS_TOKEN
  • MATRIX_PLATFORM_BACKEND — должно быть real для продакшна
  • MATRIX_AGENT_REGISTRY_PATH — путь к config/matrix-agents.yaml
  • AGENT_BASE_URL — fallback URL агента
  • SURFACES_WORKSPACE_DIR — путь к shared volume внутри контейнера (по умолчанию /workspace в коде, но в docs рекомендуют /agents)

Для New surface используйте аналогичные переменные:

  • PLATFORM_PLATFORM_BACKEND=real
  • PLATFORM_AGENT_REGISTRY_PATH=/app/config/<platform>-agents.yaml
  • SURFACES_WORKSPACE_DIR=/agents
  • AGENT_BASE_URL — если хотите общий fallback

7.2. Environment contract

В коде adapter/matrix/bot.py:

  • _agent_base_url_from_env() читает AGENT_BASE_URL или AGENT_WS_URL
  • _load_agent_registry_from_env() читает MATRIX_AGENT_REGISTRY_PATH
  • _build_platform_from_env() выбирает RealPlatformClient при MATRIX_PLATFORM_BACKEND=real

В New surface реализуйте ту же логику, заменив префиксы на PLATFORM_.


8. Тестирование и валидация

8.1. Юнит-тесты

В ветке есть покрытие для Matrix surface:

  • tests/adapter/matrix/test_files.py
  • tests/adapter/matrix/test_dispatcher.py
  • tests/adapter/matrix/test_routed_platform.py
  • tests/adapter/matrix/test_reconciliation.py
  • tests/adapter/matrix/test_context_commands.py

Для Платформа создайте аналогичные тесты:

  • проверка загрузки вложений
  • проверка маршрутизации по agent_id
  • проверка восстановления platform_chat_id
  • проверка конвертации команд

8.2. Smoke-проверка deployment

Для Matrix surface есть docker-compose.prod.yml и docker-compose.fullstack.yml.

Для New surface должно быть достаточно:

  • bot-only production deployment
  • shared volume /agents
  • независимая проверка config/<platform>-agents.yaml
  • проверка, что surface запускается без локального агента

8.3. Проверка контрактов

Особое внимание:

  • agent_registry должен загружать workspace_path
  • file flow должен поддерживать workspace_path в Attachment
  • отправка файлов должна использовать resolve_workspace_attachment_path()
  • platform_chat_id должен существовать до вызова агента

9. Реализация шаг за шагом

  1. Скопировать adapter/matrix/ как шаблон для adapter/<platform>/.
  2. Сделать adapter/<platform>/converter.py:
    • превратить native нативные сообщения в IncomingMessage
    • превратить команды в IncomingCommand
    • превратить yes/no-подтверждения в IncomingCallback
  3. Сделать adapter/<platform>/agent_registry.py на основе adapter/matrix/agent_registry.py.
  4. Сделать adapter/<platform>/files.py на основе adapter/matrix/files.py.
  5. Сделать adapter/<platform>/bot.py:
    • инстанцировать runtime
    • читать env vars PLATFORM_*
    • загружать реестр агентов
    • обрабатывать входящие события
    • отправлять Outgoing* обратно в Платформа
  6. Реализовать команды управления чатами и очередь вложений.
  7. Прописать config/<platform>-agents.yaml.
  8. Прописать docker-compose.platform.yml или аналог, чтобы surface монтировал /agents.
  9. Написать тесты по аналогии с tests/adapter/matrix/.
  10. Проверить, что все env vars читаются из окружения и не зависят от устаревших Matrix-переменных.

10. Важные замечания

  • Текущий Matrix surface на ветке main — активная реализация, а не устаревший легаси.
  • Документация и код согласованы: agent_registry, files, routed_platform, reconciliation работают вместе.
  • Обязательно явно задавайте SURFACES_WORKSPACE_DIR=/agents в production, если workspace_path в реестре указывает на /agents/*.
  • Для New surface сохраните ту же архитектуру: surface = thin adapter, агенты = внешние сервисы.
  • Не пытайтесь в surface реализовывать логику запуска/стопа агент-контейнеров.

11. Полезные ссылки внутри репозитория

  • README.md
  • docs/deploy-architecture.md
  • docs/surface-protocol.md
  • adapter/matrix/bot.py
  • adapter/matrix/converter.py
  • adapter/matrix/agent_registry.py
  • adapter/matrix/files.py
  • adapter/matrix/routed_platform.py
  • adapter/matrix/reconciliation.py
  • tests/adapter/matrix/