replace ContainerRuntime CLI to Bollard crate (default: docker socket)
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
This commit is contained in:
2026-09-17 19:51:59 +00:00
parent 78ad2bf701
commit 624bc1e028
16 changed files with 1327 additions and 354 deletions
+81
View File
@@ -0,0 +1,81 @@
//! 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, "é");
}
}