Skip to main content

open_agent/types/
http_headers.rs

1use super::AgentOptionsBuilder;
2use crate::{Error, Result};
3use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
4use std::collections::BTreeMap;
5
6impl AgentOptionsBuilder {
7    /// Adds a caller-supplied HTTP header to every model request.
8    ///
9    /// A later call with the same name replaces the earlier value, even when the casing differs.
10    /// Caller headers take precedence over the defaults selected by [`Self::protocol`].
11    /// Names and values are validated by [`Self::build`], which identifies the offending name
12    /// in its configuration error.
13    pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
14        let name = name.into();
15        self.headers
16            .retain(|existing, _| !existing.eq_ignore_ascii_case(&name));
17        self.headers.insert(name, value.into());
18        self
19    }
20}
21
22pub(super) fn validate(headers: &BTreeMap<String, String>) -> Result<()> {
23    // Deferring malformed metadata to `send()` turns a configuration defect into a
24    // request-time failure and makes the two public request paths fail at different points.
25    insert_all(&mut HeaderMap::new(), headers)
26}
27
28pub(crate) fn insert_all(target: &mut HeaderMap, headers: &BTreeMap<String, String>) -> Result<()> {
29    for (name, value) in headers {
30        let parsed_name = HeaderName::from_bytes(name.as_bytes())
31            .map_err(|_| Error::config(format!("Invalid HTTP header '{name}': invalid name")))?;
32        let parsed_value = HeaderValue::from_bytes(value.as_bytes())
33            .map_err(|_| Error::config(format!("Invalid HTTP header '{name}': invalid value")))?;
34        target.insert(parsed_name, parsed_value);
35    }
36    Ok(())
37}