CodeAgent

Struct CodeAgent 

Source
pub struct CodeAgent { /* private fields */ }
Expand description

CodeAgent: A specialized agent for code analysis and development tasks This agent is built on top of the TemplateAgent and provides code-specific functionality

Implementations§

Source§

impl CodeAgent

Source

pub async fn new(_config: Config) -> Result<Self, KowalskiError>

Creates a new CodeAgent with the specified configuration

Examples found in repository?
examples/java_analysis.rs (line 17)
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 Java 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        "Java Code Analysis Assistant",
27        "You are an expert at analyzing Java code, providing insights on code quality, best practices, and potential improvements.",
28    )
29    .with_audience(Audience::new(
30        "Java Developer",
31        "You are speaking to a Java 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 Java code for analysis
39    let java_code = r#"
40import java.util.*;
41
42public class Calculator {
43    private int result;
44    
45    public Calculator() {
46        this.result = 0;
47    }
48    
49    public int add(int a, int b) {
50        result = a + b;
51        return result;
52    }
53    
54    public int subtract(int a, int b) {
55        result = a - b;
56        return result;
57    }
58    
59    public int multiply(int a, int b) {
60        result = a * b;
61        return result;
62    }
63    
64    public double divide(int a, int b) {
65        if (b == 0) {
66            System.out.println("Error: Division by zero");
67            return 0;
68        }
69        result = a / b;
70        return (double) result;
71    }
72    
73    public static void main(String[] args) {
74        Calculator calc = new Calculator();
75        System.out.println("Addition: " + calc.add(10, 5));
76        System.out.println("Subtraction: " + calc.subtract(10, 5));
77        System.out.println("Multiplication: " + calc.multiply(10, 5));
78        System.out.println("Division: " + calc.divide(10, 5));
79    }
80}
81"#;
82
83    println!("\n📝 Java Code to Analyze:");
84    println!("{}", java_code);
85
86    // Analyze the Java code
87    let analysis_result = code_agent.analyze_java(java_code).await?;
88
89    println!("\n📊 Java Analysis Results:");
90    println!("Language: {}", analysis_result.language);
91    println!(
92        "Metrics: {}",
93        serde_json::to_string_pretty(&analysis_result.metrics)?
94    );
95    println!("Suggestions: {:?}", analysis_result.suggestions);
96    println!("Issues: {:?}", analysis_result.issues);
97
98    // Ask the agent to analyze the code
99    let analysis_prompt = format!(
100        "Please analyze this Java code and provide insights:\n\n{}\n\nAnalysis results:\nMetrics: {}\nSuggestions: {:?}\nIssues: {:?}",
101        java_code,
102        serde_json::to_string_pretty(&analysis_result.metrics)?,
103        analysis_result.suggestions,
104        analysis_result.issues
105    );
106
107    let mut response = code_agent
108        .chat_with_history(&conversation_id, &analysis_prompt, Some(role))
109        .await?;
110
111    println!("\n🤖 AI Analysis:");
112
113    // Process the streaming response
114    let mut buffer = String::new();
115    while let Some(chunk) = response.chunk().await? {
116        match code_agent
117            .process_stream_response(&conversation_id, &chunk)
118            .await
119        {
120            Ok(Some(message)) => {
121                // Print the content if it exists
122                if !message.content.is_empty() {
123                    print!("{}", message.content);
124                    io::stdout().flush()?;
125                    buffer.push_str(&message.content);
126                }
127
128                // Handle tool calls if they exist
129                if let Some(tool_calls) = &message.tool_calls {
130                    for tool_call in tool_calls {
131                        print!("\n[Tool Call] {}(", tool_call.function.name);
132                        if let Some(obj) = tool_call.function.arguments.as_object() {
133                            for (key, value) in obj {
134                                print!("{}: {}, ", key, value);
135                            }
136                        }
137                        println!(")");
138                        io::stdout().flush()?;
139                    }
140                }
141            }
142            Ok(None) => {
143                code_agent
144                    .add_message(&conversation_id, "assistant", &buffer)
145                    .await;
146                println!("\n✅ Analysis complete!\n");
147                break;
148            }
149            Err(e) => {
150                eprintln!("\n❌ Error processing stream: {}", e);
151                break;
152            }
153        }
154    }
155
156    // Ask a follow-up question about specific improvements
157    let follow_up = "What specific improvements would you recommend for this Java code?";
158    let mut follow_up_response = code_agent
159        .chat_with_history(&conversation_id, follow_up, None)
160        .await?;
161
162    println!("\n🔍 Follow-up Analysis:");
163    let mut buffer = String::new();
164    while let Some(chunk) = follow_up_response.chunk().await? {
165        match code_agent
166            .process_stream_response(&conversation_id, &chunk)
167            .await
168        {
169            Ok(Some(message)) => {
170                // Print the content if it exists
171                if !message.content.is_empty() {
172                    print!("{}", message.content);
173                    io::stdout().flush()?;
174                    buffer.push_str(&message.content);
175                }
176
177                // Handle tool calls if they exist
178                if let Some(tool_calls) = &message.tool_calls {
179                    for tool_call in tool_calls {
180                        print!("\n[Tool Call] {}(", tool_call.function.name);
181                        if let Some(obj) = tool_call.function.arguments.as_object() {
182                            for (key, value) in obj {
183                                print!("{}: {}, ", key, value);
184                            }
185                        }
186                        println!(")");
187                        io::stdout().flush()?;
188                    }
189                }
190            }
191            Ok(None) => {
192                code_agent
193                    .add_message(&conversation_id, "assistant", &buffer)
194                    .await;
195                println!("\n");
196                break;
197            }
198            Err(e) => {
199                eprintln!("\n❌ Error processing stream: {}", e);
200                break;
201            }
202        }
203    }
204
205    Ok(())
206}
More examples
Hide additional examples
examples/python_analysis.rs (line 17)
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 Python 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        "Python Code Analysis Assistant",
27        "You are an expert at analyzing Python code, providing insights on code quality, PEP 8 compliance, and potential improvements.",
28    )
29    .with_audience(Audience::new(
30        "Python Developer",
31        "You are speaking to a Python 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 Python code for analysis
39    let python_code = r#"
40import os
41import sys
42from typing import List, Optional
43
44class DataProcessor:
45    def __init__(self, data: List[int]):
46        self.data = data
47        self.result = 0
48    
49    def calculate_sum(self) -> int:
50        """Calculate the sum of all data points."""
51        total = 0
52        for item in self.data:
53            total += item
54        return total
55    
56    def calculate_average(self) -> float:
57        """Calculate the average of all data points."""
58        if len(self.data) == 0:
59            print("Error: No data to calculate average")
60            return 0.0
61        return self.calculate_sum() / len(self.data)
62    
63    def find_max(self) -> Optional[int]:
64        """Find the maximum value in the data."""
65        if not self.data:
66            return None
67        max_val = self.data[0]
68        for item in self.data:
69            if item > max_val:
70                max_val = item
71        return max_val
72
73def main():
74    # Sample data
75    numbers = [10, 20, 30, 40, 50]
76    
77    # Create processor
78    processor = DataProcessor(numbers)
79    
80    # Calculate statistics
81    print(f"Sum: {processor.calculate_sum()}")
82    print(f"Average: {processor.calculate_average()}")
83    print(f"Maximum: {processor.find_max()}")
84    
85    # Process empty data
86    empty_processor = DataProcessor([])
87    print(f"Empty average: {empty_processor.calculate_average()}")
88
89if __name__ == "__main__":
90    main()
91"#;
92
93    println!("\n📝 Python Code to Analyze:");
94    println!("{}", python_code);
95
96    // Analyze the Python code
97    let analysis_result = code_agent.analyze_python(python_code).await?;
98
99    println!("\n📊 Python Analysis Results:");
100    println!("Language: {}", analysis_result.language);
101    println!(
102        "Metrics: {}",
103        serde_json::to_string_pretty(&analysis_result.metrics)?
104    );
105    println!("Suggestions: {:?}", analysis_result.suggestions);
106    println!("PEP 8 Issues: {:?}", analysis_result.issues);
107
108    // Ask the agent to analyze the code
109    let analysis_prompt = format!(
110        "Please analyze this Python code and provide insights:\n\n{}\n\nAnalysis results:\nMetrics: {}\nSuggestions: {:?}\nPEP 8 Issues: {:?}",
111        python_code,
112        serde_json::to_string_pretty(&analysis_result.metrics)?,
113        analysis_result.suggestions,
114        analysis_result.issues
115    );
116
117    let mut response = code_agent
118        .chat_with_history(&conversation_id, &analysis_prompt, Some(role))
119        .await?;
120
121    println!("\n🤖 AI Analysis:");
122
123    // Process the streaming response
124    let mut buffer = String::new();
125    while let Some(chunk) = response.chunk().await? {
126        match code_agent
127            .process_stream_response(&conversation_id, &chunk)
128            .await
129        {
130            Ok(Some(message)) => {
131                // Print the content if it exists
132                if !message.content.is_empty() {
133                    print!("{}", message.content);
134                    io::stdout().flush()?;
135                    buffer.push_str(&message.content);
136                }
137
138                // Handle tool calls if they exist
139                if let Some(tool_calls) = &message.tool_calls {
140                    for tool_call in tool_calls {
141                        print!("\n[Tool Call] {}(", tool_call.function.name);
142                        if let Some(obj) = tool_call.function.arguments.as_object() {
143                            for (key, value) in obj {
144                                print!("{}: {}, ", key, value);
145                            }
146                        }
147                        println!(")");
148                        io::stdout().flush()?;
149                    }
150                }
151            }
152            Ok(None) => {
153                code_agent
154                    .add_message(&conversation_id, "assistant", &buffer)
155                    .await;
156                println!("\n✅ Analysis complete!\n");
157                break;
158            }
159            Err(e) => {
160                eprintln!("\n❌ Error processing stream: {}", e);
161                break;
162            }
163        }
164    }
165
166    // Ask a follow-up question about PEP 8 compliance
167    let follow_up = "How can this Python code be improved to better follow PEP 8 guidelines?";
168    let mut follow_up_response = code_agent
169        .chat_with_history(&conversation_id, follow_up, None)
170        .await?;
171
172    println!("\n🔍 Follow-up Analysis:");
173    let mut buffer = String::new();
174    while let Some(chunk) = follow_up_response.chunk().await? {
175        match code_agent
176            .process_stream_response(&conversation_id, &chunk)
177            .await
178        {
179            Ok(Some(message)) => {
180                // Print the content if it exists
181                if !message.content.is_empty() {
182                    print!("{}", message.content);
183                    io::stdout().flush()?;
184                    buffer.push_str(&message.content);
185                }
186
187                // Handle tool calls if they exist
188                if let Some(tool_calls) = &message.tool_calls {
189                    for tool_call in tool_calls {
190                        print!("\n[Tool Call] {}(", tool_call.function.name);
191                        if let Some(obj) = tool_call.function.arguments.as_object() {
192                            for (key, value) in obj {
193                                print!("{}: {}, ", key, value);
194                            }
195                        }
196                        println!(")");
197                        io::stdout().flush()?;
198                    }
199                }
200            }
201            Ok(None) => {
202                code_agent
203                    .add_message(&conversation_id, "assistant", &buffer)
204                    .await;
205                println!("\n");
206                break;
207            }
208            Err(e) => {
209                eprintln!("\n❌ Error processing stream: {}", e);
210                break;
211            }
212        }
213    }
214
215    Ok(())
216}
examples/rust_analysis.rs (line 17)
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}
Source

