Skip to main content

mdx_rust_core/
registry.rs

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