feat: 优化响应截断逻辑,支持多字节字符边界处理,并添加相关单元测试

This commit is contained in:
ooodc 2026-05-01 16:07:20 +08:00
parent 716d92a618
commit fc5b2a359f
2 changed files with 28 additions and 4 deletions

View File

@ -4,6 +4,7 @@ use async_trait::async_trait;
use reqwest::header::HeaderMap; use reqwest::header::HeaderMap;
use serde_json::json; use serde_json::json;
use crate::text::take_prefix_chars;
use crate::tools::traits::{Tool, ToolResult}; use crate::tools::traits::{Tool, ToolResult};
pub struct HttpRequestTool { pub struct HttpRequestTool {
@ -93,10 +94,10 @@ impl HttpRequestTool {
return text.to_string(); return text.to_string();
} }
if text.len() > self.max_response_size { if text.chars().count() > self.max_response_size {
format!( format!(
"{}\n\n... [Response truncated due to size limit] ...", "{}\n\n... [Response truncated due to size limit] ...",
&text[..self.max_response_size] take_prefix_chars(text, self.max_response_size)
) )
} else { } else {
text.to_string() text.to_string()
@ -437,4 +438,15 @@ mod tests {
async fn test_blocks_local_tld() { async fn test_blocks_local_tld() {
assert!(is_private_host("service.local")); assert!(is_private_host("service.local"));
} }
#[tokio::test]
async fn test_truncate_response_handles_multibyte_boundary() {
let tool = HttpRequestTool::new(vec!["*".to_string()], 3, 30, false);
let text = "a\u{1F642}bc";
let truncated = tool.truncate_response(text);
assert_eq!(
truncated,
"a\u{1F642}b\n\n... [Response truncated due to size limit] ..."
);
}
} }

View File

@ -4,6 +4,7 @@ use async_trait::async_trait;
use reqwest::header::HeaderMap; use reqwest::header::HeaderMap;
use serde_json::json; use serde_json::json;
use crate::text::take_prefix_chars;
use crate::tools::traits::{Tool, ToolResult}; use crate::tools::traits::{Tool, ToolResult};
pub struct WebFetchTool { pub struct WebFetchTool {
@ -50,10 +51,10 @@ impl WebFetchTool {
return text.to_string(); return text.to_string();
} }
if text.len() > self.max_response_size { if text.chars().count() > self.max_response_size {
format!( format!(
"{}\n\n... [Response truncated due to size limit] ...", "{}\n\n... [Response truncated due to size limit] ...",
&text[..self.max_response_size] take_prefix_chars(text, self.max_response_size)
) )
} else { } else {
text.to_string() text.to_string()
@ -383,4 +384,15 @@ mod tests {
assert!(text.contains("Content")); assert!(text.contains("Content"));
assert!(!text.contains("color")); assert!(!text.contains("color"));
} }
#[tokio::test]
async fn test_truncate_response_handles_multibyte_boundary() {
let tool = WebFetchTool::new(3, 30);
let text = "a\u{1F642}bc";
let truncated = tool.truncate_response(text);
assert_eq!(
truncated,
"a\u{1F642}b\n\n... [Response truncated due to size limit] ..."
);
}
} }