Skip to main content

lean_ctx/tools/
ctx_response.rs

1use crate::core::tokens::count_tokens;
2use crate::tools::CrpMode;
3
4pub fn handle(response: &str, crp_mode: CrpMode) -> String {
5    handle_with_context(response, crp_mode, None)
6}
7
8pub fn handle_with_context(
9    response: &str,
10    crp_mode: CrpMode,
11    input_context: Option<&str>,
12) -> String {
13    let original_tokens = count_tokens(response);
14
15    if original_tokens <= 100 {
16        return response.to_string();
17    }
18
19    let compressed = if crp_mode.is_tdd() {
20        compress_tdd(response, input_context)
21    } else {
22        compress_standard(response, input_context)
23    };
24
25    let compressed_tokens = count_tokens(&compressed);
26    let savings = original_tokens.saturating_sub(compressed_tokens);
27    let pct = if original_tokens > 0 {
28        (savings as f64 / original_tokens as f64 * 100.0).round() as usize
29    } else {
30        0
31    };
32
33    if pct < 3 {
34        return response.to_string();
35    }
36
37    crate::core::protocol::append_savings(&compressed, original_tokens, compressed_tokens)
38}
39
40fn compress_standard(text: &str, input_context: Option<&str>) -> String {
41    let echo_lines = input_context.map(build_echo_set);
42
43    let mut result = Vec::new();
44    let mut prev_empty = false;
45
46    for line in text.lines() {
47        let trimmed = line.trim();
48
49        if trimmed.is_empty() {
50            if !prev_empty {
51                result.push(String::new());
52                prev_empty = true;
53            }
54            continue;
55        }
56        prev_empty = false;
57
58        if is_filler_line(trimmed) {
59            continue;
60        }
61        if is_boilerplate_code(trimmed) {
62            continue;
63        }
64        if let Some(ref echoes) = echo_lines {
65            if is_context_echo(trimmed, echoes) {
66                continue;
67            }
68        }
69
70        result.push(line.to_string());
71    }
72
73    result.join("\n")
74}
75
76fn compress_tdd(text: &str, input_context: Option<&str>) -> String {
77    let echo_lines = input_context.map(build_echo_set);
78
79    let mut result = Vec::new();
80    let mut prev_empty = false;
81
82    for line in text.lines() {
83        let trimmed = line.trim();
84
85        if trimmed.is_empty() {
86            if !prev_empty {
87                prev_empty = true;
88            }
89            continue;
90        }
91        prev_empty = false;
92
93        if is_filler_line(trimmed) {
94            continue;
95        }
96        if is_boilerplate_code(trimmed) {
97            continue;
98        }
99        if let Some(ref echoes) = echo_lines {
100            if is_context_echo(trimmed, echoes) {
101                continue;
102            }
103        }
104
105        let compressed = apply_tdd_shortcuts(trimmed);
106        result.push(compressed);
107    }
108
109    result.join("\n")
110}
111
112fn build_echo_set(context: &str) -> std::collections::HashSet<String> {
113    context
114        .lines()
115        .map(normalize_for_echo)
116        .filter(|l| l.len() > 10)
117        .collect()
118}
119
120fn normalize_for_echo(line: &str) -> String {
121    line.trim().to_lowercase().replace(char::is_whitespace, " ")
122}
123
124fn is_context_echo(line: &str, echo_set: &std::collections::HashSet<String>) -> bool {
125    let normalized = normalize_for_echo(line);
126    if normalized.len() <= 10 {
127        return false;
128    }
129    echo_set.contains(&normalized)
130}
131
132fn is_boilerplate_code(line: &str) -> bool {
133    let trimmed = line.trim();
134
135    if trimmed.starts_with("//")
136        && !trimmed.starts_with("// TODO")
137        && !trimmed.starts_with("// FIXME")
138        && !trimmed.starts_with("// SAFETY")
139        && !trimmed.starts_with("// NOTE")
140    {
141        let comment_body = trimmed.trim_start_matches("//").trim();
142        if is_narration_comment(comment_body) {
143            return true;
144        }
145    }
146
147    if trimmed.starts_with('#') && !trimmed.starts_with("#[") && !trimmed.starts_with("#!") {
148        let comment_body = trimmed.trim_start_matches('#').trim();
149        if is_narration_comment(comment_body) {
150            return true;
151        }
152    }
153
154    false
155}
156
157fn is_narration_comment(body: &str) -> bool {
158    let b = body.to_lowercase();
159
160    let what_prefixes = [
161        "import ",
162        "define ",
163        "create ",
164        "set up ",
165        "initialize ",
166        "declare ",
167        "add ",
168        "get ",
169        "return ",
170        "check ",
171        "handle ",
172        "call ",
173        "update ",
174        "increment ",
175        "decrement ",
176        "loop ",
177        "iterate ",
178        "print ",
179        "log ",
180        "convert ",
181        "parse ",
182        "read ",
183        "write ",
184        "send ",
185        "receive ",
186        "validate ",
187        "set ",
188        "start ",
189        "stop ",
190        "open ",
191        "close ",
192        "fetch ",
193        "load ",
194        "save ",
195        "store ",
196        "delete ",
197        "remove ",
198        "calculate ",
199        "compute ",
200        "render ",
201        "display ",
202        "show ",
203        "this function ",
204        "this method ",
205        "this class ",
206        "the following ",
207        "here we ",
208        "now we ",
209    ];
210    if what_prefixes.iter().any(|p| b.starts_with(p)) {
211        return true;
212    }
213
214    let what_patterns = [" the ", " a ", " an "];
215    if b.len() < 60 && what_patterns.iter().all(|p| !b.contains(p)) {
216        return false;
217    }
218    if b.len() < 40
219        && b.split_whitespace().count() <= 5
220        && b.chars().filter(|c| c.is_uppercase()).count() == 0
221    {
222        return false;
223    }
224
225    false
226}
227
228fn is_filler_line(line: &str) -> bool {
229    let l = line.to_lowercase();
230
231    // Preserve lines with genuine information signals
232    if l.starts_with("note:")
233        || l.starts_with("hint:")
234        || l.starts_with("warning:")
235        || l.starts_with("error:")
236        || l.starts_with("however,")
237        || l.starts_with("but ")
238        || l.starts_with("caution:")
239        || l.starts_with("important:")
240    {
241        return false;
242    }
243
244    // H=0 patterns: carry zero task-relevant information
245    let prefix_fillers = [
246        // Narration / preamble
247        "here's what i",
248        "here is what i",
249        "let me explain",
250        "let me walk you",
251        "let me break",
252        "i'll now",
253        "i will now",
254        "i'm going to",
255        "first, let me",
256        "allow me to",
257        // Hedging
258        "i think",
259        "i believe",
260        "i would say",
261        "it seems like",
262        "it looks like",
263        "it appears that",
264        // Meta-commentary
265        "that's a great question",
266        "that's an interesting",
267        "good question",
268        "great question",
269        "sure thing",
270        "sure,",
271        "of course,",
272        "absolutely,",
273        // Transitions (zero-info)
274        "now, let's",
275        "now let's",
276        "next, i'll",
277        "moving on",
278        "going forward",
279        "with that said",
280        "with that in mind",
281        "having said that",
282        "that being said",
283        // Closings
284        "hope this helps",
285        "i hope this",
286        "let me know if",
287        "feel free to",
288        "don't hesitate",
289        "happy to help",
290        // Filler connectives
291        "as you can see",
292        "as we can see",
293        "this is because",
294        "the reason is",
295        "in this case",
296        "in other words",
297        "to summarize",
298        "to sum up",
299        "basically,",
300        "essentially,",
301        "it's worth noting",
302        "it should be noted",
303        "as mentioned",
304        "as i mentioned",
305        // Acknowledgments
306        "understood.",
307        "got it.",
308        "i understand.",
309        "i see.",
310        "right,",
311        "okay,",
312        "ok,",
313    ];
314
315    prefix_fillers.iter().any(|f| l.starts_with(f))
316}
317
318fn apply_tdd_shortcuts(line: &str) -> String {
319    let mut result = line.to_string();
320
321    let replacements = [
322        // Structural
323        ("function", "fn"),
324        ("configuration", "cfg"),
325        ("implementation", "impl"),
326        ("dependencies", "deps"),
327        ("dependency", "dep"),
328        ("request", "req"),
329        ("response", "res"),
330        ("context", "ctx"),
331        ("parameter", "param"),
332        ("argument", "arg"),
333        ("variable", "val"),
334        ("directory", "dir"),
335        ("repository", "repo"),
336        ("application", "app"),
337        ("environment", "env"),
338        ("description", "desc"),
339        ("information", "info"),
340        // Symbols (1 token each, replaces 5-10 tokens of prose)
341        ("returns ", "→ "),
342        ("therefore", "∴"),
343        ("approximately", "≈"),
344        ("successfully", "✓"),
345        ("completed", "✓"),
346        ("failed", "✗"),
347        ("warning", "⚠"),
348        // Operators
349        (" is not ", " ≠ "),
350        (" does not ", " ≠ "),
351        (" equals ", " = "),
352        (" and ", " & "),
353        ("error", "err"),
354        ("module", "mod"),
355        ("package", "pkg"),
356        ("initialize", "init"),
357    ];
358
359    for (from, to) in &replacements {
360        result = result.replace(from, to);
361    }
362
363    result
364}
365
366#[cfg(test)]
367mod tests {
368    use super::*;
369
370    #[test]
371    fn test_filler_detection_original() {
372        assert!(is_filler_line("Here's what I found"));
373        assert!(is_filler_line("Let me explain how this works"));
374        assert!(!is_filler_line("fn main() {}"));
375        assert!(!is_filler_line("Note: important detail"));
376    }
377
378    #[test]
379    fn test_filler_hedging_patterns() {
380        assert!(is_filler_line("I think the issue is here"));
381        assert!(is_filler_line("I believe this is correct"));
382        assert!(is_filler_line("It seems like the problem is"));
383        assert!(is_filler_line("It looks like we need to"));
384        assert!(is_filler_line("It appears that something broke"));
385    }
386
387    #[test]
388    fn test_filler_meta_commentary() {
389        assert!(is_filler_line("That's a great question!"));
390        assert!(is_filler_line("Good question, let me check"));
391        assert!(is_filler_line("Sure thing, I'll do that"));
392        assert!(is_filler_line("Of course, here's the code"));
393        assert!(is_filler_line("Absolutely, that makes sense"));
394    }
395
396    #[test]
397    fn test_filler_closings() {
398        assert!(is_filler_line("Hope this helps!"));
399        assert!(is_filler_line("Let me know if you need more"));
400        assert!(is_filler_line("Feel free to ask questions"));
401        assert!(is_filler_line("Don't hesitate to reach out"));
402        assert!(is_filler_line("Happy to help with anything"));
403    }
404
405    #[test]
406    fn test_filler_transitions() {
407        assert!(is_filler_line("Now, let's move on"));
408        assert!(is_filler_line("Moving on to the next part"));
409        assert!(is_filler_line("Going forward, we should"));
410        assert!(is_filler_line("With that said, here's what"));
411        assert!(is_filler_line("Having said that, let's"));
412    }
413
414    #[test]
415    fn test_filler_acknowledgments() {
416        assert!(is_filler_line("Understood."));
417        assert!(is_filler_line("Got it."));
418        assert!(is_filler_line("I understand."));
419        assert!(is_filler_line("I see."));
420    }
421
422    #[test]
423    fn test_filler_false_positive_protection() {
424        assert!(!is_filler_line("Note: this is critical"));
425        assert!(!is_filler_line("Warning: deprecated API"));
426        assert!(!is_filler_line("Error: connection refused"));
427        assert!(!is_filler_line("However, the edge case fails"));
428        assert!(!is_filler_line("But the second argument is wrong"));
429        assert!(!is_filler_line("Important: do not skip this step"));
430        assert!(!is_filler_line("Caution: this deletes all data"));
431        assert!(!is_filler_line("Hint: use --force flag"));
432        assert!(!is_filler_line("fn validate_token()"));
433        assert!(!is_filler_line("  let result = parse(input);"));
434        assert!(!is_filler_line("The token is expired after 24h"));
435    }
436
437    #[test]
438    fn test_tdd_shortcuts() {
439        let result = apply_tdd_shortcuts("the function returns successfully");
440        assert!(result.contains("fn"));
441        assert!(result.contains("→"));
442        assert!(result.contains("✓"));
443    }
444
445    #[test]
446    fn test_tdd_shortcuts_extended() {
447        let result = apply_tdd_shortcuts("the application environment failed");
448        assert!(result.contains("app"));
449        assert!(result.contains("env"));
450        assert!(result.contains("✗"));
451    }
452
453    #[test]
454    fn test_compress_integration() {
455        let response = "Let me explain how this works.\n\
456            I think this is correct.\n\
457            Hope this helps!\n\
458            \n\
459            The function returns an error when the token is expired.\n\
460            Note: always check the expiry first.";
461
462        let compressed = compress_standard(response, None);
463        assert!(!compressed.contains("Let me explain"));
464        assert!(!compressed.contains("I think"));
465        assert!(!compressed.contains("Hope this helps"));
466        assert!(compressed.contains("error when the token"));
467        assert!(compressed.contains("Note:"));
468    }
469
470    #[test]
471    fn test_echo_detection() {
472        let context = "fn shannon_entropy(text: &str) -> f64 {\n    let freq = HashMap::new();\n}";
473        let response = "Here's the code:\nfn shannon_entropy(text: &str) -> f64 {\n    let freq = HashMap::new();\n}\nI added the new function below.";
474
475        let compressed = compress_standard(response, Some(context));
476        assert!(!compressed.contains("fn shannon_entropy"));
477        assert!(compressed.contains("added the new function"));
478    }
479
480    #[test]
481    fn test_boilerplate_comment_removal() {
482        let response = "// Import the module\nuse std::io;\n// Define the function\nfn main() {}\n// NOTE: important edge case\nlet x = 1;";
483        let compressed = compress_standard(response, None);
484        assert!(!compressed.contains("Import the module"));
485        assert!(!compressed.contains("Define the function"));
486        assert!(compressed.contains("NOTE: important edge case"));
487        assert!(compressed.contains("use std::io"));
488        assert!(compressed.contains("fn main()"));
489    }
490}