use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct ProxyConfig {
pub anthropic_upstream: Option<String>,
pub openai_upstream: Option<String>,
pub gemini_upstream: Option<String>,
}
impl ProxyConfig {
pub fn resolve_upstream(&self, provider: ProxyProvider) -> String {
let (env_var, config_val, default) = match provider {
ProxyProvider::Anthropic => (
"LEAN_CTX_ANTHROPIC_UPSTREAM",
self.anthropic_upstream.as_deref(),
"https://api.anthropic.com",
),
ProxyProvider::OpenAi => (
"LEAN_CTX_OPENAI_UPSTREAM",
self.openai_upstream.as_deref(),
"https://api.openai.com",
),
ProxyProvider::Gemini => (
"LEAN_CTX_GEMINI_UPSTREAM",
self.gemini_upstream.as_deref(),
"https://generativelanguage.googleapis.com",
),
};
std::env::var(env_var)
.ok()
.and_then(|v| normalize_url_opt(&v))
.or_else(|| config_val.and_then(normalize_url_opt))
.unwrap_or_else(|| normalize_url(default))
}
}
#[derive(Debug, Clone, Copy)]
pub enum ProxyProvider {
Anthropic,
OpenAi,
Gemini,
}
pub fn normalize_url(value: &str) -> String {
value.trim().trim_end_matches('/').to_string()
}
pub fn normalize_url_opt(value: &str) -> Option<String> {
let trimmed = normalize_url(value);
if trimmed.is_empty() {
None
} else {
Some(trimmed)
}
}
pub fn is_local_proxy_url(value: &str) -> bool {
let n = normalize_url(value);
n.starts_with("http://127.0.0.1:")
|| n.starts_with("http://localhost:")
|| n.starts_with("http://[::1]:")
}