vtcode_core/tools/summarizers/
mod.rs1use anyhow::Result;
15
16use crate::utils::tokens::{estimate_tokens, truncate_to_tokens};
17
18pub mod execution;
19pub mod file_ops;
20pub mod search;
21
22use std::borrow::Cow;
23
24pub(super) fn truncate_line<'a>(line: &'a str, max_len: usize) -> Cow<'a, str> {
28 if line.len() <= max_len {
29 Cow::Borrowed(line)
30 } else {
31 let target = max_len.saturating_sub(3);
32 let end = line
33 .char_indices()
34 .map(|(i, _)| i)
35 .rfind(|&i| i <= target)
36 .unwrap_or(0);
37 Cow::Owned(format!("{}...", &line[..end]))
38 }
39}
40
41pub trait Summarizer {
46 fn summarize(&self, full_output: &str, metadata: Option<&serde_json::Value>) -> Result<String>;
55
56 fn estimate_savings(&self, full_output: &str, summary: &str) -> (usize, usize, f32) {
60 let ui_tokens = estimate_tokens(full_output);
61 let llm_tokens = estimate_tokens(summary);
62 let savings = ui_tokens.saturating_sub(llm_tokens);
63 let savings_pct = if ui_tokens > 0 {
64 (savings as f32 / ui_tokens as f32) * 100.0
65 } else {
66 0.0
67 };
68 (llm_tokens, ui_tokens, savings_pct)
69 }
70}
71
72pub fn extract_key_info(text: &str, max_lines: usize) -> String {
76 let mut lines: Vec<&str> = Vec::with_capacity(max_lines.min(32));
77 let mut total_lines = 0usize;
78 for line in text.lines() {
79 total_lines += 1;
80 if lines.len() < max_lines {
81 lines.push(line);
82 }
83 }
84
85 if total_lines > max_lines {
86 format!(
87 "{}\n[...{} more lines]",
88 lines.join("\n"),
89 total_lines - max_lines
90 )
91 } else {
92 lines.join("\n")
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_estimate_tokens() {
102 assert_eq!(estimate_tokens("Hello world"), 3); assert_eq!(estimate_tokens(""), 0);
104 assert_eq!(estimate_tokens("a".repeat(1000).as_str()), 250); }
106
107 #[test]
108 fn test_truncate_to_tokens() {
109 let text = "a".repeat(1000);
110 let truncated = truncate_to_tokens(&text, 50); assert!(truncated.len() <= 203); assert!(truncated.ends_with("..."));
113 }
114
115 #[test]
116 fn test_truncate_short_text() {
117 let text = "Short text";
118 let truncated = truncate_to_tokens(text, 100);
119 assert_eq!(truncated, text);
120 }
121
122 #[test]
123 fn test_extract_key_info() {
124 let text = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5";
125 let extracted = extract_key_info(text, 3);
126 assert!(extracted.contains("Line 1"));
127 assert!(extracted.contains("Line 3"));
128 assert!(extracted.contains("[...2 more lines]"));
129 }
130
131 #[test]
132 fn test_extract_key_info_exact() {
133 let text = "Line 1\nLine 2\nLine 3";
134 let extracted = extract_key_info(text, 3);
135 assert_eq!(extracted, text);
136 assert!(!extracted.contains("more lines"));
137 }
138}