1use crate::models::ComplexityLevel;
2
3#[derive(Debug, Clone)]
5pub struct ComplexityDetector {
6 threshold: ComplexityLevel,
8}
9
10impl ComplexityDetector {
11 pub fn new(threshold: ComplexityLevel) -> Self {
13 Self { threshold }
14 }
15
16 pub fn default_threshold() -> Self {
18 Self {
19 threshold: ComplexityLevel::Complex,
20 }
21 }
22
23 pub fn detect_complexity(&self, task_description: &str) -> ComplexityLevel {
25 let complexity_score = self.calculate_complexity_score(task_description);
26 self.score_to_complexity(complexity_score)
27 }
28
29 pub fn calculate_complexity_score(&self, task_description: &str) -> f32 {
31 let mut score = 0.0;
32
33 let word_count = task_description.split_whitespace().count() as f32;
35 score += (word_count / 100.0).min(2.0);
36
37 let complexity_keywords = [
39 "complex",
40 "difficult",
41 "challenging",
42 "intricate",
43 "sophisticated",
44 "algorithm",
45 "optimization",
46 "performance",
47 "architecture",
48 "design",
49 "refactor",
50 "restructure",
51 "integrate",
52 "coordinate",
53 "orchestrate",
54 "analyze",
55 "debug",
56 "troubleshoot",
57 "investigate",
58 "research",
59 "multiple",
60 "various",
61 "several",
62 "many",
63 "numerous",
64 "concurrent",
65 "parallel",
66 "async",
67 "distributed",
68 "scalable",
69 ];
70
71 for keyword in &complexity_keywords {
72 if task_description.to_lowercase().contains(keyword) {
73 score += 1.0;
74 }
75 }
76
77 let uncertainty_keywords = [
79 "unclear",
80 "ambiguous",
81 "uncertain",
82 "unknown",
83 "not sure",
84 "might",
85 "could",
86 "possibly",
87 "perhaps",
88 "maybe",
89 "question",
90 "problem",
91 "issue",
92 "bug",
93 "error",
94 ];
95
96 for keyword in &uncertainty_keywords {
97 if task_description.to_lowercase().contains(keyword) {
98 score += 0.5;
99 }
100 }
101
102 let requirement_indicators = ["and", "also", "additionally", "furthermore", "moreover"];
104 let requirement_count = requirement_indicators
105 .iter()
106 .filter(|indicator| task_description.to_lowercase().contains(*indicator))
107 .count() as f32;
108 score += (requirement_count / 5.0).min(1.0);
109
110 let technical_keywords = [
112 "algorithm",
113 "data structure",
114 "memory",
115 "performance",
116 "optimization",
117 "concurrency",
118 "threading",
119 "async",
120 "distributed",
121 "microservice",
122 "database",
123 "query",
124 "index",
125 "cache",
126 "transaction",
127 ];
128
129 for keyword in &technical_keywords {
130 if task_description.to_lowercase().contains(keyword) {
131 score += 1.5;
132 }
133 }
134
135 score
136 }
137
138 fn score_to_complexity(&self, score: f32) -> ComplexityLevel {
140 match score {
141 s if s < 2.0 => ComplexityLevel::Simple,
142 s if s < 5.0 => ComplexityLevel::Moderate,
143 _ => ComplexityLevel::Complex,
144 }
145 }
146
147 pub fn should_auto_enable(&self, complexity: ComplexityLevel) -> bool {
149 matches!(
150 (complexity, self.threshold),
151 (ComplexityLevel::Complex, _)
152 | (ComplexityLevel::Moderate, ComplexityLevel::Moderate)
153 | (ComplexityLevel::Moderate, ComplexityLevel::Simple)
154 )
155 }
156
157 pub fn set_threshold(&mut self, threshold: ComplexityLevel) {
159 self.threshold = threshold;
160 }
161
162 pub fn get_threshold(&self) -> ComplexityLevel {
164 self.threshold
165 }
166
167 pub fn analyze_task(&self, task_description: &str) -> ComplexityAnalysis {
169 let complexity = self.detect_complexity(task_description);
170 let score = self.calculate_complexity_score(task_description);
171 let should_enable = self.should_auto_enable(complexity);
172
173 ComplexityAnalysis {
174 complexity,
175 score,
176 should_enable_think_more: should_enable,
177 reasoning: self.generate_reasoning(task_description, complexity, score),
178 }
179 }
180
181 fn generate_reasoning(
183 &self,
184 task_description: &str,
185 complexity: ComplexityLevel,
186 score: f32,
187 ) -> String {
188 let mut reasoning = String::new();
189
190 reasoning.push_str(&format!("Complexity Level: {:?}\n", complexity));
191 reasoning.push_str(&format!("Complexity Score: {:.2}\n", score));
192
193 let mut factors = Vec::new();
195
196 let word_count = task_description.split_whitespace().count();
197 if word_count > 100 {
198 factors.push(format!("Long description ({} words)", word_count));
199 }
200
201 let complexity_keywords = [
202 "complex",
203 "difficult",
204 "challenging",
205 "intricate",
206 "sophisticated",
207 "algorithm",
208 "optimization",
209 "performance",
210 "architecture",
211 "design",
212 ];
213 let found_keywords: Vec<&str> = complexity_keywords
214 .iter()
215 .filter(|kw| task_description.to_lowercase().contains(*kw))
216 .copied()
217 .collect();
218 if !found_keywords.is_empty() {
219 factors.push(format!(
220 "Complex keywords found: {}",
221 found_keywords.join(", ")
222 ));
223 }
224
225 let technical_keywords = [
226 "algorithm",
227 "data structure",
228 "memory",
229 "performance",
230 "optimization",
231 "concurrency",
232 "threading",
233 "async",
234 "distributed",
235 ];
236 let found_technical: Vec<&str> = technical_keywords
237 .iter()
238 .filter(|kw| task_description.to_lowercase().contains(*kw))
239 .copied()
240 .collect();
241 if !found_technical.is_empty() {
242 factors.push(format!("Technical depth: {}", found_technical.join(", ")));
243 }
244
245 if factors.is_empty() {
246 reasoning.push_str("Factors: Simple task with straightforward requirements\n");
247 } else {
248 reasoning.push_str("Factors:\n");
249 for factor in factors {
250 reasoning.push_str(&format!(" - {}\n", factor));
251 }
252 }
253
254 reasoning
255 }
256}
257
258impl Default for ComplexityDetector {
259 fn default() -> Self {
260 Self::default_threshold()
261 }
262}
263
264#[derive(Debug, Clone)]
266pub struct ComplexityAnalysis {
267 pub complexity: ComplexityLevel,
269 pub score: f32,
271 pub should_enable_think_more: bool,
273 pub reasoning: String,
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn test_detector_creation() {
283 let detector = ComplexityDetector::new(ComplexityLevel::Complex);
284 assert_eq!(detector.get_threshold(), ComplexityLevel::Complex);
285 }
286
287 #[test]
288 fn test_default_threshold() {
289 let detector = ComplexityDetector::default_threshold();
290 assert_eq!(detector.get_threshold(), ComplexityLevel::Complex);
291 }
292
293 #[test]
294 fn test_detect_simple_task() {
295 let detector = ComplexityDetector::default();
296 let complexity = detector.detect_complexity("Write a simple function");
297 assert_eq!(complexity, ComplexityLevel::Simple);
298 }
299
300 #[test]
301 fn test_detect_moderate_task() {
302 let detector = ComplexityDetector::default();
303 let complexity = detector.detect_complexity(
304 "Implement a sorting algorithm with optimization and performance considerations",
305 );
306 assert!(matches!(
307 complexity,
308 ComplexityLevel::Moderate | ComplexityLevel::Complex
309 ));
310 }
311
312 #[test]
313 fn test_detect_complex_task() {
314 let detector = ComplexityDetector::default();
315 let complexity = detector.detect_complexity(
316 "Design and implement a distributed concurrent system with complex algorithm optimization, \
317 performance tuning, and architectural considerations for scalability"
318 );
319 assert_eq!(complexity, ComplexityLevel::Complex);
320 }
321
322 #[test]
323 fn test_should_auto_enable_complex() {
324 let detector = ComplexityDetector::new(ComplexityLevel::Complex);
325 assert!(detector.should_auto_enable(ComplexityLevel::Complex));
326 }
327
328 #[test]
329 fn test_should_not_auto_enable_simple() {
330 let detector = ComplexityDetector::new(ComplexityLevel::Complex);
331 assert!(!detector.should_auto_enable(ComplexityLevel::Simple));
332 }
333
334 #[test]
335 fn test_should_auto_enable_moderate_with_moderate_threshold() {
336 let detector = ComplexityDetector::new(ComplexityLevel::Moderate);
337 assert!(detector.should_auto_enable(ComplexityLevel::Moderate));
338 }
339
340 #[test]
341 fn test_set_threshold() {
342 let mut detector = ComplexityDetector::new(ComplexityLevel::Complex);
343 detector.set_threshold(ComplexityLevel::Simple);
344 assert_eq!(detector.get_threshold(), ComplexityLevel::Simple);
345 }
346
347 #[test]
348 fn test_analyze_task() {
349 let detector = ComplexityDetector::default();
350 let analysis = detector.analyze_task("Write a complex distributed system");
351 assert!(!analysis.reasoning.is_empty());
352 assert!(analysis.score > 0.0);
353 }
354
355 #[test]
356 fn test_complexity_keywords_detection() {
357 let detector = ComplexityDetector::default();
358 let score1 = detector.calculate_complexity_score("Simple task");
359 let score2 = detector.calculate_complexity_score("Complex algorithm optimization");
360 assert!(score2 > score1);
361 }
362
363 #[test]
364 fn test_technical_keywords_detection() {
365 let detector = ComplexityDetector::default();
366 let score1 = detector.calculate_complexity_score("Write code");
367 let score2 = detector.calculate_complexity_score("Implement concurrent distributed system");
368 assert!(score2 > score1);
369 }
370
371 #[test]
372 fn test_length_factor() {
373 let detector = ComplexityDetector::default();
374 let short = "Do something";
375 let long = "Do something very complex and intricate with many considerations and requirements and factors";
376 let score1 = detector.calculate_complexity_score(short);
377 let score2 = detector.calculate_complexity_score(long);
378 assert!(score2 > score1);
379 }
380
381 #[test]
382 fn test_default_implementation() {
383 let detector = ComplexityDetector::default();
384 assert_eq!(detector.get_threshold(), ComplexityLevel::Complex);
385 }
386
387 #[test]
388 fn test_score_to_complexity_simple() {
389 let detector = ComplexityDetector::default();
390 let complexity = detector.score_to_complexity(1.0);
391 assert_eq!(complexity, ComplexityLevel::Simple);
392 }
393
394 #[test]
395 fn test_score_to_complexity_moderate() {
396 let detector = ComplexityDetector::default();
397 let complexity = detector.score_to_complexity(3.0);
398 assert_eq!(complexity, ComplexityLevel::Moderate);
399 }
400
401 #[test]
402 fn test_score_to_complexity_complex() {
403 let detector = ComplexityDetector::default();
404 let complexity = detector.score_to_complexity(10.0);
405 assert_eq!(complexity, ComplexityLevel::Complex);
406 }
407
408 #[test]
409 fn test_analysis_includes_reasoning() {
410 let detector = ComplexityDetector::default();
411 let analysis = detector.analyze_task("Implement complex algorithm");
412 assert!(analysis.reasoning.contains("Complexity Level"));
413 assert!(analysis.reasoning.contains("Complexity Score"));
414 }
415}