diff --git a/src/agent/dispatcher.rs b/src/agent/dispatcher.rs index 95d8d711..94f69ae6 100644 --- a/src/agent/dispatcher.rs +++ b/src/agent/dispatcher.rs @@ -708,7 +708,7 @@ impl Agent { sanitized.was_modified, ) } - Err(e) => format!("Error: {}", e), + Err(e) => format!("Tool '{}' failed: {}", tc.name, e), }; context_messages.push(ChatMessage::tool_result( @@ -2028,4 +2028,25 @@ mod tests { let result = super::strip_internal_tool_call_text(input); assert_eq!(result, input); } + + #[test] + fn test_tool_error_format_includes_tool_name() { + // Regression test for issue #487: tool errors sent to the LLM should + // include the tool name so the model can reason about which tool failed + // and try alternatives. + let tool_name = "http"; + let err = crate::error::ToolError::ExecutionFailed { + name: tool_name.to_string(), + reason: "connection refused".to_string(), + }; + let formatted = format!("Tool '{}' failed: {}", tool_name, err); + assert!( + formatted.contains("Tool 'http' failed:"), + "Error should identify the tool by name, got: {formatted}" + ); + assert!( + formatted.contains("connection refused"), + "Error should include the underlying reason, got: {formatted}" + ); + } } diff --git a/src/skills/catalog.rs b/src/skills/catalog.rs index 2a2b69dc..93584f5f 100644 --- a/src/skills/catalog.rs +++ b/src/skills/catalog.rs @@ -457,12 +457,20 @@ mod tests { #[tokio::test] async fn test_search_returns_error_on_network_failure() { - // Point at an invalid URL to trigger a network error - let catalog = SkillCatalog::with_url("http://127.0.0.1:1"); + // Use RFC 5737 TEST-NET-1 (192.0.2.0/24) for reliable failure even behind proxies. + let catalog = SkillCatalog::with_url("http://192.0.2.1:9999"); let outcome = catalog.search("test").await; assert!(outcome.results.is_empty()); assert!(outcome.error.is_some()); - assert!(outcome.error.unwrap().contains("Registry unreachable")); + let error = outcome.error.unwrap(); + assert!( + error.contains("Registry unreachable") + || error.contains("connect") + || error.contains("502") + || error.contains("503") + || error.contains("504"), + "Expected connection or gateway error, got: {error}", + ); } #[tokio::test] diff --git a/src/tunnel/custom.rs b/src/tunnel/custom.rs index 888cb698..1cb71b0f 100644 --- a/src/tunnel/custom.rs +++ b/src/tunnel/custom.rs @@ -214,12 +214,16 @@ mod tests { #[tokio::test] async fn health_with_unreachable_url_is_false() { + // Use RFC 5737 TEST-NET-1 (192.0.2.0/24) for reliable failure even behind proxies. let tunnel = CustomTunnel::new( "sleep 1".into(), - Some("http://127.0.0.1:9/healthz".into()), + Some("http://192.0.2.1:9999/healthz".into()), None, ); - assert!(!tunnel.health_check().await); + assert!( + !tunnel.health_check().await, + "Health check should fail for unreachable URL" + ); } #[test]