diff --git a/src/agent/agent_loop.rs b/src/agent/agent_loop.rs index 26fd7d8..ffbedec 100644 --- a/src/agent/agent_loop.rs +++ b/src/agent/agent_loop.rs @@ -1055,8 +1055,8 @@ impl AgentLoop { let error = result.error.unwrap_or_default(); tracing::error!( tool = %tool_call.name, - args = %truncate_args(&tool_call.arguments, 2_000), - normalized_args = %truncate_args(&normalized_arguments, 2_000), + args = %truncate_args(&tool_call.arguments, 4_000), + normalized_args = %truncate_args(&normalized_arguments, 4_000), error = %error, output = %result.output, "Tool returned an error result" @@ -1067,8 +1067,8 @@ impl AgentLoop { Err(e) => { tracing::error!( tool = %tool_call.name, - args = %truncate_args(&tool_call.arguments, 2_000), - normalized_args = %truncate_args(&normalized_arguments, 2_000), + args = %truncate_args(&tool_call.arguments, 4_000), + normalized_args = %truncate_args(&normalized_arguments, 4_000), error = %e, error_details = %format!("{:#}", e), "Tool execution failed" diff --git a/src/observability/mod.rs b/src/observability/mod.rs index 11521e9..4e06af5 100644 --- a/src/observability/mod.rs +++ b/src/observability/mod.rs @@ -187,7 +187,14 @@ pub fn truncate_args(args: &serde_json::Value, max_len: usize) -> String { if args_str.len() <= max_len { return args_str; } - format!("{}...truncated", &args_str[..max_len]) + // Find the last valid char boundary before max_len to avoid splitting UTF-8 chars + let truncate_at = args_str + .char_indices() + .take_while(|(idx, _)| *idx < max_len) + .last() + .map(|(idx, c)| idx + c.len_utf8()) + .unwrap_or(0); + format!("{}...truncated", &args_str[..truncate_at]) } #[cfg(test)] @@ -288,4 +295,15 @@ mod tests { assert!(truncated.ends_with("...truncated")); assert!(truncated.len() < long_args.to_string().len()); } + + #[test] + fn test_truncate_args_utf8_boundary() { + // Test that truncation respects UTF-8 character boundaries + // Each Chinese character is 3 bytes in UTF-8 + let long_args = serde_json::json!({"key": "测试测试测试测试测试测试测试测试测试测试测试测试测试测试"}); + let truncated = truncate_args(&long_args, 50); + assert!(truncated.ends_with("...truncated")); + // Verify the truncated string is valid UTF-8 (no panic occurred) + assert!(truncated.is_char_boundary(truncated.len())); + } }