Skip to main content

mdx_rust_core/
registry.rs

1//! Agent registry management
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::path::PathBuf;
6
7/// Represents a registered agent
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct RegisteredAgent {
10    pub name: String,
11    pub path: PathBuf,
12    pub contract: AgentContract,
13    pub registered_at: String, // ISO8601 for simplicity in early phases
14}
15
16/// The kind of agent contract detected
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
18pub enum AgentContract {
19    /// Native Rust function or trait (preferred for Rig agents)
20    NativeRust,
21    /// Separate process speaking JSON over stdin/stdout
22    Process,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, Default)]
26pub struct Registry {
27    pub agents: HashMap<String, RegisteredAgent>,
28}
29
30impl Registry {
31    pub fn new() -> Self {
32        Self::default()
33    }
34
35    /// Load registry from the .mdx-rust directory
36    pub fn load_from(artifact_root: &std::path::Path) -> anyhow::Result<Self> {
37        let registry_path = artifact_root.join("registry.json");
38        if !registry_path.exists() {
39            return Ok(Self::default());
40        }
41        let content = std::fs::read_to_string(registry_path)?;
42        let reg: Registry = serde_json::from_str(&content)?;
43        Ok(reg)
44    }
45
46    /// Save registry to the .mdx-rust directory
47    pub fn save_to(&self, artifact_root: &std::path::Path) -> anyhow::Result<()> {
48        let registry_path = artifact_root.join("registry.json");
49        if let Some(parent) = registry_path.parent() {
50            std::fs::create_dir_all(parent)?;
51        }
52        let content = serde_json::to_string_pretty(self)?;
53        std::fs::write(registry_path, content)?;
54        Ok(())
55    }
56
57    pub fn register(&mut self, agent: RegisteredAgent) {
58        self.agents.insert(agent.name.clone(), agent);
59    }
60
61    pub fn get(&self, name: &str) -> Option<&RegisteredAgent> {
62        self.agents.get(name)
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use tempfile::tempdir;
70
71    #[test]
72    fn test_registry_save_load_roundtrip() {
73        let dir = tempdir().unwrap();
74        let root = dir.path();
75
76        let mut reg = Registry::new();
77        reg.register(RegisteredAgent {
78            name: "test-agent".to_string(),
79            path: PathBuf::from("/tmp/test"),
80            contract: AgentContract::NativeRust,
81            registered_at: "123".to_string(),
82        });
83
84        reg.save_to(root).unwrap();
85        let loaded = Registry::load_from(root).unwrap();
86
87        assert_eq!(loaded.agents.len(), 1);
88        assert_eq!(
89            loaded.get("test-agent").unwrap().contract,
90            AgentContract::NativeRust
91        );
92    }
93}