feat: multi-agent architecture with Conversations API and persistent state

Mistral Agents + Conversations API integration:
- Orchestrator agent created on startup with Sol's personality + tools
- ConversationRegistry routes messages through persistent conversations
- Per-room conversation state (room_id → conversation_id + token counts)
- Function call handling within conversation responses
- Configurable via [agents] section in sol.toml (use_conversations_api flag)

Multimodal support:
- m.image detection and Matrix media download (mxc:// → base64 data URI)
- ContentPart-based messages sent to Mistral vision models
- Archive stores media_urls for image messages

System prompt rewrite:
- 687 → 150 lines — dense, few-shot examples, hard rules
- {room_context_rules} placeholder for group vs DM behavior
- Sender prefixing (<@user:server>) for multi-user turns in group rooms

SQLite persistence (/data/sol.db):
- Conversation mappings and agent IDs survive reboots
- WAL mode for concurrent reads
- Falls back to in-memory on failure (sneezes into all rooms to signal)
- PVC already mounted at /data alongside Matrix SDK state store

New modules:
- src/persistence.rs — SQLite state store
- src/conversations.rs — ConversationRegistry + message merging
- src/agents/{mod,definitions,registry}.rs — agent lifecycle
- src/agent_ux.rs — reaction + thread progress UX
- src/tools/bridge.rs — tool dispatch for domain agents

102 tests passing.
This commit is contained in:
2026-03-21 22:21:14 +00:00
parent 5e2186f324
commit 7580c10dda
20 changed files with 1723 additions and 655 deletions

View File

@@ -13,7 +13,7 @@ name = "sol"
path = "src/main.rs"
[dependencies]
mistralai-client = { version = "1.0.0", registry = "sunbeam" }
mistralai-client = { version = "1.1.0", registry = "sunbeam" }
matrix-sdk = { version = "0.9", features = ["e2e-encryption", "sqlite"] }
opensearch = "2"
tokio = { version = "1", features = ["full"] }
@@ -35,3 +35,5 @@ deno_error = "0.7"
tempfile = "3"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
uuid = { version = "1", features = ["v4"] }
base64 = "0.22"
rusqlite = { version = "0.32", features = ["bundled"] }