1use 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 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 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}