From bcbccecb3a745f3ecf0a2ebd1f7434d79f368a23 Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Tue, 4 Aug 2026 19:30:46 +0200 Subject: [PATCH] fix: sanitize Bedrock tool errors --- crates/goose/src/providers/formats/bedrock.rs | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/crates/goose/src/providers/formats/bedrock.rs b/crates/goose/src/providers/formats/bedrock.rs index d076f8e58d84..6a8a423037c9 100644 --- a/crates/goose/src/providers/formats/bedrock.rs +++ b/crates/goose/src/providers/formats/bedrock.rs @@ -261,11 +261,10 @@ pub fn to_bedrock_message_content(content: &MessageContent) -> Result>()?, ), Err(error) => { - // For errors, create a text content block with the error message - Some(vec![bedrock::ToolResultContentBlock::Text(format!( - "The tool call returned the following error:\n{}", - error - ))]) + let message = format!("The tool call returned the following error:\n{}", error); + Some(vec![bedrock::ToolResultContentBlock::Text( + crate::utils::sanitize_unicode_tags(&message), + )]) } }; bedrock::ContentBlock::ToolResult( @@ -1250,6 +1249,49 @@ mod tests { Ok(()) } + #[test] + fn tool_response_error_sanitizes_unicode_tags() -> Result<()> { + let error = ErrorData::new( + ErrorCode::INTERNAL_ERROR, + "visible\u{E0041}\u{E0042} error".to_string(), + None, + ); + let content = MessageContent::tool_response("call_hidden".to_string(), Err(error)); + + let bedrock::ContentBlock::ToolResult(result) = to_bedrock_message_content(&content)? + else { + panic!("expected ToolResult"); + }; + let bedrock::ToolResultContentBlock::Text(text) = &result.content[0] else { + panic!("expected text error content"); + }; + + assert!(!crate::utils::contains_unicode_tags(text.as_str())); + assert!(text.contains("visible error")); + Ok(()) + } + + #[test] + fn tool_response_error_preserves_ordinary_text() -> Result<()> { + let error = ErrorData::new( + ErrorCode::INTERNAL_ERROR, + "ordinary tool failure".to_string(), + None, + ); + let content = MessageContent::tool_response("call_error".to_string(), Err(error)); + + let bedrock::ContentBlock::ToolResult(result) = to_bedrock_message_content(&content)? + else { + panic!("expected ToolResult"); + }; + let bedrock::ToolResultContentBlock::Text(text) = &result.content[0] else { + panic!("expected text error content"); + }; + + assert!(text.contains("ordinary tool failure")); + Ok(()) + } + #[test] fn test_cache_points_with_tool_response_messages() -> Result<()> { use chrono::Utc;