1use crate::edit_control::ModifiableEdit;
6use crate::memory::SymbolicContext;
7use crate::ops::{default_operator_registry, SomaOperator};
8use anyhow::Result;
9use std::collections::HashMap;
10use std::io::{self, Write};
11
12pub struct VisualReasoningCLI {
14 operator_registry: HashMap<String, Box<dyn SomaOperator>>,
15 analysis_history: Vec<VisualAnalysisResult>,
16 current_session: VisualSession,
17}
18
19#[derive(Debug, Clone)]
21pub struct VisualSession {
22 pub session_id: String,
23 pub file_path: String,
24 pub analysis_count: usize,
25 pub patterns_detected: Vec<String>,
26 pub confidence_scores: Vec<f64>,
27}
28
29#[derive(Debug, Clone)]
31pub struct VisualAnalysisResult {
32 pub analysis_type: String,
33 pub visual_elements: Vec<String>,
34 pub relationships: Vec<String>,
35 pub complexity_score: f64,
36 pub confidence: f64,
37 pub symbolic_mapping: SymbolicContext,
38 pub recommendations: Vec<String>,
39 pub timestamp: u64,
40}
41
42impl Default for VisualReasoningCLI {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl VisualReasoningCLI {
49 pub fn new() -> Self {
50 Self {
51 operator_registry: default_operator_registry(),
52 analysis_history: Vec::new(),
53 current_session: VisualSession {
54 session_id: format!("visual_{}",
55 std::time::SystemTime::now()
56 .duration_since(std::time::UNIX_EPOCH)
57 .unwrap()
58 .as_secs()),
59 file_path: String::new(),
60 analysis_count: 0,
61 patterns_detected: Vec::new(),
62 confidence_scores: Vec::new(),
63 },
64 }
65 }
66
67 pub fn run_visual_analysis(&mut self, edit: &ModifiableEdit) -> Result<()> {
69 self.current_session.file_path = edit.base_edit.file.clone();
70
71 println!("\n㪠Visual Reasoning Analysis System");
72 println!("===================================");
73 println!("File: {}", edit.base_edit.file);
74
75 loop {
76 match self.show_visual_menu()? {
77 VisualMenuChoice::CodeStructureAnalysis => {
78 self.analyze_code_structure(edit)?;
79 }
80 VisualMenuChoice::PatternRecognition => {
81 self.run_pattern_recognition(edit)?;
82 }
83 VisualMenuChoice::DependencyMapping => {
84 self.map_dependencies(edit)?;
85 }
86 VisualMenuChoice::VisualDiffAnalysis => {
87 self.analyze_visual_diff(edit)?;
88 }
89 VisualMenuChoice::ASTreeVisualization => {
90 self.visualize_ast_structure(edit)?;
91 }
92 VisualMenuChoice::SessionSummary => {
93 self.show_session_summary()?;
94 }
95 VisualMenuChoice::ExportAnalysis => {
96 self.export_analysis_results()?;
97 }
98 VisualMenuChoice::Back => break,
99 }
100 }
101
102 Ok(())
103 }
104
105 fn show_visual_menu(&self) -> Result<VisualMenuChoice> {
106 loop {
107 println!("\nπ― Visual Reasoning Options:");
108 println!(" 1. ποΈ Code Structure Analysis");
109 println!(" 2. π Pattern Recognition");
110 println!(" 3. πΈοΈ Dependency Mapping");
111 println!(" 4. π Visual Diff Analysis");
112 println!(" 5. π³ AST Tree Visualization");
113 println!(" 6. π Session Summary");
114 println!(" 7. πΎ Export Analysis Results");
115 println!(" 8. β¬
οΈ Back to Main Menu");
116
117 print!("\nSelect visual analysis (1-8): ");
118 io::stdout().flush()?;
119
120 let mut input = String::new();
121 io::stdin().read_line(&mut input)?;
122
123 match input.trim() {
124 "1" => return Ok(VisualMenuChoice::CodeStructureAnalysis),
125 "2" => return Ok(VisualMenuChoice::PatternRecognition),
126 "3" => return Ok(VisualMenuChoice::DependencyMapping),
127 "4" => return Ok(VisualMenuChoice::VisualDiffAnalysis),
128 "5" => return Ok(VisualMenuChoice::ASTreeVisualization),
129 "6" => return Ok(VisualMenuChoice::SessionSummary),
130 "7" => return Ok(VisualMenuChoice::ExportAnalysis),
131 "8" => return Ok(VisualMenuChoice::Back),
132 _ => println!("β Invalid choice. Please try again."),
133 }
134 }
135 }
136
137 fn analyze_code_structure(&mut self, edit: &ModifiableEdit) -> Result<()> {
138 println!("\nποΈ Code Structure Analysis");
139 println!("==========================");
140
141 let mut context = SymbolicContext::new();
142 context.set("visual_type", "code_structure");
143 context.set("analysis_mode", "architecture");
144 context.set("file_path", &edit.base_edit.file);
145 context.set("code_content", &edit.compute_final_code());
146
147 if let Some(visual_op) = self.operator_registry.get("visual_reasoning") {
149 let result = visual_op.execute(&context)?;
150
151 let analysis = VisualAnalysisResult {
152 analysis_type: "code_structure".to_string(),
153 visual_elements: vec!["functions".to_string(), "classes".to_string(), "modules".to_string()],
154 relationships: vec!["calls".to_string(), "inherits".to_string(), "imports".to_string()],
155 complexity_score: result.resolve_or_default("visual_complexity", "0.5").parse().unwrap_or(0.5),
156 confidence: result.resolve_or_default("conversion_confidence", "0.8").parse().unwrap_or(0.8),
157 symbolic_mapping: result,
158 recommendations: self.generate_structure_recommendations(&edit.base_edit.file),
159 timestamp: std::time::SystemTime::now()
160 .duration_since(std::time::UNIX_EPOCH)
161 .unwrap()
162 .as_secs(),
163 };
164
165 self.display_analysis_result(&analysis);
166 self.analysis_history.push(analysis);
167 self.current_session.analysis_count += 1;
168 }
169
170 Ok(())
171 }
172
173 fn run_pattern_recognition(&mut self, edit: &ModifiableEdit) -> Result<()> {
174 println!("\nπ Pattern Recognition Analysis");
175 println!("==============================");
176
177 let code = edit.compute_final_code();
178 let patterns = self.detect_code_patterns(&code);
179
180 println!("π Detected Patterns:");
181 for (i, pattern) in patterns.iter().enumerate() {
182 println!(" {}. {}", i + 1, pattern);
183 }
184
185 let mut context = SymbolicContext::new();
187 context.set("visual_type", "pattern_recognition");
188 context.set("patterns_detected", &patterns.join(","));
189 context.set("pattern_count", &patterns.len().to_string());
190
191 if let Some(cognitive_op) = self.operator_registry.get("cognitive_load") {
192 let cognitive_result = cognitive_op.execute(&context)?;
193
194 println!("\nπ§ Cognitive Pattern Analysis:");
195 println!(" β’ Pattern complexity: {}",
196 cognitive_result.resolve_or_default("load_score", "unknown"));
197 println!(" β’ Processing load: {}",
198 cognitive_result.resolve_or_default("load_level", "unknown"));
199 }
200
201 self.current_session.patterns_detected.extend(patterns);
202
203 Ok(())
204 }
205
206 fn map_dependencies(&mut self, edit: &ModifiableEdit) -> Result<()> {
207 println!("\nπΈοΈ Dependency Mapping");
208 println!("=====================");
209
210 let dependencies = self.extract_dependencies(&edit.compute_final_code());
211
212 println!("π¦ Dependencies Found:");
213 for (i, dep) in dependencies.iter().enumerate() {
214 println!(" {}. {}", i + 1, dep);
215 }
216
217 self.display_dependency_graph(&dependencies);
219
220 Ok(())
221 }
222
223 fn analyze_visual_diff(&mut self, edit: &ModifiableEdit) -> Result<()> {
224 println!("\nπ Visual Diff Analysis");
225 println!("=======================");
226
227 let line_range = edit.base_edit.line_range;
229 let original_lines = line_range.1 - line_range.0 + 1;
230 let modified_lines = edit.base_edit.new_code.lines().count();
231 let diff_ratio = if original_lines > 0 {
232 (modified_lines as f64 - original_lines as f64) / original_lines as f64
233 } else {
234 0.0
235 };
236
237 println!("π Diff Statistics:");
238 println!(" β’ Original lines: {}", original_lines);
239 println!(" β’ Modified lines: {}", modified_lines);
240 println!(" β’ Change ratio: {:.2}%", diff_ratio * 100.0);
241
242 self.display_visual_diff_chart(original_lines, modified_lines);
244
245 Ok(())
246 }
247
248 fn visualize_ast_structure(&mut self, edit: &ModifiableEdit) -> Result<()> {
249 println!("\nπ³ AST Tree Visualization");
250 println!("=========================");
251
252 let ast_nodes = self.parse_ast_structure(&edit.compute_final_code());
253
254 println!("π² AST Structure:");
255 for (depth, node) in ast_nodes {
256 let indent = " ".repeat(depth);
257 println!("{}ββ {}", indent, node);
258 }
259
260 Ok(())
261 }
262
263 fn show_session_summary(&self) -> Result<()> {
264 println!("\nπ Visual Analysis Session Summary");
265 println!("==================================");
266 println!("Session ID: {}", self.current_session.session_id);
267 println!("File: {}", self.current_session.file_path);
268 println!("Analyses performed: {}", self.current_session.analysis_count);
269 println!("Patterns detected: {}", self.current_session.patterns_detected.len());
270
271 if !self.current_session.confidence_scores.is_empty() {
272 let avg_confidence: f64 = self.current_session.confidence_scores.iter().sum::<f64>()
273 / self.current_session.confidence_scores.len() as f64;
274 println!("Average confidence: {:.2}", avg_confidence);
275 }
276
277 println!("\nπ Analysis History:");
278 for (i, analysis) in self.analysis_history.iter().enumerate() {
279 println!(" {}. {} (confidence: {:.2})",
280 i + 1, analysis.analysis_type, analysis.confidence);
281 }
282
283 Ok(())
284 }
285
286 fn export_analysis_results(&self) -> Result<()> {
287 println!("\nπΎ Export Analysis Results");
288 println!("==========================");
289
290 let export_data = serde_json::json!({
291 "session_id": self.current_session.session_id,
292 "file_path": self.current_session.file_path,
293 "analysis_count": self.current_session.analysis_count,
294 "patterns_detected": self.current_session.patterns_detected,
295 "analysis_history": self.analysis_history.len()
296 });
297
298 println!("π Analysis Export Data:");
299 println!("{}", serde_json::to_string_pretty(&export_data)?);
300
301 Ok(())
302 }
303
304 fn detect_code_patterns(&self, code: &str) -> Vec<String> {
307 let mut patterns = Vec::new();
308
309 if code.contains("fn ") { patterns.push("Function definitions".to_string()); }
310 if code.contains("struct ") { patterns.push("Struct definitions".to_string()); }
311 if code.contains("impl ") { patterns.push("Implementation blocks".to_string()); }
312 if code.contains("match ") { patterns.push("Pattern matching".to_string()); }
313 if code.contains("if ") { patterns.push("Conditional logic".to_string()); }
314 if code.contains("for ") || code.contains("while ") {
315 patterns.push("Loop constructs".to_string());
316 }
317 if code.contains("use ") { patterns.push("Import statements".to_string()); }
318 if code.contains("pub ") { patterns.push("Public interfaces".to_string()); }
319
320 patterns
321 }
322
323 fn extract_dependencies(&self, code: &str) -> Vec<String> {
324 let mut deps = Vec::new();
325
326 for line in code.lines() {
327 let trimmed = line.trim();
328 if trimmed.starts_with("use ") {
329 if let Some(dep) = trimmed.strip_prefix("use ") {
330 if let Some(dep_name) = dep.split("::").next() {
331 deps.push(dep_name.to_string());
332 }
333 }
334 }
335 }
336
337 deps.sort();
338 deps.dedup();
339 deps
340 }
341
342 fn display_dependency_graph(&self, dependencies: &[String]) {
343 println!("\nπ Dependency Graph (ASCII):");
344 println!("ββ {} ββ", self.current_session.file_path);
345 for dep in dependencies {
346 println!("βββ {}", dep);
347 }
348 println!("βββββββββββ");
349 }
350
351 fn display_visual_diff_chart(&self, original: usize, modified: usize) {
352 println!("\nπ Visual Diff Chart:");
353 let max_val = original.max(modified);
354 let orig_bars = if max_val > 0 { (original * 20) / max_val } else { 0 };
355 let mod_bars = if max_val > 0 { (modified * 20) / max_val } else { 0 };
356
357 println!("Original: [{}] ({} lines)", "β".repeat(orig_bars), original);
358 println!("Modified: [{}] ({} lines)", "β".repeat(mod_bars), modified);
359 }
360
361 fn parse_ast_structure(&self, code: &str) -> Vec<(usize, String)> {
362 let mut ast_nodes = Vec::new();
363 let mut depth = 0;
364
365 for line in code.lines() {
366 let trimmed = line.trim();
367
368 if trimmed.starts_with("fn ") {
370 ast_nodes.push((depth, format!("Function: {}",
371 trimmed.split(' ').nth(1).unwrap_or("unknown"))));
372 depth += 1;
373 } else if trimmed.starts_with("struct ") {
374 ast_nodes.push((depth, format!("Struct: {}",
375 trimmed.split(' ').nth(1).unwrap_or("unknown"))));
376 depth += 1;
377 } else if trimmed == "}" && depth > 0 {
378 depth -= 1;
379 } else if trimmed.starts_with("let ") {
380 ast_nodes.push((depth + 1, format!("Variable: {}",
381 trimmed.split(' ').nth(1).unwrap_or("unknown"))));
382 }
383 }
384
385 ast_nodes
386 }
387
388 fn generate_structure_recommendations(&self, file_path: &str) -> Vec<String> {
389 let mut recommendations = Vec::new();
390
391 let extension = std::path::Path::new(file_path)
392 .extension()
393 .and_then(|ext| ext.to_str())
394 .unwrap_or("");
395
396 match extension {
397 "rs" => {
398 recommendations.push("Consider using modules to organize code".to_string());
399 recommendations.push("Implement proper error handling with Result types".to_string());
400 recommendations.push("Add comprehensive documentation comments".to_string());
401 }
402 "py" => {
403 recommendations.push("Follow PEP 8 style guidelines".to_string());
404 recommendations.push("Add type hints for better code clarity".to_string());
405 recommendations.push("Use docstrings for function documentation".to_string());
406 }
407 _ => {
408 recommendations.push("Maintain consistent coding style".to_string());
409 recommendations.push("Add appropriate comments and documentation".to_string());
410 }
411 }
412
413 recommendations
414 }
415
416 fn display_analysis_result(&self, result: &VisualAnalysisResult) {
417 println!("\nπ Analysis Results:");
418 println!(" β’ Type: {}", result.analysis_type);
419 println!(" β’ Elements: {}", result.visual_elements.join(", "));
420 println!(" β’ Relationships: {}", result.relationships.join(", "));
421 println!(" β’ Complexity: {:.2}", result.complexity_score);
422 println!(" β’ Confidence: {:.2}", result.confidence);
423
424 println!("\nπ‘ Recommendations:");
425 for (i, rec) in result.recommendations.iter().enumerate() {
426 println!(" {}. {}", i + 1, rec);
427 }
428 }
429}
430
431#[derive(Debug)]
432enum VisualMenuChoice {
433 CodeStructureAnalysis,
434 PatternRecognition,
435 DependencyMapping,
436 VisualDiffAnalysis,
437 ASTreeVisualization,
438 SessionSummary,
439 ExportAnalysis,
440 Back,
441}
442
443pub fn process_visual_reasoning(edit: ModifiableEdit) -> Result<Result<(), String>> {
445 let mut visual_cli = VisualReasoningCLI::new();
446
447 match visual_cli.run_visual_analysis(&edit) {
448 Ok(()) => Ok(Ok(())),
449 Err(e) => Ok(Err(format!("Visual reasoning analysis failed: {}", e))),
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456 use crate::agents::gpt4_agent::ProposedEdit;
457
458 #[test]
459 fn test_visual_reasoning_cli_creation() {
460 let cli = VisualReasoningCLI::new();
461 assert!(!cli.operator_registry.is_empty());
462 assert!(cli.analysis_history.is_empty());
463 assert_eq!(cli.current_session.analysis_count, 0);
464 }
465
466 #[test]
467 fn test_visual_session_creation() {
468 let session = VisualSession {
469 session_id: "test_session".to_string(),
470 file_path: "test.rs".to_string(),
471 analysis_count: 0,
472 patterns_detected: Vec::new(),
473 confidence_scores: Vec::new(),
474 };
475
476 assert_eq!(session.session_id, "test_session");
477 assert_eq!(session.file_path, "test.rs");
478 assert_eq!(session.analysis_count, 0);
479 }
480
481 #[test]
482 fn test_visual_analysis_result_creation() {
483 let result = VisualAnalysisResult {
484 analysis_type: "test_analysis".to_string(),
485 visual_elements: vec!["element1".to_string()],
486 relationships: vec!["rel1".to_string()],
487 complexity_score: 0.8,
488 confidence: 0.9,
489 symbolic_mapping: SymbolicContext::new(),
490 recommendations: vec!["recommendation1".to_string()],
491 timestamp: 12345,
492 };
493
494 assert_eq!(result.analysis_type, "test_analysis");
495 assert_eq!(result.visual_elements.len(), 1);
496 assert_eq!(result.complexity_score, 0.8);
497 assert_eq!(result.confidence, 0.9);
498 }
499
500 #[test]
501 #[ignore] fn test_process_visual_reasoning_function() {
503 let proposed_edit = ProposedEdit {
506 file: "test.rs".to_string(),
507 line_range: (1, 2),
508 new_code: "// test".to_string(),
509 reason: "Test".to_string(),
510 confidence: 0.8,
511 };
512
513 let modifiable_edit = ModifiableEdit::from_proposed_edit(proposed_edit);
514 let _result = process_visual_reasoning(modifiable_edit);
515 assert!(true, "Function exists and compiles");
516 }
517
518 #[test]
519 fn test_pattern_detection_helper() {
520 let cli = VisualReasoningCLI::new();
521
522 let rust_code = "fn main() {\n struct MyStruct;\n impl MyStruct {}\n}";
523 let patterns = cli.detect_code_patterns(rust_code);
524
525 assert!(patterns.contains(&"Function definitions".to_string()));
526 assert!(patterns.contains(&"Struct definitions".to_string()));
527 assert!(patterns.contains(&"Implementation blocks".to_string()));
528 }
529
530 #[test]
531 fn test_dependency_extraction_helper() {
532 let cli = VisualReasoningCLI::new();
533
534 let rust_code = "use std::collections::HashMap;\nuse serde::Serialize;\nfn main() {}";
535 let deps = cli.extract_dependencies(rust_code);
536
537 assert!(deps.contains(&"std".to_string()));
538 assert!(deps.contains(&"serde".to_string()));
539 assert_eq!(deps.len(), 2);
540 }
541}