wip: deployment architecture research — Phase 05 ready to plan

- docs/deploy-architecture.md: full deployment topology, agent API, file transfer via shared volume
- .planning/HANDOFF.json + .continue-here.md: session state for Phase 05 planning
This commit is contained in:
Mikhail Putilovskij 2026-04-27 21:46:27 +03:00
parent c34db0e6c0
commit 8ffbe7b6b3
4 changed files with 308 additions and 29 deletions

145
docs/deploy-architecture.md Normal file
View file

@ -0,0 +1,145 @@
# Deployment Architecture — Matrix Bot + Agents
> Сформировано 2026-04-27 по итогам обсуждения с платформой.
---
## Топология
```
lambda.coredump.ru
├── :7000 (reverse proxy, path-based routing)
│ ├── /agent_0/ → agent_0 container
│ ├── /agent_1/ → agent_1 container
│ └── /agent_N/ → agent_N container
└── Matrix bot instance (один инстанс на всех)
└── volume /agents/ (shared с агентами)
├── /agents/0/ ← workspace agent_0
├── /agents/1/ ← workspace agent_1
└── /agents/N/
```
- **Один инстанс Matrix-бота** обслуживает всех пользователей.
- **Один агент-контейнер на пользователя.** Изоляция по agent_id, не через chat_id внутри одного инстанса.
- **Shared volume** `/agents/` смонтирован и в Matrix-бот, и в каждый агент-контейнер. Агент видит свой подкаталог как `/workspace`.
---
## Конфиг (два словаря)
```yaml
# config/matrix-agents.yaml
user_agents:
"@user0:matrix.lambda.coredump.ru": agent-0
"@user1:matrix.lambda.coredump.ru": agent-1
"@user2:matrix.lambda.coredump.ru": agent-2
agents:
- id: agent-0
label: "Agent 0"
base_url: "ws://lambda.coredump.ru:7000/agent_0/"
workspace_path: "/agents/0/"
- id: agent-1
label: "Agent 1"
base_url: "ws://lambda.coredump.ru:7000/agent_1/"
workspace_path: "/agents/1/"
```
- `user_agents` — маппинг Matrix user_id → agent_id (статический, выдаётся платформой)
- `agents` — маппинг agent_id → URL агента и путь к его workspace на shared volume
---
## Agent API (используем master ветку `platform/agent_api`)
```python
from lambda_agent_api.agent_api import AgentApi
connected_agents: dict[str, AgentApi] = {}
def on_agent_disconnect(agent: AgentApi):
del connected_agents[agent.id]
async def on_message(matrix_user_id: str, text: str):
agent_id = get_agent_id_by_user(matrix_user_id) # из user_agents конфига
agent = connected_agents.get(agent_id)
if not agent:
agent = AgentApi(
agent_id,
get_agent_base_url(agent_id), # ws://lambda.coredump.ru:7000/agent_0/
on_disconnect=on_agent_disconnect,
chat_id=0, # default, один чат на агента
)
await agent.connect()
connected_agents[agent_id] = agent
async for event in agent.send_message(text):
...
```
**Параметры конструктора (master):**
```python
AgentApi(
agent_id: str,
base_url: str, # ws://host:port/agent_N/
chat_id: int = 0, # default — один чат на агента
on_disconnect: callable,
)
```
**Lifecycle:** агент автоматически отключается после нескольких минут бездействия.
`on_disconnect` удаляет из пула → следующее сообщение создаёт новое соединение.
---
## Передача файлов
### Пользователь → Агент (входящий файл)
1. Matrix-бот получает файл от пользователя
2. Сохраняет в workspace агента: `/agents/{N}/incoming/{filename}`
3. Вызывает `agent.send_message(text, attachments=["incoming/filename"])`
— путь относительно `/workspace` агента
### Агент → Пользователь (исходящий файл)
1. Агент эмитит `MsgEventSendFile(path="output/report.pdf")`
2. Matrix-бот читает файл: `/agents/{N}/output/report.pdf`
3. Отправляет как Matrix file message пользователю
**Ключевое:** поверхность видит `/agents/` целиком через shared volume. Прямой HTTP-доступ к файлам не нужен.
---
## Текущее состояние platform-agent (main)
- Composio интегрирован в main (`#9-интеграция-composIO`)
- Агент требует в `.env`: `AGENT_ID`, `COMPOSIO_API_KEY`
- Backend: `IsolatedShellBackend` (main) / `CompositeBackend` (ветка `#19`, не merged)
- Memory: `MemorySaver` — история слетает при рестарте контейнера (known limitation)
---
## platform-master (будущее, пока не используем)
Ветка `feat/storage` реализует реальный Master-сервис:
- `POST /api/v1/create {chat_id}` → поднимает/переиспользует sandbox-контейнер
- TTL-based lifecycle (300с default, конфигурируемо)
- `ChatStorage` — API для upload/download файлов через Master
- Auth + p2p lease — вне текущего scope MVP
**Для деплоя MVP используем статический конфиг без Master.**
При готовности Master: `get_agent_url()` будет вызывать `POST /api/v1/create`, URL возвращается в ответе.
---
## Что НЕ решено / открытые вопросы
- Ветка `platform-agent_api #9-clientside-tool-call` убирает `attachments` и `MsgEventSendFile` — пока игнорируем, используем master. Уточнить у Азамата сроки мержа перед деплоем.
- `chat_id` — при нашей модели C1/C2/C3 каждый чат должен иметь отдельный `chat_id`. Нужно решить: один `AgentApi` на агента (chat_id=0) или по инстансу на чат (chat_id=1/2/3). Пока берём `chat_id=0` (один контекст на пользователя).
- Composio `AGENT_ID` в `.env` для каждого агента — уточнить у платформы значения.
- Что происходит с историей при рестарте агента — `MemorySaver` не персистентный.