pub async fn analyze_java( &self, code: &str, ) -> Result<CodeAnalysisResult, KowalskiError>

Analyzes Java code

Examples found in repository?
examples/java_analysis.rs (line 87)
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 Java 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        "Java Code Analysis Assistant",
27        "You are an expert at analyzing Java code, providing insights on code quality, best practices, and potential improvements.",
28    )
29    .with_audience(Audience::new(
30        "Java Developer",
31        "You are speaking to a Java 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 Java code for analysis
39    let java_code = r#"
40import java.util.*;
41
42public class Calculator {
43    private int result;
44    
45    public Calculator() {
46        this.result = 0;
47    }
48    
49    public int add(int a, int b) {
50        result = a + b;
51        return result;
52    }
53    
54    public int subtract(int a, int b) {
55        result = a - b;
56        return result;
57    }
58    
59    public int multiply(int a, int b) {
60        result = a * b;
61        return result;
62    }
63    
64    public double divide(int a, int b) {
65        if (b == 0) {
66            System.out.println("Error: Division by zero");
67            return 0;
68        }
69        result = a / b;
70        return (double) result;
71    }
72    
73    public static void main(String[] args) {
74        Calculator calc = new Calculator();
75        System.out.println("Addition: " + calc.add(10, 5));
76        System.out.println("Subtraction: " + calc.subtract(10, 5));
77        System.out.println("Multiplication: " + calc.multiply(10, 5));
78        System.out.println("Division: " + calc.divide(10, 5));
79    }
80}
81"#;
82
83    println!("\n📝 Java Code to Analyze:");
84    println!("{}", java_code);
85
86    // Analyze the Java code
87    let analysis_result = code_agent.analyze_java(java_code).await?;
88
89    println!("\n📊 Java Analysis Results:");
90    println!("Language: {}", analysis_result.language);
91    println!(
92        "Metrics: {}",
93        serde_json::to_string_pretty(&analysis_result.metrics)?
94    );
95    println!("Suggestions: {:?}", analysis_result.suggestions);
96    println!("Issues: {:?}", analysis_result.issues);
97
98    // Ask the agent to analyze the code
99    let analysis_prompt = format!(
100        "Please analyze this Java code and provide insights:\n\n{}\n\nAnalysis results:\nMetrics: {}\nSuggestions: {:?}\nIssues: {:?}",
101        java_code,
102        serde_json::to_string_pretty(&analysis_result.metrics)?,
103        analysis_result.suggestions,
104        analysis_result.issues
105    );
106
107    let mut response = code_agent
108        .chat_with_history(&conversation_id, &analysis_prompt, Some(role))
109        .await?;
110
111    println!("\n🤖 AI Analysis:");
112
113    // Process the streaming response
114    let mut buffer = String::new();
115    while let Some(chunk) = response.chunk().await? {
116        match code_agent
117            .process_stream_response(&conversation_id, &chunk)
118            .await
119        {
120            Ok(Some(message)) => {
121                // Print the content if it exists
122                if !message.content.is_empty() {
123                    print!("{}", message.content);
124                    io::stdout().flush()?;
125                    buffer.push_str(&message.content);
126                }
127
128                // Handle tool calls if they exist
129                if let Some(tool_calls) = &message.tool_calls {
130                    for tool_call in tool_calls {
131                        print!("\n[Tool Call] {}(", tool_call.function.name);
132                        if let Some(obj) = tool_call.function.arguments.as_object() {
133                            for (key, value) in obj {
134                                print!("{}: {}, ", key, value);
135                            }
136                        }
137                        println!(")");
138                        io::stdout().flush()?;
139                    }
140                }
141            }
142            Ok(None) => {
143                code_agent
144                    .add_message(&conversation_id, "assistant", &buffer)
145                    .await;
146                println!("\n✅ Analysis complete!\n");
147                break;
148            }
149            Err(e) => {
150                eprintln!("\n❌ Error processing stream: {}", e);
151                break;
152            }
153        }
154    }
155
156    // Ask a follow-up question about specific improvements
157    let follow_up = "What specific improvements would you recommend for this Java code?";
158    let mut follow_up_response = code_agent
159        .chat_with_history(&conversation_id, follow_up, None)
160        .await?;
161
162    println!("\n🔍 Follow-up Analysis:");
163    let mut buffer = String::new();
164    while let Some(chunk) = follow_up_response.chunk().await? {
165        match code_agent
166            .process_stream_response(&conversation_id, &chunk)
167            .await
168        {
169            Ok(Some(message)) => {
170                // Print the content if it exists
171                if !message.content.is_empty() {
172                    print!("{}", message.content);
173                    io::stdout().flush()?;
174                    buffer.push_str(&message.content);
175                }
176
177                // Handle tool calls if they exist
178                if let Some(tool_calls) = &message.tool_calls {
179                    for tool_call in tool_calls {
180                        print!("\n[Tool Call] {}(", tool_call.function.name);
181                        if let Some(obj) = tool_call.function.arguments.as_object() {
182                            for (key, value) in obj {
183                                print!("{}: {}, ", key, value);
184                            }
185                        }
186                        println!(")");
187                        io::stdout().flush()?;
188                    }
189                }
190            }
191            Ok(None) => {
192                code_agent
193                    .add_message(&conversation_id, "assistant", &buffer)
194                    .await;
195                println!("\n");
196                break;
197            }
198            Err(e) => {
199                eprintln!("\n❌ Error processing stream: {}", e);
200                break;
201            }
202        }
203    }
204
205    Ok(())
206}
Source

pub async fn analyze_python( &self, code: &str, ) -> Result<CodeAnalysisResult, KowalskiError>

Analyzes Python code

Examples found in repository?
examples/python_analysis.rs (line 97)
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 Python 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        "Python Code Analysis Assistant",
27        "You are an expert at analyzing Python code, providing insights on code quality, PEP 8 compliance, and potential improvements.",
28    )
29    .with_audience(Audience::new(
30        "Python Developer",
31        "You are speaking to a Python 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 Python code for analysis
39    let python_code = r#"
40import os
41import sys
42from typing import List, Optional
43
44class DataProcessor:
45    def __init__(self, data: List[int]):
46        self.data = data
47        self.result = 0
48    
49    def calculate_sum(self) -> int:
50        """Calculate the sum of all data points."""
51        total = 0
52        for item in self.data:
53            total += item
54        return total
55    
56    def calculate_average(self) -> float:
57        """Calculate the average of all data points."""
58        if len(self.data) == 0:
59            print("Error: No data to calculate average")
60            return 0.0
61        return self.calculate_sum() / len(self.data)
62    
63    def find_max(self) -> Optional[int]:
64        """Find the maximum value in the data."""
65        if not self.data:
66            return None
67        max_val = self.data[0]
68        for item in self.data:
69            if item > max_val:
70                max_val = item
71        return max_val
72
73def main():
74    # Sample data
75    numbers = [10, 20, 30, 40, 50]
76    
77    # Create processor
78    processor = DataProcessor(numbers)
79    
80    # Calculate statistics
81    print(f"Sum: {processor.calculate_sum()}")
82    print(f"Average: {processor.calculate_average()}")
83    print(f"Maximum: {processor.find_max()}")
84    
85    # Process empty data
86    empty_processor = DataProcessor([])
87    print(f"Empty average: {empty_processor.calculate_average()}")
88
89if __name__ == "__main__":
90    main()
91"#;
92
93    println!("\n📝 Python Code to Analyze:");
94    println!("{}", python_code);
95
96    // Analyze the Python code
97    let analysis_result = code_agent.analyze_python(python_code).await?;
98
99    println!("\n📊 Python Analysis Results:");
100    println!("Language: {}", analysis_result.language);
101    println!(
102        "Metrics: {}",
103        serde_json::to_string_pretty(&analysis_result.metrics)?
104    );
105    println!("Suggestions: {:?}", analysis_result.suggestions);
106    println!("PEP 8 Issues: {:?}", analysis_result.issues);
107
108    // Ask the agent to analyze the code
109    let analysis_prompt = format!(
110        "Please analyze this Python code and provide insights:\n\n{}\n\nAnalysis results:\nMetrics: {}\nSuggestions: {:?}\nPEP 8 Issues: {:?}",
111        python_code,
112        serde_json::to_string_pretty(&analysis_result.metrics)?,
113        analysis_result.suggestions,
114        analysis_result.issues
115    );
116
117    let mut response = code_agent
118        .chat_with_history(&conversation_id, &analysis_prompt, Some(role))
119        .await?;
120
121    println!("\n🤖 AI Analysis:");
122
123    // Process the streaming response
124    let mut buffer = String::new();
125    while let Some(chunk) = response.chunk().await? {
126        match code_agent
127            .process_stream_response(&conversation_id, &chunk)
128            .await
129        {
130            Ok(Some(message)) => {
131                // Print the content if it exists
132                if !message.content.is_empty() {
133                    print!("{}", message.content);
134                    io::stdout().flush()?;
135                    buffer.push_str(&message.content);
136                }
137
138                // Handle tool calls if they exist
139                if let Some(tool_calls) = &message.tool_calls {
140                    for tool_call in tool_calls {
141                        print!("\n[Tool Call] {}(", tool_call.function.name);
142                        if let Some(obj) = tool_call.function.arguments.as_object() {
143                            for (key, value) in obj {
144                                print!("{}: {}, ", key, value);
145                            }
146                        }
147                        println!(")");
148                        io::stdout().flush()?;
149                    }
150                }
151            }
152            Ok(None) => {
153                code_agent
154                    .add_message(&conversation_id, "assistant", &buffer)
155                    .await;
156                println!("\n✅ Analysis complete!\n");
157                break;
158            }
159            Err(e) => {
160                eprintln!("\n❌ Error processing stream: {}", e);
161                break;
162            }
163        }
164    }
165
166    // Ask a follow-up question about PEP 8 compliance
167    let follow_up = "How can this Python code be improved to better follow PEP 8 guidelines?";
168    let mut follow_up_response = code_agent
169        .chat_with_history(&conversation_id, follow_up, None)
170        .await?;
171
172    println!("\n🔍 Follow-up Analysis:");
173    let mut buffer = String::new();
174    while let Some(chunk) = follow_up_response.chunk().await? {
175        match code_agent
176            .process_stream_response(&conversation_id, &chunk)
177            .await
178        {
179            Ok(Some(message)) => {
180                // Print the content if it exists
181                if !message.content.is_empty() {
182                    print!("{}", message.content);
183                    io::stdout().flush()?;
184                    buffer.push_str(&message.content);
185                }
186
187                // Handle tool calls if they exist
188                if let Some(tool_calls) = &message.tool_calls {
189                    for tool_call in tool_calls {
190                        print!("\n[Tool Call] {}(", tool_call.function.name);
191                        if let Some(obj) = tool_call.function.arguments.as_object() {
192                            for (key, value) in obj {
193                                print!("{}: {}, ", key, value);
194                            }
195                        }
196                        println!(")");
197                        io::stdout().flush()?;
198                    }
199                }
200            }
201            Ok(None) => {
202                code_agent
203                    .add_message(&conversation_id, "assistant", &buffer)
204                    .await;
205                println!("\n");
206                break;
207            }
208            Err(e) => {
209                eprintln!("\n❌ Error processing stream: {}", e);
210                break;
211            }
212        }
213    }
214
215    Ok(())
216}
Source

pub async fn analyze_rust( &self, code: &str, ) -> Result<CodeAnalysisResult, KowalskiError>

Analyzes Rust code

Examples found in repository?
examples/rust_analysis.rs (line 111)
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}

