surfaces/docs/deploy-architecture.md
Mikhail Putilovskij 8ffbe7b6b3 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
2026-04-27 21:46:27 +03:00

145 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` не персистентный.