ci/woodpecker/push/tests Pipeline was successful
limit tool result to open router tool response (with truncated info for ai) Hard kill if graceful shutdown is too long
82 lines
2.0 KiB
Rust
82 lines
2.0 KiB
Rust
//! Small text helpers shared by the modules that log what the model answered and
|
|
//! bound what the tools return to it.
|
|
|
|
/// First `limit` characters of `text`, for logs.
|
|
///
|
|
/// Cuts on character boundaries, so the excerpt stays valid UTF-8, and marks a
|
|
/// truncation with an ellipsis.
|
|
pub fn excerpt(text: &str, limit: usize) -> String {
|
|
let mut chars = text.chars();
|
|
let excerpt = chars.by_ref().take(limit).collect::<String>();
|
|
|
|
if chars.next().is_some() {
|
|
return format!("{excerpt}…");
|
|
}
|
|
|
|
excerpt
|
|
}
|
|
|
|
/// Truncates `text` in place to at most `limit` bytes, cutting on a character
|
|
/// boundary so the result stays valid UTF-8.
|
|
///
|
|
/// Returns `true` when something was dropped.
|
|
pub fn truncate_bytes(text: &mut String, limit: usize) -> bool {
|
|
if text.len() <= limit {
|
|
return false;
|
|
}
|
|
|
|
let mut end = limit;
|
|
while !text.is_char_boundary(end) {
|
|
end -= 1;
|
|
}
|
|
|
|
text.truncate(end);
|
|
|
|
true
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn a_short_text_is_kept_as_is() {
|
|
assert_eq!(excerpt("abc", 3), "abc");
|
|
}
|
|
|
|
#[test]
|
|
fn a_long_text_is_truncated_and_marked() {
|
|
assert_eq!(excerpt("abcdef", 3), "abc…");
|
|
}
|
|
|
|
#[test]
|
|
fn truncation_cuts_on_character_boundaries() {
|
|
assert_eq!(excerpt("ééé", 2), "éé…");
|
|
}
|
|
|
|
#[test]
|
|
fn a_short_text_is_not_truncated() {
|
|
let mut text = String::from("abc");
|
|
|
|
assert!(!truncate_bytes(&mut text, 3));
|
|
assert_eq!(text, "abc");
|
|
}
|
|
|
|
#[test]
|
|
fn a_long_text_is_truncated_within_the_limit() {
|
|
let mut text = String::from("abcdef");
|
|
|
|
assert!(truncate_bytes(&mut text, 4));
|
|
assert_eq!(text, "abcd");
|
|
}
|
|
|
|
#[test]
|
|
fn byte_truncation_never_splits_a_character() {
|
|
let mut text = String::from("ééé");
|
|
|
|
// The limit falls in the middle of the second `é`: it is dropped.
|
|
assert!(truncate_bytes(&mut text, 3));
|
|
assert_eq!(text, "é");
|
|
}
|
|
}
|