From 34d6bb73c201c0d55d7fd37119863e48dfcfb1b7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:27:50 +0000 Subject: [PATCH 1/2] Initial plan From 75375ae4cf52689fe7b1b577f51bcc4835422968 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:38:23 +0000 Subject: [PATCH 2/2] refactor(utils): rename utils::str to utils::strings to avoid shadowing Rust primitive; fix rag test assertion to use chars().count(); add zero-max edge case test Co-authored-by: chinkan <16433287+chinkan@users.noreply.github.com> Agent-Logs-Url: https://github.com/chinkan/RustFox/sessions/df38c695-4336-437e-8324-5b6db9d2c378 --- src/memory/query_rewriter.rs | 2 +- src/memory/rag.rs | 8 ++++---- src/platform/tool_notifier.rs | 4 ++-- src/utils/mod.rs | 2 +- src/utils/{str.rs => strings.rs} | 8 ++++++++ 5 files changed, 16 insertions(+), 8 deletions(-) rename src/utils/{str.rs => strings.rs} (86%) 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), ""); + } }