lean_ctx/core/
adaptive.rs1use crate::core::cache::SessionCache;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum TaskComplexity {
5 Mechanical,
6 Standard,
7 Architectural,
8}
9
10impl TaskComplexity {
11 pub fn instruction_suffix(&self) -> &'static str {
12 match self {
13 TaskComplexity::Mechanical => {
14 "TASK COMPLEXITY: mechanical\n\
15 Minimal reasoning needed. Act immediately, report result in one line."
16 }
17 TaskComplexity::Standard => {
18 "TASK COMPLEXITY: standard\n\
19 Brief reasoning allowed. Summarize approach in 1-2 lines, then act."
20 }
21 TaskComplexity::Architectural => {
22 "TASK COMPLEXITY: architectural\n\
23 Full reasoning expected. Outline approach, consider edge cases, then act."
24 }
25 }
26 }
27
28 pub fn encoded_suffix(&self) -> String {
29 use crate::core::protocol::encode_instructions;
30 match self {
31 TaskComplexity::Mechanical => encode_instructions("mechanical"),
32 TaskComplexity::Standard => encode_instructions("standard"),
33 TaskComplexity::Architectural => encode_instructions("architectural"),
34 }
35 }
36}
37
38pub fn classify_from_context(cache: &SessionCache) -> TaskComplexity {
39 let stats = cache.get_stats();
40 let unique_files = cache.get_all_entries().len();
41 let total_reads = stats.total_reads;
42
43 if unique_files <= 1 && total_reads <= 3 {
44 return TaskComplexity::Mechanical;
45 }
46
47 if unique_files >= 5 || total_reads >= 15 {
48 return TaskComplexity::Architectural;
49 }
50
51 TaskComplexity::Standard
52}
53
54#[cfg(test)]
55pub fn classify_from_signals(
56 file_count: usize,
57 has_tests: bool,
58 has_multi_lang: bool,
59) -> TaskComplexity {
60 if has_tests && file_count >= 5 {
61 return TaskComplexity::Architectural;
62 }
63
64 if has_multi_lang || file_count >= 3 {
65 return TaskComplexity::Standard;
66 }
67
68 TaskComplexity::Mechanical
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_mechanical_classification() {
77 let result = classify_from_signals(1, false, false);
78 assert_eq!(result, TaskComplexity::Mechanical);
79 }
80
81 #[test]
82 fn test_standard_classification() {
83 let result = classify_from_signals(3, false, false);
84 assert_eq!(result, TaskComplexity::Standard);
85 }
86
87 #[test]
88 fn test_architectural_classification() {
89 let result = classify_from_signals(5, true, false);
90 assert_eq!(result, TaskComplexity::Architectural);
91 }
92
93 #[test]
94 fn test_multi_lang_triggers_standard() {
95 let result = classify_from_signals(1, false, true);
96 assert_eq!(result, TaskComplexity::Standard);
97 }
98
99 #[test]
100 fn test_instruction_suffix_not_empty() {
101 assert!(!TaskComplexity::Mechanical.instruction_suffix().is_empty());
102 assert!(!TaskComplexity::Standard.instruction_suffix().is_empty());
103 assert!(!TaskComplexity::Architectural
104 .instruction_suffix()
105 .is_empty());
106 }
107
108 #[test]
109 fn test_context_based_mechanical() {
110 let cache = SessionCache::new();
111 let result = classify_from_context(&cache);
112 assert_eq!(result, TaskComplexity::Mechanical);
113 }
114}