llm_stack_openai/
config.rs1use std::time::Duration;
4
5#[derive(Clone)]
19pub struct OpenAiConfig {
20 pub api_key: String,
22 pub model: String,
24 pub base_url: String,
26 pub organization: Option<String>,
28 pub timeout: Option<Duration>,
30 pub client: Option<reqwest::Client>,
33}
34
35impl std::fmt::Debug for OpenAiConfig {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.debug_struct("OpenAiConfig")
38 .field("api_key", &"[REDACTED]")
39 .field("model", &self.model)
40 .field("base_url", &self.base_url)
41 .field("organization", &self.organization)
42 .field("timeout", &self.timeout)
43 .field("client", &self.client.as_ref().map(|_| "..."))
44 .finish()
45 }
46}
47
48impl Default for OpenAiConfig {
49 fn default() -> Self {
50 Self {
51 api_key: String::new(),
52 model: "gpt-4o".into(),
53 base_url: "https://api.openai.com/v1".into(),
54 organization: None,
55 timeout: None,
56 client: None,
57 }
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn test_default_config() {
67 let config = OpenAiConfig::default();
68 assert_eq!(config.model, "gpt-4o");
69 assert_eq!(config.base_url, "https://api.openai.com/v1");
70 assert!(config.api_key.is_empty());
71 assert!(config.organization.is_none());
72 assert!(config.timeout.is_none());
73 assert!(config.client.is_none());
74 }
75
76 #[test]
77 fn test_debug_redacts_api_key() {
78 let config = OpenAiConfig {
79 api_key: "sk-super-secret".into(),
80 ..Default::default()
81 };
82 let debug_output = format!("{config:?}");
83 assert!(!debug_output.contains("sk-super-secret"));
84 assert!(debug_output.contains("[REDACTED]"));
85 }
86
87 #[test]
88 fn test_config_override() {
89 let config = OpenAiConfig {
90 api_key: "test-key".into(),
91 model: "gpt-4o-mini".into(),
92 organization: Some("org-123".into()),
93 ..Default::default()
94 };
95 assert_eq!(config.api_key, "test-key");
96 assert_eq!(config.model, "gpt-4o-mini");
97 assert_eq!(config.organization.as_deref(), Some("org-123"));
98 }
99}