docs: add matrix direct-agent prototype design
This commit is contained in:
parent
b08a5e3d96
commit
1fdb5bf303
1 changed files with 243 additions and 0 deletions
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue