diff --git a/src/harness/providers/openai/mod.rs b/src/harness/providers/openai/mod.rs index bbefe30..04568c7 100644 --- a/src/harness/providers/openai/mod.rs +++ b/src/harness/providers/openai/mod.rs @@ -76,7 +76,7 @@ use convert::*; use sse::*; #[cfg(test)] use transport::{ - auth_headers, effective_temperature, error_source_chain, glob_match, merge_provider_options, + auth_headers, effective_temperature, glob_match, merge_provider_options, merge_system_into_user, request_timeout, }; diff --git a/src/harness/providers/openai/test.rs b/src/harness/providers/openai/test.rs index 42147e6..5ae6268 100644 --- a/src/harness/providers/openai/test.rs +++ b/src/harness/providers/openai/test.rs @@ -1475,33 +1475,3 @@ fn merge_provider_options_prefers_overrides_and_handles_nulls() { json!(["top_k", 40]) ); } - -#[test] -fn error_source_chain_walks_all_causes() { - use std::fmt; - // A transport error whose outer Display hides the actionable errno one link - // down the `source()` chain (the reqwest/hyper shape). - #[derive(Debug)] - struct Outer(std::io::Error); - impl fmt::Display for Outer { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "error sending request for url (http://localhost:1234/)") - } - } - impl std::error::Error for Outer { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(&self.0) - } - } - let io = std::io::Error::new( - std::io::ErrorKind::ConnectionRefused, - "connection refused (os error 111)", - ); - let chain = error_source_chain(&Outer(io)); - assert!(chain.contains("error sending request for url (http://localhost:1234/)")); - assert!(chain.contains("connection refused (os error 111)")); - assert_eq!( - chain, - "error sending request for url (http://localhost:1234/): connection refused (os error 111)" - ); -} diff --git a/src/harness/providers/openai/transport.rs b/src/harness/providers/openai/transport.rs index bb0fb90..92a569f 100644 --- a/src/harness/providers/openai/transport.rs +++ b/src/harness/providers/openai/transport.rs @@ -877,12 +877,8 @@ impl OpenAiModel { url: &str, ) -> Result { let response = builder.send().await.map_err(|e| { - let error = self.provider_error( - format!("{what} to {url} failed: {}", error_source_chain(&e)), - None, - None, - None, - ); + let error = + self.provider_error(format!("{what} to {url} failed: {e}"), None, None, None); TinyAgentsError::Model(self.provider_failure_message(&error)) })?; @@ -992,27 +988,6 @@ pub(super) fn request_timeout(timeout_ms: Option, streaming: bool) -> Optio } } -/// Renders an error together with its full `source()` cause chain, joined by -/// `": "`. -/// -/// `reqwest`/`hyper` transport errors surface only their outermost context in -/// `Display` (e.g. `error sending request for url (...)`), while the actionable -/// detail — `connection refused (os error 111)`, a TLS failure, a DNS error — -/// lives one or more links down the `source()` chain. A plain `{e}` drops it, so -/// callers that classify on the message (loopback-offline detection, transport -/// retryability) never see it. Walking the chain here keeps the whole shape in -/// the `TinyAgentsError::Model` string. Pure, so it is unit-testable. -pub(super) fn error_source_chain(err: &dyn std::error::Error) -> String { - let mut rendered = err.to_string(); - let mut source = err.source(); - while let Some(inner) = source { - rendered.push_str(": "); - rendered.push_str(&inner.to_string()); - source = inner.source(); - } - rendered -} - /// Merges baked `defaults` under a request's own `overrides` provider options. /// /// Keys present in `overrides` win over `defaults`. A `Null` on either side