linger_openai_sdk/
config.rs1use crate::error::LingerError;
2use crate::retry::{NoopRetrySleeper, RetryPolicy, RetrySleeper};
3use std::fmt;
4use std::sync::Arc;
5
6#[derive(Clone)]
9#[non_exhaustive]
10pub struct ClientConfig {
11 api_key: String,
12 base_url: String,
13 organization: Option<String>,
14 project: Option<String>,
15 retry_policy: RetryPolicy,
16 retry_sleeper: Arc<dyn RetrySleeper>,
17}
18
19impl ClientConfig {
20 pub fn builder() -> ClientConfigBuilder {
23 ClientConfigBuilder::default()
24 }
25
26 pub(crate) fn api_key(&self) -> &str {
29 &self.api_key
30 }
31
32 pub fn base_url(&self) -> &str {
35 &self.base_url
36 }
37
38 pub fn organization(&self) -> Option<&str> {
41 self.organization.as_deref()
42 }
43
44 pub fn project(&self) -> Option<&str> {
47 self.project.as_deref()
48 }
49
50 pub fn retry_policy(&self) -> &RetryPolicy {
53 &self.retry_policy
54 }
55
56 pub fn retry_sleeper(&self) -> Arc<dyn RetrySleeper> {
59 self.retry_sleeper.clone()
60 }
61}
62
63impl fmt::Debug for ClientConfig {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.debug_struct("ClientConfig")
66 .field("api_key", &"<redacted>")
67 .field("base_url", &self.base_url)
68 .field(
69 "organization",
70 &self.organization.as_ref().map(|_| "<redacted>"),
71 )
72 .field("project", &self.project.as_ref().map(|_| "<redacted>"))
73 .field("retry_policy", &self.retry_policy)
74 .field("retry_sleeper", &self.retry_sleeper)
75 .finish()
76 }
77}
78
79#[derive(Clone, Debug)]
82#[non_exhaustive]
83pub struct ClientConfigBuilder {
84 api_key: Option<String>,
85 base_url: String,
86 organization: Option<String>,
87 project: Option<String>,
88 retry_policy: RetryPolicy,
89 retry_sleeper: Arc<dyn RetrySleeper>,
90}
91
92impl Default for ClientConfigBuilder {
93 fn default() -> Self {
94 Self {
95 api_key: None,
96 base_url: "https://api.openai.com".to_string(),
97 organization: None,
98 project: None,
99 retry_policy: RetryPolicy::default(),
100 retry_sleeper: Arc::new(NoopRetrySleeper),
101 }
102 }
103}
104
105impl ClientConfigBuilder {
106 pub fn api_key(mut self, api_key: impl Into<String>) -> Self {
109 self.api_key = Some(api_key.into());
110 self
111 }
112
113 pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
116 self.base_url = base_url.into();
117 self
118 }
119
120 pub fn organization(mut self, organization: impl Into<String>) -> Self {
123 self.organization = Some(organization.into());
124 self
125 }
126
127 pub fn project(mut self, project: impl Into<String>) -> Self {
130 self.project = Some(project.into());
131 self
132 }
133
134 pub fn retry_policy(mut self, retry_policy: RetryPolicy) -> Self {
137 self.retry_policy = retry_policy;
138 self
139 }
140
141 pub fn retry_sleeper(mut self, retry_sleeper: Arc<dyn RetrySleeper>) -> Self {
144 self.retry_sleeper = retry_sleeper;
145 self
146 }
147
148 pub fn build(self) -> Result<ClientConfig, LingerError> {
151 let api_key = self
152 .api_key
153 .filter(|value| !value.trim().is_empty())
154 .ok_or_else(|| LingerError::invalid_config("api_key is required"))?;
155 if self.base_url.trim().is_empty() {
156 return Err(LingerError::invalid_config("base_url is required"));
157 }
158 Ok(ClientConfig {
159 api_key,
160 base_url: self.base_url.trim_end_matches('/').to_string(),
161 organization: self.organization,
162 project: self.project,
163 retry_policy: self.retry_policy,
164 retry_sleeper: self.retry_sleeper,
165 })
166 }
167}