claude_agent/client/
gateway.rs1use std::env;
4
5#[derive(Clone, Debug, Default)]
10pub struct GatewayConfig {
11 pub base_url: Option<String>,
13 pub auth_token: Option<String>,
15 pub custom_headers: Vec<(String, String)>,
17 pub disable_betas: bool,
19}
20
21impl GatewayConfig {
22 pub fn from_env() -> Option<Self> {
24 let base_url = env::var("ANTHROPIC_BASE_URL").ok();
25 let auth_token = env::var("ANTHROPIC_AUTH_TOKEN").ok();
26 let custom_headers = parse_custom_headers();
27 let disable_betas = env::var("CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS")
28 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
29 .unwrap_or(false);
30
31 if base_url.is_some() || auth_token.is_some() || !custom_headers.is_empty() {
32 Some(Self {
33 base_url,
34 auth_token,
35 custom_headers,
36 disable_betas,
37 })
38 } else {
39 None
40 }
41 }
42
43 pub fn with_base_url(url: impl Into<String>) -> Self {
45 Self {
46 base_url: Some(url.into()),
47 ..Default::default()
48 }
49 }
50
51 pub fn auth_token(mut self, token: impl Into<String>) -> Self {
53 self.auth_token = Some(token.into());
54 self
55 }
56
57 pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
59 self.custom_headers.push((name.into(), value.into()));
60 self
61 }
62
63 pub fn headers(mut self, headers: impl IntoIterator<Item = (String, String)>) -> Self {
65 self.custom_headers.extend(headers);
66 self
67 }
68
69 pub fn disable_betas(mut self) -> Self {
71 self.disable_betas = true;
72 self
73 }
74
75 pub fn is_active(&self) -> bool {
77 self.base_url.is_some() || self.auth_token.is_some()
78 }
79
80 pub fn effective_base_url(&self, default: &str) -> String {
82 self.base_url.clone().unwrap_or_else(|| default.to_string())
83 }
84
85 pub fn all_headers(&self) -> Vec<(String, String)> {
87 self.custom_headers.clone()
88 }
89}
90
91fn parse_custom_headers() -> Vec<(String, String)> {
94 env::var("ANTHROPIC_CUSTOM_HEADERS")
95 .ok()
96 .map(|s| {
97 s.lines()
98 .filter_map(|line| {
99 let mut parts = line.splitn(2, ':');
100 match (parts.next(), parts.next()) {
101 (Some(key), Some(value)) => {
102 Some((key.trim().to_string(), value.trim().to_string()))
103 }
104 _ => None,
105 }
106 })
107 .collect()
108 })
109 .unwrap_or_default()
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_gateway_config_builder() {
118 let config = GatewayConfig::with_base_url("https://my-gateway.com")
119 .auth_token("my-token")
120 .header("X-Custom", "value")
121 .disable_betas();
122
123 assert_eq!(config.base_url, Some("https://my-gateway.com".to_string()));
124 assert_eq!(config.auth_token, Some("my-token".to_string()));
125 assert!(config.disable_betas);
126 assert_eq!(config.custom_headers.len(), 1);
127 }
128
129 #[test]
130 fn test_effective_base_url() {
131 let config = GatewayConfig::default();
132 assert_eq!(
133 config.effective_base_url("https://default.com"),
134 "https://default.com"
135 );
136
137 let config = GatewayConfig::with_base_url("https://custom.com");
138 assert_eq!(
139 config.effective_base_url("https://default.com"),
140 "https://custom.com"
141 );
142 }
143}