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