|
| 1 | +// providers/http_util.rs — shared HTTP-client construction helpers for |
| 2 | +// provider adapters. |
| 3 | +// |
| 4 | +// Every provider needs a `reqwest::Client` with a long timeout (LLM calls |
| 5 | +// routinely run >60s). Before this module each constructor inlined |
| 6 | +// `Client::builder().timeout(...).build().expect("...")` which panicked |
| 7 | +// at startup on TLS-init failures. AGENTS.md forbids `.expect()` on |
| 8 | +// fallible production paths, so we centralize the build here and return |
| 9 | +// a structured `ProviderError` instead. |
| 10 | + |
| 11 | +use std::time::Duration; |
| 12 | + |
| 13 | +use claurst_core::provider_id::ProviderId; |
| 14 | + |
| 15 | +use crate::provider_error::ProviderError; |
| 16 | + |
| 17 | +/// Default timeout applied to every provider HTTP client. LLM streaming |
| 18 | +/// responses can take well over a minute; ten minutes is the standard |
| 19 | +/// upper bound across the adapters in this crate. |
| 20 | +pub const DEFAULT_PROVIDER_TIMEOUT: Duration = Duration::from_secs(600); |
| 21 | + |
| 22 | +/// Build a default `reqwest::Client` for a provider adapter, propagating |
| 23 | +/// any builder failure as a structured [`ProviderError::Other`] so the |
| 24 | +/// registry can skip the provider instead of crashing the process. |
| 25 | +pub fn build_default_http_client(provider: &ProviderId) -> Result<reqwest::Client, ProviderError> { |
| 26 | + reqwest::Client::builder() |
| 27 | + .timeout(DEFAULT_PROVIDER_TIMEOUT) |
| 28 | + .build() |
| 29 | + .map_err(|e| ProviderError::Other { |
| 30 | + provider: provider.clone(), |
| 31 | + message: format!("failed to build HTTP client: {e}"), |
| 32 | + status: None, |
| 33 | + body: None, |
| 34 | + }) |
| 35 | +} |
| 36 | + |
| 37 | +#[cfg(test)] |
| 38 | +mod tests { |
| 39 | + use super::*; |
| 40 | + |
| 41 | + #[test] |
| 42 | + fn build_default_http_client_succeeds_for_well_known_provider() { |
| 43 | + // Under normal conditions the reqwest builder succeeds; the test |
| 44 | + // primarily guards against a regression in the timeout arg or the |
| 45 | + // ProviderError mapping. |
| 46 | + let pid = ProviderId::new("test"); |
| 47 | + let client = build_default_http_client(&pid).expect("client must build"); |
| 48 | + // Smoke-check: the client is usable. |
| 49 | + let _ = client.get("http://127.0.0.1:1").build(); |
| 50 | + } |
| 51 | +} |
0 commit comments