hematite/agent/
truncation.rs1pub fn formatted_truncate(content: &str, max_bytes: usize) -> String {
5 if content.len() <= max_bytes {
6 return content.to_string();
7 }
8
9 let total_lines = content.lines().count();
10 let truncated = truncate_middle(content, max_bytes);
11
12 format!(
13 "[TRUNCATED: total lines: {}]\n{}\n[... middle truncated to fit budget ...]\n{}",
14 total_lines, truncated.head, truncated.tail
15 )
16}
17
18pub struct TruncatedOutput {
19 pub head: String,
20 pub tail: String,
21}
22
23pub fn truncate_middle(content: &str, max_bytes: usize) -> TruncatedOutput {
26 if content.len() <= max_bytes {
27 return TruncatedOutput {
28 head: content.to_string(),
29 tail: String::new(),
30 };
31 }
32
33 let head_size = (max_bytes as f32 * 0.4) as usize;
35 let tail_size = (max_bytes as f32 * 0.4) as usize;
36
37 let head_boundary = find_valid_boundary_forward(content, head_size);
39 let tail_boundary = find_valid_boundary_backward(content, content.len() - tail_size);
40
41 TruncatedOutput {
42 head: content[..head_boundary].to_string(),
43 tail: content[tail_boundary..].to_string(),
44 }
45}
46
47pub fn safe_head(s: &str, max_bytes: usize) -> &str {
49 let end = find_valid_boundary_forward(s, max_bytes.min(s.len()));
50 &s[..end]
51}
52
53pub fn safe_tail(s: &str, max_bytes: usize) -> &str {
55 if s.len() <= max_bytes {
56 return s;
57 }
58 let offset = s.len() - max_bytes;
59 let start = (offset..=s.len())
61 .find(|&i| s.is_char_boundary(i))
62 .unwrap_or(s.len());
63 &s[start..]
64}
65
66fn find_valid_boundary_forward(content: &str, target: usize) -> usize {
67 let mut pos = target;
68 while pos > 0 && !content.is_char_boundary(pos) {
69 pos -= 1;
70 }
71 pos
72}
73
74fn find_valid_boundary_backward(content: &str, target: usize) -> usize {
75 let mut pos = target;
76 while pos < content.len() && !content.is_char_boundary(pos) {
77 pos += 1;
78 }
79 pos
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_middle_truncation() {
88 let input = "1234567890";
89 let result = truncate_middle(input, 4);
90 assert_eq!(result.head, "1");
92 assert_eq!(result.tail, "0");
93 }
94
95 #[test]
96 fn test_utf8_boundary_safety() {
97 let input = "π¦π¦π¦π¦π¦"; let result = truncate_middle(input, 10);
99 assert_eq!(result.head, "π¦");
101 assert_eq!(result.tail, "π¦");
102 }
103}