/// The default bound on a verbatim block -- a tool call's input or its /// output. Short, because this text is a machine's and the reader is /// looking for one line of it. pub const VERBATIM_LINES: usize = 80; pub const VERBATIM_BYTES: usize = 4096; pub const MESSAGE_LINES: usize = 200; pub const MESSAGE_BYTES: usize = 16 * 1024; const _: () = assert!(VERBATIM_LINES > 0 && VERBATIM_BYTES > 0); const _: () = assert!(MESSAGE_LINES > 0 && MESSAGE_BYTES > 0); /// `text` cut to `max_lines` lines and `max_bytes` bytes, with the line /// count it was cut *from*; `None` when the whole of it fits. pub fn cut(text: &str, max_lines: usize, max_bytes: usize) -> Option<(&str, usize)> { debug_assert!( max_lines > 0 && max_bytes > 0, "a cap of nothing shows an empty block and a 'Show all' for every value there is", ); let by_lines = text .char_indices() .filter(|(_, c)| *c == '\n') .nth(max_lines - 1) .map(|(i, _)| i); let by_bytes = (text.len() > max_bytes).then(|| { let mut end = max_bytes; // Back up to a character boundary: a cut inside a multi-byte // character panics on the slice below, and a transcript is full of // them. while !text.is_char_boundary(end) { end -= 1; } end }); let cut = match (by_lines, by_bytes) { (Some(a), Some(b)) => a.min(b), (a, b) => a.or(b)?, }; Some((&text[..cut], text.lines().count())) } pub fn show_all_label(lines: usize) -> String { format!("Show all {lines} lines") } #[cfg(test)] mod tests { use super::*; #[test] fn text_under_both_bounds_is_not_cut() { assert_eq!(cut("one\ntwo\nthree", 80, 4096), None); } #[test] fn the_line_bound_cuts_at_a_line_boundary() { let text = "a\nb\nc\nd\n"; let (shown, lines) = cut(text, 2, 4096).expect("four lines is over a bound of two"); assert_eq!(shown, "a\nb"); assert_eq!( lines, 4, "the count is the whole text's, not the shown part's" ); } #[test] fn the_byte_bound_cuts_one_long_line() { let text = "x".repeat(5000); let (shown, lines) = cut(&text, 80, 4096).expect("5000 bytes is over a bound of 4096"); assert_eq!(shown.len(), 4096); assert_eq!(lines, 1); } #[test] fn the_tighter_of_the_two_bounds_wins() { let text = "aaaa\n".repeat(100); let (shown, _) = cut(&text, 80, 100).expect("over both"); assert_eq!(shown.len(), 100, "the byte bound is the tighter one here"); let (shown, _) = cut(&text, 4, 4096).expect("over the line bound"); assert_eq!(shown, "aaaa\naaaa\naaaa\naaaa"); } #[test] fn a_cut_inside_a_multibyte_character_backs_up_to_the_boundary() { let text = "é".repeat(100); let (shown, _) = cut(&text, 80, 11).expect("200 bytes is over a bound of 11"); assert_eq!( shown, "é".repeat(5), "11 bytes lands mid-character; 10 is the cut" ); } }