diff --git a/src/memory/query_rewriter.rs b/src/memory/query_rewriter.rs index da9ce47..8051e29 100644 --- a/src/memory/query_rewriter.rs +++ b/src/memory/query_rewriter.rs @@ -94,7 +94,7 @@ fn format_history(messages: &[ChatMessage]) -> String { .iter() .filter_map(|m| { m.content.as_ref().map(|c| { - let snippet = crate::utils::str::truncate_chars(c, 200); + let snippet = crate::utils::strings::truncate_chars(c, 200); format!("{}: {}", m.role, snippet) }) }) diff --git a/src/memory/rag.rs b/src/memory/rag.rs index c11a834..c5eca1d 100644 --- a/src/memory/rag.rs +++ b/src/memory/rag.rs @@ -42,7 +42,7 @@ pub async fn auto_retrieve_context( for msg in &results { if let Some(content) = &msg.content { let role = &msg.role; - let snippet = crate::utils::str::truncate_chars(content, 300); + let snippet = crate::utils::strings::truncate_chars(content, 300); block.push_str(&format!("[{}] {}\n", role, snippet)); } } @@ -136,8 +136,8 @@ mod tests { async fn test_auto_retrieve_truncates_long_snippets() { // Verify the 300-char truncation logic via truncate_chars let content = "x".repeat(500); - let snippet = crate::utils::str::truncate_chars(&content, 300); - assert_eq!(snippet.len(), 303); // 300 + "..." + let snippet = crate::utils::strings::truncate_chars(&content, 300); + assert_eq!(snippet.chars().count(), 303); // 300 chars + "..." assert!(snippet.ends_with("...")); } @@ -147,7 +147,7 @@ mod tests { // content longer than 300 bytes with Chinese characters. // Old &content[..300] would panic here. let long_chinese = "每日論文摘要(香港時間)人工智能".repeat(25); // ~400 chars, >1200 bytes - let result = crate::utils::str::truncate_chars(&long_chinese, 300); + let result = crate::utils::strings::truncate_chars(&long_chinese, 300); assert!(result.ends_with("..."), "should be truncated"); assert!( std::str::from_utf8(result.as_bytes()).is_ok(), diff --git a/src/platform/tool_notifier.rs b/src/platform/tool_notifier.rs index 11baa25..7a7124d 100644 --- a/src/platform/tool_notifier.rs +++ b/src/platform/tool_notifier.rs @@ -29,14 +29,14 @@ pub fn format_args_preview(args_json: &str) -> String { serde_json::Value::String(s) => s.clone(), other => other.to_string(), }; - let truncated = crate::utils::str::truncate_chars(&s, 60); + let truncated = crate::utils::strings::truncate_chars(&s, 60); return format!("\"{}\"", truncated); } } } } // Fallback: truncate raw JSON - crate::utils::str::truncate_chars(args_json, 60) + crate::utils::strings::truncate_chars(args_json, 60) } /// Manages the live-edited Telegram status message during agent tool execution. diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3bb9df5..e8dfd78 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1 @@ -pub mod str; +pub mod strings; diff --git a/src/utils/str.rs b/src/utils/strings.rs similarity index 86% rename from src/utils/str.rs rename to src/utils/strings.rs index 0cf4039..408eca6 100644 --- a/src/utils/str.rs +++ b/src/utils/strings.rs @@ -60,4 +60,12 @@ mod tests { assert!(result.ends_with("...")); assert!(std::str::from_utf8(result.as_bytes()).is_ok()); } + + #[test] + fn test_truncate_chars_zero_max() { + // max_chars=0: every non-empty string is truncated immediately to "..." + assert_eq!(truncate_chars("hello", 0), "..."); + // Empty string is never truncated (loop body never entered) + assert_eq!(truncate_chars("", 0), ""); + } }