Trait Implementations§

Source§

impl Agent for CodeAgent

Source§

fn new<'async_trait>( config: Config, ) -> Pin<Box<dyn Future<Output = Result<Self, KowalskiError>> + Send + 'async_trait>>
where Self: 'async_trait,

Creates a new agent with the specified configuration.
Source§

fn start_conversation(&mut self, model: &str) -> String

Starts a new conversation
Source§

fn get_conversation(&self, id: &str) -> Option<&Conversation>

Gets a conversation by ID
Source§

fn list_conversations(&self) -> Vec<&Conversation>

Lists all conversations
Source§

fn delete_conversation(&mut self, id: &str) -> bool

Deletes a conversation
Source§

fn chat_with_history<'life0, 'life1, 'life2, 'async_trait>( &'life0 mut self, conversation_id: &'life1 str, content: &'life2 str, role: Option<Role>, ) -> Pin<Box<dyn Future<Output = Result<Response, KowalskiError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Chats with history
Source§

fn process_stream_response<'life0, 'life1, 'life2, 'async_trait>( &'life0 mut self, conversation_id: &'life1 str, chunk: &'life2 [u8], ) -> Pin<Box<dyn Future<Output = Result<Option<Message>, KowalskiError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Processes a stream response
Source§

fn add_message<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 mut self, conversation_id: &'life1 str, role: &'life2 str, content: &'life3 str, ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Adds a message to a conversation
Source§

fn name(&self) -> &str

Gets the agent’s name
Source§

fn description(&self) -> &str

Gets the agent’s description

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> MaybeSendSync for T