langsmith_rust/config/
env.rs

1use crate::error::{LangSmithError, Result};
2use once_cell::sync::Lazy;
3use std::sync::Mutex;
4
5#[derive(Debug, Clone)]
6pub struct Config {
7    pub tracing_enabled: bool,
8    pub endpoint: String,
9    pub api_key: String,
10    pub project: Option<String>,
11    pub tenant_id: Option<String>,
12}
13
14static CONFIG: Lazy<Mutex<Option<Config>>> = Lazy::new(|| Mutex::new(None));
15
16impl Config {
17    pub fn from_env() -> Result<Self> {
18        // Try to load .env file (ignore errors if it doesn't exist)
19        // Note: dotenvy doesn't override existing env vars, so env vars set in code take precedence
20        let _ = dotenvy::dotenv();
21        
22        Self::from_env_internal()
23    }
24    
25    fn from_env_internal() -> Result<Self> {
26        let tracing_enabled = std::env::var("LANGSMITH_TRACING")
27            .unwrap_or_else(|_| "false".to_string())
28            .to_lowercase()
29            .parse::<bool>()
30            .unwrap_or(false);
31
32        let endpoint = std::env::var("LANGSMITH_ENDPOINT")
33            .unwrap_or_else(|_| "https://api.smith.langchain.com".to_string());
34
35        let api_key = std::env::var("LANGSMITH_API_KEY")
36            .map_err(|_| LangSmithError::Config("LANGSMITH_API_KEY not set".to_string()))?;
37
38        let project = std::env::var("LANGSMITH_PROJECT").ok();
39        let tenant_id = std::env::var("LANGSMITH_TENANT_ID").ok();
40
41        Ok(Config {
42            tracing_enabled,
43            endpoint,
44            api_key,
45            project,
46            tenant_id,
47        })
48    }
49    
50    /// Create config from environment without loading .env file (for testing)
51    #[doc(hidden)]
52    pub fn from_env_no_dotenv() -> Result<Self> {
53        Self::from_env_internal()
54    }
55
56    pub fn get() -> Result<Self> {
57        let mut config = CONFIG.lock().unwrap();
58        if config.is_none() {
59            *config = Some(Self::from_env()?);
60        }
61        Ok(config.as_ref().unwrap().clone())
62    }
63
64    pub fn is_tracing_enabled() -> bool {
65        Self::get()
66            .map(|c| c.tracing_enabled)
67            .unwrap_or(false)
68    }
69
70    /// Reset the singleton config (for testing only)
71    /// 
72    /// # Safety
73    /// This function should only be used in tests to reset the singleton state
74    #[doc(hidden)]
75    pub fn reset() {
76        let mut config = CONFIG.lock().unwrap();
77        *config = None;
78    }
79}