Skip to main content

providers_kit/config/
ollama.rs

1use url::Url;
2
3use super::ApiKey;
4use crate::KitError;
5use crate::error::ValidationViolation;
6
7const DEFAULT_OLLAMA_LOCAL_BASE_URL: &str = "http://localhost:11434/api";
8const DEFAULT_OLLAMA_CLOUD_BASE_URL: &str = "https://ollama.com/api";
9
10/// Ollama local or cloud configuration.
11///
12/// Construction is passive and does not verify a running local or cloud service.
13///
14/// # Examples
15///
16/// ```
17/// use providers_kit::config::{ApiKey, OllamaConfig};
18/// let config = OllamaConfig::local();
19/// let _config = config.with_base_url("http://127.0.0.1:11434/api".parse().unwrap())?;
20///
21/// # Ok::<(), providers_kit::KitError>(())
22/// ```
23///
24#[derive(Clone)]
25pub struct OllamaConfig {
26    base_url: Url,
27    api_key: Option<ApiKey>,
28}
29
30impl OllamaConfig {
31    /// Creates an unauthenticated local Ollama configuration.
32    ///
33    /// ```
34    /// let config = providers_kit::config::OllamaConfig::local();
35    /// let _ = config;
36    /// ```
37    #[must_use]
38    pub fn local() -> Self {
39        Self {
40            base_url: Url::parse(DEFAULT_OLLAMA_LOCAL_BASE_URL)
41                .expect("crate-owned local Ollama base URL should parse"),
42            api_key: None,
43        }
44    }
45
46    /// Creates an authenticated local or proxy configuration.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use providers_kit::config::{ApiKey, OllamaConfig};
52    /// let config = OllamaConfig::local_with_key(ApiKey::new("example-key")?);
53    /// let _config = config.with_base_url("http://127.0.0.1:11434/api".parse().unwrap())?;
54    ///
55    /// # Ok::<(), providers_kit::KitError>(())
56    /// ```
57    ///
58    #[must_use]
59    pub fn local_with_key(api_key: ApiKey) -> Self {
60        Self {
61            base_url: Url::parse(DEFAULT_OLLAMA_LOCAL_BASE_URL)
62                .expect("crate-owned local Ollama base URL should parse"),
63            api_key: Some(api_key),
64        }
65    }
66
67    /// Creates an Ollama Cloud configuration.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use providers_kit::config::{ApiKey, OllamaConfig};
73    /// let config = OllamaConfig::cloud(ApiKey::new("example-key")?);
74    /// let _config = config.with_base_url("http://127.0.0.1:11434/api".parse().unwrap())?;
75    ///
76    /// # Ok::<(), providers_kit::KitError>(())
77    /// ```
78    ///
79    #[must_use]
80    pub fn cloud(api_key: ApiKey) -> Self {
81        Self {
82            base_url: Url::parse(DEFAULT_OLLAMA_CLOUD_BASE_URL)
83                .expect("crate-owned Ollama Cloud base URL should parse"),
84            api_key: Some(api_key),
85        }
86    }
87
88    /// Replaces the API base URL.
89    ///
90    /// # Errors
91    ///
92    /// Returns a configuration error unless the URL path is exactly `/api`. The URL is not contacted or checked for endpoint capabilities here.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use providers_kit::config::OllamaConfig;
98    /// assert!(OllamaConfig::local().with_base_url("http://localhost:11434/".parse().unwrap()).is_err());
99    /// let _config = OllamaConfig::local().with_base_url("http://localhost:11434/api".parse().unwrap())?;
100    ///
101    /// # Ok::<(), providers_kit::KitError>(())
102    /// ```
103    ///
104    pub fn with_base_url(mut self, base_url: Url) -> Result<Self, KitError> {
105        if base_url.path() != "/api" {
106            return Err(KitError::config(
107                ValidationViolation::InvalidValue {
108                    field: "base_url.path",
109                    rule: "exact /api path",
110                },
111                "Ollama base URL must point at the exact /api path",
112            ));
113        }
114        self.base_url = base_url;
115        Ok(self)
116    }
117
118    pub(crate) fn base_url(&self) -> &Url {
119        &self.base_url
120    }
121
122    pub(crate) fn api_key(&self) -> Option<&ApiKey> {
123        self.api_key.as_ref()
124    }
125}