swiftide_integrations/open_router/
config.rs

1use derive_builder::Builder;
2use reqwest::header::{AUTHORIZATION, HeaderMap};
3use secrecy::{ExposeSecret as _, SecretString};
4use serde::Deserialize;
5
6const OPENROUTER_API_BASE: &str = "https://openrouter.ai/api/v1";
7
8#[derive(Clone, Debug, Deserialize, Builder)]
9#[serde(default)]
10#[builder(setter(into, strip_option))]
11pub struct OpenRouterConfig {
12    #[builder(default = OPENROUTER_API_BASE.to_string())]
13    api_base: String,
14    api_key: SecretString,
15    /// Sets the HTTP-Referer header (leaderbord)
16    site_url: Option<String>,
17    /// Sets the name (leaderbord)
18    site_name: Option<String>,
19}
20
21impl OpenRouterConfig {
22    pub fn builder() -> OpenRouterConfigBuilder {
23        OpenRouterConfigBuilder::default()
24    }
25    pub fn with_api_base(&mut self, api_base: &str) -> &mut Self {
26        self.api_base = api_base.to_string();
27
28        self
29    }
30
31    pub fn with_api_key(&mut self, api_key: impl Into<SecretString>) -> &mut Self {
32        self.api_key = api_key.into();
33
34        self
35    }
36    pub fn with_site_url(&mut self, site_url: &str) -> &mut Self {
37        self.site_url = Some(site_url.to_string());
38
39        self
40    }
41
42    pub fn with_site_name(&mut self, site_name: &str) -> &mut Self {
43        self.site_name = Some(site_name.to_string());
44
45        self
46    }
47}
48
49impl Default for OpenRouterConfig {
50    fn default() -> Self {
51        Self {
52            api_base: OPENROUTER_API_BASE.to_string(),
53            api_key: std::env::var("OPENROUTER_API_KEY")
54                .unwrap_or_else(|_| String::new())
55                .into(),
56            site_url: None,
57            site_name: None,
58        }
59    }
60}
61
62impl async_openai::config::Config for OpenRouterConfig {
63    fn headers(&self) -> HeaderMap {
64        let mut headers = HeaderMap::new();
65
66        let api_key = self.api_key.expose_secret();
67        assert!(!api_key.is_empty(), "API key for OpenRouter is required");
68
69        headers.insert(
70            AUTHORIZATION,
71            format!("Bearer {}", self.api_key.expose_secret())
72                .as_str()
73                .parse()
74                .unwrap(),
75        );
76        if let Ok(site_url) = self
77            .site_url
78            .as_deref()
79            .unwrap_or("https://github.com/bosun-ai/swiftide")
80            .parse()
81        {
82            headers.insert("HTTP-Referer", site_url);
83        }
84
85        if let Ok(site_name) = self.site_url.as_deref().unwrap_or("Swiftide").parse() {
86            headers.insert("X-Title", site_name);
87        }
88
89        headers
90    }
91
92    fn url(&self, path: &str) -> String {
93        format!("{}{}", self.api_base, path)
94    }
95
96    fn api_base(&self) -> &str {
97        &self.api_base
98    }
99
100    fn api_key(&self) -> &SecretString {
101        &self.api_key
102    }
103
104    fn query(&self) -> Vec<(&str, &str)> {
105        vec![]
106    }
107}