agentcat_sdk/config/
env.rs1use std::fmt;
6use std::path::PathBuf;
7
8use super::Options;
9use crate::wire;
10
11pub const AGENTCAT_PROJECT_ID: &str = "AGENTCAT_PROJECT_ID";
13
14pub const AGENTCAT_API_URL: &str = "AGENTCAT_API_URL";
16
17pub const MCPCAT_API_URL: &str = "MCPCAT_API_URL";
20
21pub const AGENTCAT_ENABLED: &str = "AGENTCAT_ENABLED";
24
25pub(crate) const DEFAULT_API_BASE_URL: &str = "https://api.agentcat.com";
27
28pub(crate) trait Env: Send + Sync + fmt::Debug {
31 fn var(&self, name: &str) -> Option<String>;
33
34 fn home_dir(&self) -> Option<PathBuf>;
36}
37
38#[derive(Debug, Clone, Copy)]
40pub(crate) struct ProcessEnv;
41
42impl Env for ProcessEnv {
43 #[expect(
44 clippy::disallowed_methods,
45 reason = "the one place that reads the process environment"
46 )]
47 fn var(&self, name: &str) -> Option<String> {
48 std::env::var(name).ok()
49 }
50
51 fn home_dir(&self) -> Option<PathBuf> {
52 std::env::home_dir()
53 }
54}
55
56#[cfg(test)]
58#[derive(Debug, Clone, Default)]
59pub(crate) struct MapEnv {
60 vars: std::collections::HashMap<String, String>,
61 home: Option<PathBuf>,
62}
63
64#[cfg(test)]
65impl MapEnv {
66 pub(crate) fn new(vars: &[(&str, &str)]) -> Self {
68 Self {
69 vars: vars
70 .iter()
71 .map(|&(name, value)| (name.to_owned(), value.to_owned()))
72 .collect(),
73 home: None,
74 }
75 }
76
77 pub(crate) fn with_home(mut self, home: PathBuf) -> Self {
79 self.home = Some(home);
80 self
81 }
82}
83
84#[cfg(test)]
85impl Env for MapEnv {
86 fn var(&self, name: &str) -> Option<String> {
87 self.vars.get(name).cloned()
88 }
89
90 fn home_dir(&self) -> Option<PathBuf> {
91 self.home.clone()
92 }
93}
94
95pub(crate) fn resolve_api_base_url(options: &Options, env: &dyn Env) -> String {
99 options
100 .api_base_url_option()
101 .map(str::to_owned)
102 .or_else(|| env.var(AGENTCAT_API_URL).filter(|url| !url.is_empty()))
103 .or_else(|| env.var(MCPCAT_API_URL).filter(|url| !url.is_empty()))
104 .unwrap_or_else(|| DEFAULT_API_BASE_URL.to_owned())
105}
106
107pub(crate) fn sdk_enabled(env: &dyn Env) -> bool {
110 let Some(value) = env.var(AGENTCAT_ENABLED) else {
111 return true;
112 };
113 let value = wire::trim(&value).to_lowercase();
114 !matches!(value.as_str(), "false" | "0" | "no" | "off")
115}