1use anyhow::Result;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10use super::session::{SessionState, WorkflowStage};
11
12#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
14pub enum ConfidenceLevel {
15 Low = 1,
16 Medium = 2,
17 High = 3,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ToolSuggestion {
23 pub tool_name: String,
25 pub suggested_parameters: HashMap<String, serde_json::Value>,
27 pub confidence: ConfidenceLevel,
29 pub reasoning: String,
31 pub expected_outcome: String,
33 pub priority: u8,
35}
36
37impl ToolSuggestion {
38 pub fn new(
40 tool_name: String,
41 confidence: ConfidenceLevel,
42 reasoning: String,
43 expected_outcome: String,
44 priority: u8,
45 ) -> Self {
46 Self {
47 tool_name,
48 suggested_parameters: HashMap::new(),
49 confidence,
50 reasoning,
51 expected_outcome,
52 priority,
53 }
54 }
55
56 pub fn with_parameter(mut self, key: String, value: serde_json::Value) -> Self {
58 self.suggested_parameters.insert(key, value);
59 self
60 }
61
62 pub fn with_parameters(mut self, params: HashMap<String, serde_json::Value>) -> Self {
64 self.suggested_parameters.extend(params);
65 self
66 }
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct WorkflowSuggestion {
72 pub current_stage: WorkflowStage,
74 pub next_stage: Option<WorkflowStage>,
76 pub immediate_suggestions: Vec<ToolSuggestion>,
78 pub alternatives: Vec<ToolSuggestion>,
80 pub workflow_guidance: String,
82 pub progress_assessment: String,
84}
85
86impl WorkflowSuggestion {
87 pub fn for_stage(stage: WorkflowStage) -> Self {
89 let next_stage = stage.next_stage();
90 let workflow_guidance = Self::get_stage_guidance(&stage);
91 let progress_assessment = Self::assess_stage_progress(&stage);
92
93 Self {
94 current_stage: stage,
95 next_stage,
96 immediate_suggestions: Vec::new(),
97 alternatives: Vec::new(),
98 workflow_guidance,
99 progress_assessment,
100 }
101 }
102
103 fn get_stage_guidance(stage: &WorkflowStage) -> String {
105 match stage {
106 WorkflowStage::Discovery => {
107 "Focus on understanding the overall structure and scope of the codebase. \
108 Start with repository statistics and content exploration."
109 .to_string()
110 }
111 WorkflowStage::Mapping => {
112 "Map out the relationships between components. Use symbol search and \
113 dependency analysis to understand the architecture."
114 .to_string()
115 }
116 WorkflowStage::DeepDive => {
117 "Dive deep into specific areas of interest. Explain individual symbols \
118 and analyze complex patterns like inheritance hierarchies."
119 .to_string()
120 }
121 WorkflowStage::Synthesis => {
122 "Synthesize your findings with quality analysis. Look for complexity issues, \
123 security concerns, and opportunities for improvement."
124 .to_string()
125 }
126 }
127 }
128
129 fn assess_stage_progress(stage: &WorkflowStage) -> String {
131 match stage {
132 WorkflowStage::Discovery => {
133 "Building initial understanding of the codebase structure.".to_string()
134 }
135 WorkflowStage::Mapping => {
136 "Mapping relationships and understanding component interactions.".to_string()
137 }
138 WorkflowStage::DeepDive => {
139 "Analyzing specific components and complex patterns in detail.".to_string()
140 }
141 WorkflowStage::Synthesis => {
142 "Evaluating code quality and identifying improvement opportunities.".to_string()
143 }
144 }
145 }
146
147 pub fn add_suggestion(mut self, suggestion: ToolSuggestion) -> Self {
149 self.immediate_suggestions.push(suggestion);
150 self
151 }
152
153 pub fn add_alternative(mut self, suggestion: ToolSuggestion) -> Self {
155 self.alternatives.push(suggestion);
156 self
157 }
158
159 pub fn sort_by_priority(mut self) -> Self {
161 self.immediate_suggestions.sort_by_key(|s| s.priority);
162 self.alternatives.sort_by_key(|s| s.priority);
163 self
164 }
165}
166
167#[derive(Debug)]
169pub struct WorkflowContext {
170 session_state: SessionState,
172}
173
174impl WorkflowContext {
175 pub fn new(session_state: SessionState) -> Self {
177 Self { session_state }
178 }
179
180 pub fn generate_suggestions(&self) -> Result<WorkflowSuggestion> {
182 let stage = &self.session_state.current_stage;
183 let workflow_guidance = match stage {
184 WorkflowStage::Discovery => {
185 "Focus on understanding the overall structure and scope of the codebase."
186 }
187 WorkflowStage::Mapping => {
188 "Map relationships between components and understand architecture."
189 }
190 WorkflowStage::DeepDive => {
191 "Dive deep into specific areas of interest and analyze patterns."
192 }
193 WorkflowStage::Synthesis => {
194 "Synthesize findings with quality analysis and security review."
195 }
196 };
197
198 let immediate_suggestions = match stage {
200 WorkflowStage::Discovery => vec![ToolSuggestion::new(
201 "repository_stats".to_string(),
202 ConfidenceLevel::High,
203 "Get an overview of the repository structure".to_string(),
204 "Understanding of codebase size and organization".to_string(),
205 1,
206 )],
207 WorkflowStage::Mapping => vec![ToolSuggestion::new(
208 "search_symbols".to_string(),
209 ConfidenceLevel::High,
210 "Find key symbols in the codebase".to_string(),
211 "Discovery of main classes and functions".to_string(),
212 1,
213 )],
214 WorkflowStage::DeepDive => vec![ToolSuggestion::new(
215 "explain_symbol".to_string(),
216 ConfidenceLevel::High,
217 "Analyze specific symbols in detail".to_string(),
218 "Deep understanding of symbol implementation".to_string(),
219 1,
220 )],
221 WorkflowStage::Synthesis => vec![ToolSuggestion::new(
222 "analyze_complexity".to_string(),
223 ConfidenceLevel::High,
224 "Evaluate code complexity and quality".to_string(),
225 "Assessment of code maintainability".to_string(),
226 1,
227 )],
228 };
229
230 Ok(WorkflowSuggestion {
231 current_stage: stage.clone(),
232 next_stage: stage.next_stage(),
233 immediate_suggestions,
234 alternatives: vec![],
235 workflow_guidance: workflow_guidance.to_string(),
236 progress_assessment: "Analysis in progress".to_string(),
237 })
238 }
239
240 pub fn suggest_for_symbol(&self, symbol_id: &str) -> Result<Vec<ToolSuggestion>> {
242 let mut suggestions = Vec::new();
243
244 suggestions.push(
246 ToolSuggestion::new(
247 "explain_symbol".to_string(),
248 ConfidenceLevel::High,
249 format!("Get detailed explanation of symbol {}", symbol_id),
250 "Complete understanding of symbol implementation and context".to_string(),
251 1,
252 )
253 .with_parameter(
254 "symbol_id".to_string(),
255 serde_json::Value::String(symbol_id.to_string()),
256 )
257 .with_parameter(
258 "include_dependencies".to_string(),
259 serde_json::Value::Bool(true),
260 )
261 .with_parameter("include_usages".to_string(), serde_json::Value::Bool(true)),
262 );
263
264 suggestions.push(
266 ToolSuggestion::new(
267 "find_references".to_string(),
268 ConfidenceLevel::High,
269 format!("Find all references to symbol {}", symbol_id),
270 "Understanding of how and where the symbol is used".to_string(),
271 2,
272 )
273 .with_parameter(
274 "symbol_id".to_string(),
275 serde_json::Value::String(symbol_id.to_string()),
276 ),
277 );
278
279 suggestions.push(
281 ToolSuggestion::new(
282 "find_dependencies".to_string(),
283 ConfidenceLevel::Medium,
284 format!("Analyze dependencies for symbol {}", symbol_id),
285 "Understanding of what the symbol depends on".to_string(),
286 3,
287 )
288 .with_parameter(
289 "target".to_string(),
290 serde_json::Value::String(symbol_id.to_string()),
291 ),
292 );
293
294 Ok(suggestions)
295 }
296
297 pub fn suggest_alternatives(&self) -> Result<Vec<ToolSuggestion>> {
299 let current_stage = &self.session_state.current_stage;
300
301 match current_stage {
302 WorkflowStage::Discovery => Ok(vec![ToolSuggestion::new(
303 "search_content".to_string(),
304 ConfidenceLevel::Medium,
305 "Search for specific terms or concepts in the codebase".to_string(),
306 "Targeted discovery of relevant code sections".to_string(),
307 1,
308 )]),
309 WorkflowStage::Mapping => Ok(vec![ToolSuggestion::new(
310 "trace_path".to_string(),
311 ConfidenceLevel::Medium,
312 "Find connections between discovered symbols".to_string(),
313 "Understanding of execution paths and symbol relationships".to_string(),
314 1,
315 )]),
316 WorkflowStage::DeepDive => Ok(vec![ToolSuggestion::new(
317 "analyze_transitive_dependencies".to_string(),
318 ConfidenceLevel::Medium,
319 "Analyze complex dependency chains".to_string(),
320 "Understanding of indirect dependencies and potential cycles".to_string(),
321 1,
322 )]),
323 WorkflowStage::Synthesis => Ok(vec![ToolSuggestion::new(
324 "analyze_performance".to_string(),
325 ConfidenceLevel::Medium,
326 "Evaluate performance characteristics of the code".to_string(),
327 "Performance assessment and optimization opportunities".to_string(),
328 1,
329 )]),
330 }
331 }
332
333 pub fn suggest_batch_analysis(&self) -> Result<Vec<String>> {
335 let current_stage = &self.session_state.current_stage;
336
337 match current_stage {
338 WorkflowStage::Discovery => Ok(vec![
339 "repository_stats".to_string(),
340 "search_symbols".to_string(),
341 "content_stats".to_string(),
342 ]),
343 WorkflowStage::Mapping => Ok(vec![
344 "trace_path".to_string(),
345 "find_dependencies".to_string(),
346 "detect_patterns".to_string(),
347 ]),
348 WorkflowStage::DeepDive => Ok(vec![
349 "explain_symbol".to_string(),
350 "trace_data_flow".to_string(),
351 "find_references".to_string(),
352 ]),
353 WorkflowStage::Synthesis => Ok(vec![
354 "analyze_complexity".to_string(),
355 "analyze_security".to_string(),
356 "analyze_performance".to_string(),
357 ]),
358 }
359 }
360
361 pub fn assess_stage_completion(&self) -> Result<WorkflowStageAssessment> {
363 let current_stage = &self.session_state.current_stage;
364 let completed_tools = &self.session_state.history;
365
366 let stage_tools = self.suggest_batch_analysis()?;
368 let completed_stage_tools = completed_tools
369 .records
370 .iter()
371 .filter(|entry| stage_tools.contains(&entry.tool_name) && entry.success)
372 .count();
373
374 let completion_percentage = if stage_tools.is_empty() {
375 100.0
376 } else {
377 (completed_stage_tools as f64 / stage_tools.len() as f64) * 100.0
378 };
379
380 let is_ready_for_next = completion_percentage >= 60.0;
381 let next_stage = if is_ready_for_next {
382 current_stage.next_stage()
383 } else {
384 None
385 };
386
387 Ok(WorkflowStageAssessment {
388 current_stage: current_stage.clone(),
389 completion_percentage,
390 completed_tools: completed_stage_tools,
391 total_stage_tools: stage_tools.len(),
392 is_ready_for_next_stage: is_ready_for_next,
393 next_stage,
394 missing_tools: stage_tools
395 .into_iter()
396 .filter(|tool| {
397 !completed_tools
398 .records
399 .iter()
400 .any(|entry| &entry.tool_name == tool && entry.success)
401 })
402 .collect(),
403 recommendations: generate_stage_recommendations(current_stage, completion_percentage),
404 })
405 }
406
407 pub fn suggest_workflow_optimizations(&self) -> Result<Vec<WorkflowOptimization>> {
409 let analysis_history = &self.session_state.history;
410 let mut optimizations = Vec::new();
411
412 let analysis_tools = analysis_history
414 .records
415 .iter()
416 .filter(|entry| {
417 [
418 "analyze_complexity",
419 "analyze_security",
420 "analyze_performance",
421 ]
422 .contains(&entry.tool_name.as_str())
423 })
424 .collect::<Vec<_>>();
425
426 if analysis_tools.len() > 1 {
427 optimizations.push(WorkflowOptimization {
428 optimization_type: "parallelization".to_string(),
429 description: "Analysis tools can be run in parallel for better performance"
430 .to_string(),
431 affected_tools: analysis_tools.iter().map(|e| e.tool_name.clone()).collect(),
432 estimated_time_savings: 30.0,
433 implementation: "Use batch_analysis tool with parallel execution strategy"
434 .to_string(),
435 });
436 }
437
438 let mut tool_counts = std::collections::HashMap::new();
440 for entry in &analysis_history.records {
441 *tool_counts.entry(&entry.tool_name).or_insert(0) += 1;
442 }
443
444 for (tool_name, count) in tool_counts {
445 if count > 2 {
446 optimizations.push(WorkflowOptimization {
447 optimization_type: "deduplication".to_string(),
448 description: format!(
449 "{} has been called {} times - consider caching results",
450 tool_name, count
451 ),
452 affected_tools: vec![tool_name.clone()],
453 estimated_time_savings: 15.0,
454 implementation: "Enable result caching to avoid redundant analysis".to_string(),
455 });
456 }
457 }
458
459 Ok(optimizations)
460 }
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct WorkflowStageAssessment {
466 pub current_stage: WorkflowStage,
468 pub completion_percentage: f64,
470 pub completed_tools: usize,
472 pub total_stage_tools: usize,
474 pub is_ready_for_next_stage: bool,
476 pub next_stage: Option<WorkflowStage>,
478 pub missing_tools: Vec<String>,
480 pub recommendations: Vec<String>,
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize)]
486pub struct WorkflowOptimization {
487 pub optimization_type: String,
489 pub description: String,
491 pub affected_tools: Vec<String>,
493 pub estimated_time_savings: f64,
495 pub implementation: String,
497}
498
499fn generate_stage_recommendations(
501 stage: &WorkflowStage,
502 completion_percentage: f64,
503) -> Vec<String> {
504 let mut recommendations = Vec::new();
505
506 match stage {
507 WorkflowStage::Discovery => {
508 if completion_percentage < 50.0 {
509 recommendations.push("Start with repository_stats for overview".to_string());
510 recommendations.push("Use search_symbols to discover key components".to_string());
511 } else {
512 recommendations.push("Consider moving to Mapping stage".to_string());
513 }
514 }
515 WorkflowStage::Mapping => {
516 if completion_percentage < 50.0 {
517 recommendations.push("Use trace_path to understand relationships".to_string());
518 recommendations
519 .push("Run detect_patterns to identify architectural patterns".to_string());
520 } else {
521 recommendations.push("Ready for detailed analysis in DeepDive stage".to_string());
522 }
523 }
524 WorkflowStage::DeepDive => {
525 if completion_percentage < 50.0 {
526 recommendations.push("Use explain_symbol for detailed understanding".to_string());
527 recommendations.push("Trace data flow for complex operations".to_string());
528 } else {
529 recommendations.push("Consider quality analysis in Synthesis stage".to_string());
530 }
531 }
532 WorkflowStage::Synthesis => {
533 if completion_percentage < 50.0 {
534 recommendations.push("Run quality analysis tools".to_string());
535 recommendations.push("Perform security and performance analysis".to_string());
536 } else {
537 recommendations.push("Analysis complete - review findings".to_string());
538 }
539 }
540 }
541
542 recommendations
543}
544
545#[cfg(test)]
546mod tests {
547 use super::*;
548 use crate::context::session::SessionState;
549
550 #[test]
551 fn test_tool_suggestion_creation() {
552 let suggestion = ToolSuggestion::new(
553 "test_tool".to_string(),
554 ConfidenceLevel::High,
555 "Test reasoning".to_string(),
556 "Test outcome".to_string(),
557 1,
558 )
559 .with_parameter(
560 "param1".to_string(),
561 serde_json::Value::String("value1".to_string()),
562 );
563
564 assert_eq!(suggestion.tool_name, "test_tool");
565 assert_eq!(suggestion.confidence, ConfidenceLevel::High);
566 assert_eq!(suggestion.priority, 1);
567 assert!(suggestion.suggested_parameters.contains_key("param1"));
568 }
569
570 #[test]
571 fn test_workflow_suggestion_creation() {
572 let suggestion = WorkflowSuggestion::for_stage(WorkflowStage::Discovery);
573 assert_eq!(suggestion.current_stage, WorkflowStage::Discovery);
574 assert_eq!(suggestion.next_stage, Some(WorkflowStage::Mapping));
575 assert!(!suggestion.workflow_guidance.is_empty());
576 }
577
578 #[test]
579 fn test_workflow_context() {
580 let session = SessionState::new();
581 let context = WorkflowContext::new(session);
582
583 let suggestions = context.generate_suggestions().unwrap();
584 assert_eq!(suggestions.current_stage, WorkflowStage::Discovery);
585 assert!(!suggestions.immediate_suggestions.is_empty());
586 }
587
588 #[test]
589 fn test_symbol_suggestions() {
590 let session = SessionState::new();
591 let context = WorkflowContext::new(session);
592
593 let suggestions = context.suggest_for_symbol("test_symbol").unwrap();
594 assert!(!suggestions.is_empty());
595 assert!(suggestions.iter().any(|s| s.tool_name == "explain_symbol"));
596 }
597
598 #[test]
599 fn test_confidence_ordering() {
600 assert!(ConfidenceLevel::High > ConfidenceLevel::Medium);
601 assert!(ConfidenceLevel::Medium > ConfidenceLevel::Low);
602 }
603}