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:
@@ -6,6 +6,35 @@ pub struct Config {
|
||||
pub opensearch: OpenSearchConfig,
|
||||
pub mistral: MistralConfig,
|
||||
pub behavior: BehaviorConfig,
|
||||
#[serde(default)]
|
||||
pub agents: AgentsConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct AgentsConfig {
|
||||
/// Model for the orchestrator agent.
|
||||
#[serde(default = "default_model")]
|
||||
pub orchestrator_model: String,
|
||||
/// Model for domain agents.
|
||||
#[serde(default = "default_model")]
|
||||
pub domain_model: String,
|
||||
/// Token threshold for conversation compaction (~90% of model context window).
|
||||
#[serde(default = "default_compaction_threshold")]
|
||||
pub compaction_threshold: u32,
|
||||
/// Whether to use the Conversations API (vs manual message management).
|
||||
#[serde(default)]
|
||||
pub use_conversations_api: bool,
|
||||
}
|
||||
|
||||
impl Default for AgentsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
orchestrator_model: default_model(),
|
||||
domain_model: default_model(),
|
||||
compaction_threshold: default_compaction_threshold(),
|
||||
use_conversations_api: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -13,6 +42,10 @@ pub struct MatrixConfig {
|
||||
pub homeserver_url: String,
|
||||
pub user_id: String,
|
||||
pub state_store_path: String,
|
||||
/// Path to the SQLite database for persistent state (conversations, agents).
|
||||
/// Should be on a persistent volume in K8s (e.g. Longhorn PVC mounted at /data).
|
||||
#[serde(default = "default_db_path")]
|
||||
pub db_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -112,6 +145,8 @@ fn default_script_timeout_secs() -> u64 { 5 }
|
||||
fn default_script_max_heap_mb() -> usize { 64 }
|
||||
fn default_memory_index() -> String { "sol_user_memory".into() }
|
||||
fn default_memory_extraction_enabled() -> bool { true }
|
||||
fn default_db_path() -> String { "/data/sol.db".into() }
|
||||
fn default_compaction_threshold() -> u32 { 118000 } // ~90% of 131K context window
|
||||
|
||||
impl Config {
|
||||
pub fn load(path: &str) -> anyhow::Result<Self> {
|
||||
|
||||
Reference in New Issue
Block a user