feat: commit staged matrix attachments on next message

This commit is contained in:
Mikhail Putilovskij 2026-04-20 21:39:37 +03:00
parent f111ed3348
commit 323a6d3144
3 changed files with 155 additions and 23 deletions

View file

@ -7,7 +7,7 @@
| Поверхность | Статус |
|---|---|
| Telegram | 🔨 В разработке, отдельный worktree `feat/telegram-adapter` |
| Matrix | ✅ Рабочий прототип, подключается к реальному агенту |
| Matrix | ✅ Рабочий прототип, запускается через root `docker compose` вместе с `platform-agent` |
---
@ -69,8 +69,8 @@ surfaces-bot/
- **Диалог** — сообщения, вложения, подтверждения `!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` требует `AGENT_WS_URL=ws://host:port/agent_ws/`
- **Ограничения real backend**пока это текстовый direct-agent прототип без вложений и без асинхронных callbacks; локальные настройки и user-state хранятся в `PrototypeStateStore`
- **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`
---
@ -90,6 +90,7 @@ class PlatformClient(Protocol):
Бот передаёт `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. Адаптеры и ядро не трогаем.
---
@ -120,32 +121,38 @@ MATRIX_PASSWORD=... # или MATRIX_ACCESS_TOKEN=...
# Выбор backend: mock (по умолчанию) или real (подключение к platform-agent)
MATRIX_PLATFORM_BACKEND=real
# URL WebSocket endpoint platform-agent (только при MATRIX_PLATFORM_BACKEND=real)
AGENT_WS_URL=ws://127.0.0.1:8000/agent_ws/
AGENT_BASE_URL=http://127.0.0.1:8000
# 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
```
### 3. Запуск platform-agent (для real backend)
### 3. Compose runtime
platform-agent — отдельный репозиторий, сейчас клонируется в `external/platform-agent`.
Root `docker-compose.yml` теперь является основным локальным runtime для Matrix и platform-agent.
Он поднимает `matrix-bot`, `platform-agent` и общий volume `/workspace`.
```bash
cd external/platform-agent
# Создать .env с параметрами LLM провайдера
cat > .env <<EOF
PROVIDER_MODEL=openai/gpt-4o-mini
PROVIDER_URL=https://openrouter.ai/api/v1
PROVIDER_API_KEY=sk-or-...
EOF
# Запустить
uv run uvicorn src.main:app --host 127.0.0.1 --port 8000
docker compose up --build
```
Проверить что работает: `curl http://127.0.0.1:8000/agent_ws/` должен вернуть ответ об апгрейде до WebSocket.
Compose использует локальные директории `external/platform-agent` и `external/platform-agent_api` как источник кода для агента.
Matrix бот подключается к `platform-agent` по service name, а не к отдельно запущенному `localhost`.
### 4. Запуск бота
### 4.1. Staged attachments в Matrix
Если Matrix-клиент отправляет файлы отдельными media events, бот не вызывает агента сразу.
Вместо этого он сохраняет файлы в shared `/workspace`, ставит их в очередь для конкретного чата и пользователя, и ждёт следующего обычного сообщения.
Команды:
- `!list` — показать staged вложения
- `!remove <n>` — удалить вложение по номеру
- `!remove all` — очистить все staged вложения
Следующее обычное сообщение пользователя уходит агенту вместе со всеми staged файлами.
### 4. Запуск бота вручную
```bash
# Первый запуск или сброс состояния
@ -184,6 +191,7 @@ PYTHONPATH=. uv run python -m adapter.matrix.bot
| Состояние контекста | `!context` | Текущая сессия и список сохранений |
| Справка | `!help` | |
| Подтверждения | `!yes` / `!no` | Для опасных действий |
| Staged вложения | `!list`, `!remove <n>`, `!remove all` | Файлы без текстовой инструкции ставятся в очередь до следующего сообщения |
### Не работает — блокеры на стороне platform-agent
@ -192,7 +200,6 @@ PYTHONPATH=. uv run python -m adapter.matrix.bot
| `!load` в другом чате | platform-agent использует `StateBackend` — файлы живут в памяти отдельно для каждого `thread_id`. Файл, сохранённый в чате A, не виден в чате B. Фикс: переключить platform-agent на `FilesystemBackend` с общим хранилищем. |
| Счётчик токенов в `!context` | platform-agent отдаёт `tokens_used=0` хардкодом в `MsgEventEnd`. Наш код перехватывает значение корректно. |
| `!reset` | platform-agent не имеет endpoint `/reset`. Задокументировано в ТЗ к платформе. |
| Файловые вложения | Нет API загрузки файлов в область видимости агента. ТЗ передано платформе. |
| Персистентность между рестартами | platform-agent использует `MemorySaver` (in-memory). Все разговоры теряются при рестарте процесса. |
| E2EE комнаты | `python-olm` не собирается на macOS/ARM. Ограничение инфраструктуры. |
@ -201,7 +208,7 @@ PYTHONPATH=. uv run python -m adapter.matrix.bot
| Функция | Статус |
|---|---|
| `!settings`, `!skills`, `!soul`, `!safety` | Заглушки MVP. Требуют готового SDK платформы. |
| Вложения (изображения, документы) | Только текстовые сообщения в текущем MVP. |
| Вложения без текстовой инструкции | Поддержан staged UX только для Matrix. Для других поверхностей ещё не перенесено. |
---