diff --git a/crates/open_ai/src/responses.rs b/crates/open_ai/src/responses.rs index 6d6c903ea3..0a11d91e9f 100644 --- a/crates/open_ai/src/responses.rs +++ b/crates/open_ai/src/responses.rs @@ -743,7 +743,13 @@ pub async fn compact_response( )) .map_err(|error| RequestError::Other(error.into()))?; - let mut response = client.send(request).await?; + let mut response = client + .send(request) + .await + .map_err(|error| RequestError::HttpSend { + provider: provider_name.to_owned(), + error, + })?; let mut body = String::new(); response .body_mut() @@ -784,7 +790,13 @@ pub async fn stream_response( )) .map_err(|e| RequestError::Other(e.into()))?; - let mut response = client.send(request).await?; + let mut response = client + .send(request) + .await + .map_err(|error| RequestError::HttpSend { + provider: provider_name.to_owned(), + error, + })?; if response.status().is_success() { if is_streaming { let reader = BufReader::new(response.into_body()); @@ -1111,6 +1123,60 @@ mod tests { ); } + #[test] + fn stream_response_reports_http_send_errors() { + let http_client = + FakeHttpClient::create(|_| async move { Err(anyhow::anyhow!("DNS lookup failed")) }); + + let error = block_on(stream_response( + http_client.as_ref(), + "ChatGPT Subscription", + "https://chatgpt.com/backend-api/codex", + "secret", + response_test_request(), + &CustomHeaders::default(), + )); + let error = match error { + Ok(_) => panic!("expected request to fail"), + Err(error) => language_model_core::LanguageModelCompletionError::from(error), + }; + + match error { + language_model_core::LanguageModelCompletionError::HttpSend { provider, error } => { + assert_eq!(provider.0.as_ref(), "ChatGPT Subscription"); + assert_eq!(error.to_string(), "DNS lookup failed"); + } + error => panic!("expected an HTTP send error, got {error:?}"), + } + } + + #[test] + fn compact_response_reports_http_send_errors() { + let http_client = + FakeHttpClient::create(|_| async move { Err(anyhow::anyhow!("DNS lookup failed")) }); + + let error = block_on(compact_response( + http_client.as_ref(), + "ChatGPT Subscription", + "https://chatgpt.com/backend-api/codex", + "secret", + compact_test_request(), + &CustomHeaders::default(), + )); + let error = match error { + Ok(_) => panic!("expected request to fail"), + Err(error) => language_model_core::LanguageModelCompletionError::from(error), + }; + + match error { + language_model_core::LanguageModelCompletionError::HttpSend { provider, error } => { + assert_eq!(provider.0.as_ref(), "ChatGPT Subscription"); + assert_eq!(error.to_string(), "DNS lookup failed"); + } + error => panic!("expected an HTTP send error, got {error:?}"), + } + } + #[test] fn compacted_response_preserves_canonical_output_items() { let output = vec![ @@ -1308,4 +1374,25 @@ mod tests { service_tier: Some(ServiceTier::Priority), } } + + fn response_test_request() -> Request { + Request { + model: "gpt-5.4".to_string(), + instructions: None, + input: ResponseInput::new(Vec::new(), Vec::new()), + include: Vec::new(), + stream: true, + temperature: None, + top_p: None, + max_output_tokens: None, + parallel_tool_calls: None, + tool_choice: None, + tools: Vec::new(), + prompt_cache_key: None, + reasoning: None, + store: None, + service_tier: None, + context_management: None, + } + } }