lean_ctx/core/terse/
mcp_compress.rs1use super::dictionaries::{self, DictLevel};
9use crate::core::config::CompressionLevel;
10
11#[derive(Debug, Clone, Copy, PartialEq)]
13pub enum DescriptionMode {
14 Full,
15 Terse,
16 Lazy,
17}
18
19impl DescriptionMode {
20 pub fn from_compression_level(level: &CompressionLevel) -> Self {
21 match level {
22 CompressionLevel::Off | CompressionLevel::Lite => Self::Full,
23 CompressionLevel::Standard => Self::Terse,
24 CompressionLevel::Max => Self::Lazy,
25 }
26 }
27}
28
29pub fn compress_description(name: &str, description: &str, mode: DescriptionMode) -> String {
31 match mode {
32 DescriptionMode::Full => description.to_string(),
33 DescriptionMode::Terse => terse_description(description),
34 DescriptionMode::Lazy => lazy_description(name, description),
35 }
36}
37
38fn terse_description(desc: &str) -> String {
39 let abbreviated = dictionaries::apply_dictionaries(desc, DictLevel::General);
40
41 let mut lines: Vec<&str> = abbreviated.lines().collect();
42
43 lines.retain(|line| {
44 let trimmed = line.trim();
45 !trimmed.is_empty()
46 && !trimmed.starts_with("Example")
47 && !trimmed.starts_with("Note:")
48 && !trimmed.starts_with("See also")
49 });
50
51 if lines.len() > 3 {
52 lines.truncate(3);
53 }
54
55 lines.join("\n")
56}
57
58fn lazy_description(name: &str, desc: &str) -> String {
59 let first_line = desc.lines().next().unwrap_or(name);
60 let summary = if first_line.len() > 80 {
61 format!("{}…", &first_line[..77])
62 } else {
63 first_line.to_string()
64 };
65 format!("{summary} (use ctx_discover_tools for full docs)")
66}
67
68pub fn estimate_savings(descriptions: &[(&str, &str)], mode: DescriptionMode) -> (u32, u32) {
70 let mut total_before = 0u32;
71 let mut total_after = 0u32;
72
73 for (name, desc) in descriptions {
74 let before = super::counter::count(desc);
75 let compressed = compress_description(name, desc, mode);
76 let after = super::counter::count(&compressed);
77 total_before += before;
78 total_after += after;
79 }
80
81 (total_before, total_after)
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn full_mode_unchanged() {
90 let desc = "Read a file from disk with caching.";
91 assert_eq!(
92 compress_description("ctx_read", desc, DescriptionMode::Full),
93 desc
94 );
95 }
96
97 #[test]
98 fn terse_mode_abbreviates() {
99 let desc = "Read a configuration file from the directory.";
100 let result = compress_description("ctx_read", desc, DescriptionMode::Terse);
101 assert!(
102 result.contains("cfg") || result.contains("dir"),
103 "should abbreviate: {result}"
104 );
105 }
106
107 #[test]
108 fn lazy_mode_short() {
109 let desc = "Read a file from disk with intelligent caching and compression modes.\nSupports 10 different read modes for optimal token efficiency.";
110 let result = compress_description("ctx_read", desc, DescriptionMode::Lazy);
111 assert!(
112 result.contains("ctx_discover_tools"),
113 "lazy should reference ctx_discover_tools"
114 );
115 assert!(result.lines().count() == 1, "lazy should be 1 line");
116 }
117
118 #[test]
119 fn mode_from_compression_level() {
120 assert_eq!(
121 DescriptionMode::from_compression_level(&CompressionLevel::Off),
122 DescriptionMode::Full
123 );
124 assert_eq!(
125 DescriptionMode::from_compression_level(&CompressionLevel::Standard),
126 DescriptionMode::Terse
127 );
128 assert_eq!(
129 DescriptionMode::from_compression_level(&CompressionLevel::Max),
130 DescriptionMode::Lazy
131 );
132 }
133
134 #[test]
135 fn estimate_savings_returns_values() {
136 let descs = vec![
137 (
138 "ctx_read",
139 "Read a configuration file from the directory with caching.",
140 ),
141 (
142 "ctx_shell",
143 "Execute a shell command with pattern compression.",
144 ),
145 ];
146 let (before, after) = estimate_savings(&descs, DescriptionMode::Terse);
147 assert!(before > 0);
148 assert!(after > 0);
149 assert!(after <= before);
150 }
151}