Skip to main content

portalis_specgen/
lib.rs

1//! Specification Generator Agent
2//!
3//! Generates Rust type specifications from Python analysis.
4
5use async_trait::async_trait;
6use portalis_core::{Agent, AgentCapability, AgentId, Result};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct SpecGenInput {
11    pub analysis: serde_json::Value,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct SpecGenOutput {
16    pub specification: String,
17}
18
19pub struct SpecGenAgent {
20    id: AgentId,
21}
22
23impl SpecGenAgent {
24    pub fn new() -> Self {
25        Self { id: AgentId::new() }
26    }
27}
28
29impl Default for SpecGenAgent {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35#[async_trait]
36impl Agent for SpecGenAgent {
37    type Input = SpecGenInput;
38    type Output = SpecGenOutput;
39
40    async fn execute(&self, input: Self::Input) -> Result<Self::Output> {
41        // Simplified for POC - delegates to transpiler
42        Ok(SpecGenOutput {
43            specification: serde_json::to_string_pretty(&input.analysis)?,
44        })
45    }
46
47    fn id(&self) -> AgentId {
48        self.id
49    }
50
51    fn name(&self) -> &str {
52        "SpecGenAgent"
53    }
54
55    fn capabilities(&self) -> Vec<AgentCapability> {
56        vec![AgentCapability::SpecificationGeneration]
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use serde_json::json;
64
65    #[tokio::test]
66    async fn test_specification_generation() {
67        let agent = SpecGenAgent::new();
68
69        let analysis = json!({
70            "functions": [{
71                "name": "add",
72                "return_type": "i32"
73            }]
74        });
75
76        let input = SpecGenInput {
77            analysis: analysis.clone(),
78        };
79
80        let output = agent.execute(input).await.unwrap();
81
82        assert!(!output.specification.is_empty());
83        assert!(output.specification.contains("add"));
84    }
85
86    #[tokio::test]
87    async fn test_specification_preserves_structure() {
88        let agent = SpecGenAgent::new();
89
90        let analysis = json!({
91            "functions": [],
92            "classes": [],
93            "metadata": {"version": "1.0"}
94        });
95
96        let input = SpecGenInput {
97            analysis: analysis.clone(),
98        };
99
100        let output = agent.execute(input).await.unwrap();
101
102        // Should be valid JSON
103        let parsed: serde_json::Value = serde_json::from_str(&output.specification).unwrap();
104        assert_eq!(parsed, analysis);
105    }
106
107    #[test]
108    fn test_agent_metadata() {
109        let agent = SpecGenAgent::new();
110
111        assert_eq!(agent.name(), "SpecGenAgent");
112        assert_eq!(agent.capabilities(), vec![AgentCapability::SpecificationGeneration]);
113    }
114}