rust_analysis/
rust_analysis.rs

1use env_logger;
2use kowalski_code_agent::agent::CodeAgent;
3use kowalski_core::{
4    agent::Agent,
5    config::Config,
6    role::{Audience, Preset, Role},
7};
8use std::io::{self, Write};
9
10#[tokio::main]
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // Initialize logging
13    env_logger::init();
14
15    // Load configuration
16    let config = Config::default();
17    let mut code_agent = CodeAgent::new(config).await?;
18
19    // Start a conversation
20    println!("šŸ¦€ Starting Rust Code Analysis...");
21    let conversation_id = code_agent.start_conversation("llama3.2");
22    println!("Code Agent Conversation ID: {}", conversation_id);
23
24    // Set up the role for code analysis
25    let role = Role::new(
26        "Rust Code Analysis Assistant",
27        "You are an expert at analyzing Rust code, providing insights on code quality, safety, and potential improvements.",
28    )
29    .with_audience(Audience::new(
30        "Rust Developer",
31        "You are speaking to a Rust developer who needs detailed code analysis.",
32    ))
33    .with_preset(Preset::new(
34        "Analysis",
35        "Provide comprehensive analysis with specific recommendations for improvement.",
36    ));
37
38    // Sample Rust code for analysis
39    let rust_code = r#"
40use std::collections::HashMap;
41use std::error::Error;
42
43#[derive(Debug)]
44struct DataProcessor {
45    data: Vec<i32>,
46    cache: HashMap<String, i32>,
47}
48
49impl DataProcessor {
50    fn new(data: Vec<i32>) -> Self {
51        Self {
52            data,
53            cache: HashMap::new(),
54        }
55    }
56    
57    fn calculate_sum(&self) -> i32 {
58        self.data.iter().sum()
59    }
60    
61    fn calculate_average(&self) -> Option<f64> {
62        if self.data.is_empty() {
63            None
64        } else {
65            Some(self.calculate_sum() as f64 / self.data.len() as f64)
66        }
67    }
68    
69    fn find_max(&self) -> Option<&i32> {
70        self.data.iter().max()
71    }
72    
73    fn process_with_cache(&mut self, key: String) -> Result<i32, Box<dyn Error>> {
74        if let Some(&cached_value) = self.cache.get(&key) {
75            return Ok(cached_value);
76        }
77        
78        let result = self.calculate_sum();
79        self.cache.insert(key, result);
80        Ok(result)
81    }
82}
83
84fn main() {
85    let numbers = vec![10, 20, 30, 40, 50];
86    let mut processor = DataProcessor::new(numbers);
87    
88    println!("Sum: {}", processor.calculate_sum());
89    
90    match processor.calculate_average() {
91        Some(avg) => println!("Average: {}", avg),
92        None => println!("No data to calculate average"),
93    }
94    
95    match processor.find_max() {
96        Some(max) => println!("Maximum: {}", max),
97        None => println!("No data to find maximum"),
98    }
99    
100    match processor.process_with_cache("sum".to_string()) {
101        Ok(result) => println!("Cached result: {}", result),
102        Err(e) => println!("Error: {}", e),
103    }
104}
105"#;
106
107    println!("\nšŸ“ Rust Code to Analyze:");
108    println!("{}", rust_code);
109
110    // Analyze the Rust code
111    let analysis_result = code_agent.analyze_rust(rust_code).await?;
112
113    println!("\nšŸ“Š Rust Analysis Results:");
114    println!("Language: {}", analysis_result.language);
115    println!(
116        "Metrics: {}",
117        serde_json::to_string_pretty(&analysis_result.metrics)?
118    );
119    println!("Suggestions: {:?}", analysis_result.suggestions);
120    println!("Rust Issues: {:?}", analysis_result.issues);
121
122    // Ask the agent to analyze the code
123    let analysis_prompt = format!(
124        "Please analyze this Rust code and provide insights:\n\n{}\n\nAnalysis results:\nMetrics: {}\nSuggestions: {:?}\nRust Issues: {:?}",
125        rust_code,
126        serde_json::to_string_pretty(&analysis_result.metrics)?,
127        analysis_result.suggestions,
128        analysis_result.issues
129    );
130
131    let mut response = code_agent
132        .chat_with_history(&conversation_id, &analysis_prompt, Some(role))
133        .await?;
134
135    println!("\nšŸ¤– AI Analysis:");
136
137    // Process the streaming response
138    let mut buffer = String::new();
139    while let Some(chunk) = response.chunk().await? {
140        match code_agent
141            .process_stream_response(&conversation_id, &chunk)
142            .await
143        {
144            Ok(Some(message)) => {
145                // Print the content if it exists
146                if !message.content.is_empty() {
147                    print!("{}", message.content);
148                    io::stdout().flush()?;
149                    buffer.push_str(&message.content);
150                }
151
152                // Handle tool calls if they exist
153                if let Some(tool_calls) = &message.tool_calls {
154                    for tool_call in tool_calls {
155                        print!("\n[Tool Call] {}(", tool_call.function.name);
156                        if let Some(obj) = tool_call.function.arguments.as_object() {
157                            for (key, value) in obj {
158                                print!("{}: {}, ", key, value);
159                            }
160                        }
161                        println!(")");
162                        io::stdout().flush()?;
163                    }
164                }
165            }
166            Ok(None) => {
167                code_agent
168                    .add_message(&conversation_id, "assistant", &buffer)
169                    .await;
170                println!("\nāœ… Analysis complete!\n");
171                break;
172            }
173            Err(e) => {
174                eprintln!("\nāŒ Error processing stream: {}", e);
175                break;
176            }
177        }
178    }
179
180    // Ask a follow-up question about Rust-specific improvements
181    let follow_up = "What Rust-specific improvements would you recommend for this code?";
182    let mut follow_up_response = code_agent
183        .chat_with_history(&conversation_id, follow_up, None)
184        .await?;
185
186    println!("\nšŸ” Follow-up Analysis:");
187    let mut buffer = String::new();
188    while let Some(chunk) = follow_up_response.chunk().await? {
189        match code_agent
190            .process_stream_response(&conversation_id, &chunk)
191            .await
192        {
193            Ok(Some(message)) => {
194                // Print the content if it exists
195                if !message.content.is_empty() {
196                    print!("{}", message.content);
197                    io::stdout().flush()?;
198                    buffer.push_str(&message.content);
199                }
200
201                // Handle tool calls if they exist
202                if let Some(tool_calls) = &message.tool_calls {
203                    for tool_call in tool_calls {
204                        print!("\n[Tool Call] {}(", tool_call.function.name);
205                        if let Some(obj) = tool_call.function.arguments.as_object() {
206                            for (key, value) in obj {
207                                print!("{}: {}, ", key, value);
208                            }
209                        }
210                        println!(")");
211                        io::stdout().flush()?;
212                    }
213                }
214            }
215            Ok(None) => {
216                code_agent
217                    .add_message(&conversation_id, "assistant", &buffer)
218                    .await;
219                println!("\n");
220                break;
221            }
222            Err(e) => {
223                eprintln!("\nāŒ Error processing stream: {}", e);
224                break;
225            }
226        }
227    }
228
229    Ok(())
230}