From 1fdb5bf303d6029ef5d83d9a9c474db12b941546 Mon Sep 17 00:00:00 2001 From: Mikhail Putilovskij Date: Wed, 8 Apr 2026 00:22:20 +0300 Subject: [PATCH] docs: add matrix direct-agent prototype design --- ...08-matrix-direct-agent-prototype-design.md | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-08-matrix-direct-agent-prototype-design.md diff --git a/docs/superpowers/specs/2026-04-08-matrix-direct-agent-prototype-design.md b/docs/superpowers/specs/2026-04-08-matrix-direct-agent-prototype-design.md new file mode 100644 index 0000000..581eb56 --- /dev/null +++ b/docs/superpowers/specs/2026-04-08-matrix-direct-agent-prototype-design.md @@ -0,0 +1,243 @@ +# Matrix Direct-Agent Prototype Design + +## Goal + +Ship a working Matrix prototype that talks to the real Lambda agent instead of `MockPlatformClient`, while preserving the current Matrix adapter logic and keeping the code expandable toward future platform versions. + +## Scope + +This design is for a Matrix-only prototype delivered from this repository on a dedicated branch. It is not a `main` branch rollout and it is not a separate prototype repo. + +The design assumes a minimal companion fork of `platform/agent` may be used, but changes there must stay as small as possible. + +## Constraints + +- Preserve the current Matrix transport logic as much as possible. +- Keep `core/` unaware of platform immaturity. +- Avoid broad changes to platform repos. +- Prefer one narrow patch to `platform/agent` over changes to both `platform/agent` and `platform/agent_api`. +- Keep the backend boundary reusable for future Telegram or other surfaces. +- Do not pretend unsupported platform capabilities are real. + +## Live Platform Findings + +Based on the live repo analysis performed on April 7, 2026: + +- `platform/master` is not yet a usable consumer-facing backend for surfaces. +- `platform/agent` exposes a working WebSocket endpoint for prompt/response exchange. +- `platform/agent_api` documents and implements text-oriented WebSocket messaging, but the bot does not need to depend on that package directly. +- `platform/agent` currently hardcodes a single shared backend memory thread via `thread_id = "default"`, which would cause all chats to share context. + +## Architecture + +The prototype remains in this repo and introduces a new real backend path behind the existing SDK boundary. + +### New files + +- `sdk/real.py` + - Exports `RealPlatformClient` + - Implements the existing `PlatformClient` contract from `sdk/interface.py` + - Composes the lower-level prototype pieces + +- `sdk/agent_session.py` + - Owns direct WebSocket communication with the real agent + - Manages connection lifecycle, request/response handling, and thread identity + +- `sdk/prototype_state.py` + - Owns local prototype-only state + - Stores user mapping, local settings, and lightweight metadata needed until a real control plane exists + +### Responsibility split + +- Matrix adapter remains transport-specific only. +- `core/` continues to depend only on `PlatformClient`. +- `RealPlatformClient` acts as the anti-corruption layer between the current bot contract and the platform’s incomplete shape. +- Local control-plane behavior remains explicit and replaceable later. + +## Message and Identity Model + +Each Matrix chat gets a stable backend session identity. + +### Surface identity + +- Surface: `matrix` +- Surface user id: Matrix MXID, for example `@alice:example.org` +- Surface chat id: logical chat id from `ChatManager`, for example `C1` +- Surface ref: Matrix room id + +### Backend thread identity + +Use a deterministic thread key: + +`matrix:{matrix_user_id}:{chat_id}` + +Example: + +`matrix:@alice:example.org:C1` + +### Mapping rules + +- One Matrix logical chat maps to one backend memory thread. +- `!new` creates a fresh logical chat and therefore a fresh backend thread. +- `!rename` only changes display metadata and does not change backend identity. +- `!archive` stops active use of the thread in the surface, but does not need to delete backend memory in v1. + +## Runtime Flow + +### Normal message flow + +1. Matrix event arrives in an existing room. +2. Existing Matrix routing resolves room to logical `chat_id`. +3. `core/handlers/message.py` calls `platform.send_message(...)`. +4. `RealPlatformClient` derives the backend thread key from `(platform, user_id, chat_id)`. +5. `AgentSessionClient` sends the prompt to the agent WebSocket using that thread key. +6. The reply is converted into the existing `MessageResponse` or `MessageChunk` contract. +7. Matrix sends the final text back to the room. + +### Settings flow + +For v1, settings remain local: + +- `get_settings()` reads from local prototype state +- `update_settings()` writes to local prototype state + +This is intentional. The prototype must not claim settings are backed by the real platform when no such platform API exists yet. + +## Feature Matrix + +### Real in v1 + +- `!start` +- Plain text messaging with the real agent +- Matrix chat lifecycle already implemented in this repo: + - `!new` + - `!chats` + - `!rename` + - `!archive` +- Per-chat conversation memory, provided the agent accepts dynamic thread identity + +### Local in v1 + +- `!settings` +- `!skills` +- `!soul` +- `!safety` +- `!status` +- user registration and local user mapping + +### Deferred + +- Attachments and file upload to the agent +- Voice input to the agent +- Image input to the agent +- Long-running task callbacks and webhook-style async completion +- Real control-plane integration through `platform/master` + +## Minimal Upstream Change + +To avoid shared memory across all conversations, make one narrow change in the forked `platform/agent` repo: + +- stop hardcoding `thread_id = "default"` +- derive thread identity from WebSocket connection context + +### Preferred mechanism + +Read `thread_id` from WebSocket query parameters rather than changing the message payload format. + +Example: + +`ws://host:port/agent_ws/?thread_id=matrix:@alice:example.org:C1` + +This is preferred because: + +- it limits the platform patch to one repo +- it avoids changing both server and SDK protocol shape +- it keeps the client message body text-only +- it makes session identity explicit and easy to reason about + +## Why Not Use `platform/agent_api` Directly + +The bot should not depend on their client package for the prototype. + +Reasons: + +- the bot already has its own internal integration boundary in `sdk/interface.py` +- a tiny local WebSocket client is enough for this protocol +- avoiding a dependency on `platform/agent_api` keeps rebasing simpler +- if upstream stabilizes later, the bot can adopt their SDK without affecting Matrix handlers + +## Repo Strategy + +### This repo + +Owns: + +- Matrix surface logic +- SDK compatibility layer +- local prototype state +- backend selection and wiring + +### Forked `platform/agent` + +Owns only: + +- minimal thread identity patch required for per-chat memory + +### Explicitly not doing + +- no separate prototype repo +- no changes to `platform/master` for v1 +- no unnecessary changes to `platform/agent_api` + +## Migration Path + +This design is intentionally expandable. + +When the platform develops further: + +- `sdk/prototype_state.py` can be replaced or reduced by a real `MasterClient` +- `sdk/agent_session.py` can remain the direct session transport if still relevant +- `RealPlatformClient` can continue to present the stable bot-facing interface +- Telegram or another surface can reuse the same backend components without rethinking the integration model + +## Risks + +### Risk: hidden platform assumptions leak upward + +Mitigation: +- keep all direct-agent logic below `RealPlatformClient` +- avoid changing `core/` contracts for prototype convenience + +### Risk: settings semantics drift from future platform reality + +Mitigation: +- make local settings behavior explicit in code and docs +- keep settings isolated in `sdk/prototype_state.py` + +### Risk: upstream `agent` fork diverges + +Mitigation: +- keep the patch minimal and narrowly scoped to thread identity + +### Risk: thread identity source is unstable + +Mitigation: +- derive thread key from existing stable bot-side identities: platform, surface user id, logical chat id + +## Testing Strategy + +- Unit tests for `sdk/agent_session.py` request/response behavior +- Unit tests for `sdk/prototype_state.py` local settings and user mapping +- Unit tests for `sdk/real.py` contract compliance with `PlatformClient` +- Matrix integration tests confirming: + - existing commands still work + - different logical chats map to different backend thread keys + - rename does not change thread identity + - archive stops reuse from the surface perspective + +## Success Criteria + +- Matrix can talk to the real agent without rewriting the Matrix adapter architecture +- Chats do not share backend memory accidentally +- Unsupported platform capabilities remain local or deferred rather than being faked as “real” +- The backend boundary remains suitable for later Telegram or other surfaces