agnt_tools/http.rs
1//! Shared HTTP client for tool use (Fetch, etc.).
2//!
3//! Separate from `agnt-net`'s LLM backend client so the two have independent
4//! connection pools. Tool fetches go to arbitrary user URLs; LLM calls go to
5//! a single provider. Different traffic patterns, different retry posture.
6
7use std::sync::{Arc, OnceLock};
8
9static AGENT: OnceLock<ureq::Agent> = OnceLock::new();
10
11/// Shared ureq Agent wired to a native-tls connector so HTTPS verifies
12/// against the system CA store (not the baked-in webpki-roots).
13///
14/// `redirects(0)` is set so the SSRF guard in `Fetch` cannot be bypassed by
15/// a `302 Location: http://169.254.169.254/…` hop — the model must re-fetch
16/// any redirect target explicitly, re-triggering validation.
17///
18/// Falls back to a plain ureq Agent (with TLS config) if `native-tls` init
19/// fails at runtime instead of panicking — addresses the S5 panic-removal
20/// pass for the first-HTTPS-call panic site.
21pub fn agent() -> &'static ureq::Agent {
22 AGENT.get_or_init(|| {
23 match native_tls::TlsConnector::new() {
24 Ok(connector) => ureq::AgentBuilder::new()
25 .tls_connector(Arc::new(connector))
26 .redirects(0)
27 .build(),
28 Err(_) => ureq::AgentBuilder::new().redirects(0).build(),
29 }
30 })
31}