Skip to main content

modular_agent_core/
config.rs

1use im::Vector;
2use serde::{Deserialize, Serialize};
3
4use crate::FnvIndexMap;
5use crate::error::AgentError;
6use crate::value::{AgentValue, AgentValueMap};
7
8/// Type alias for a map of agent configurations.
9pub type AgentConfigsMap = FnvIndexMap<String, AgentConfigs>;
10
11/// Configuration container for an agent.
12///
13/// Holds configuration values in key-value format and provides type-safe accessor methods.
14/// Configuration parameters defined with `#[modular_agent]` macro are stored in this struct.
15#[derive(Debug, Default, Serialize, Deserialize, Clone)]
16pub struct AgentConfigs(FnvIndexMap<String, AgentValue>);
17
18impl AgentConfigs {
19    /// Creates a new empty configuration container.
20    pub fn new() -> Self {
21        Self(FnvIndexMap::default())
22    }
23
24    /// Sets a configuration value.
25    pub fn set(&mut self, key: String, value: AgentValue) {
26        self.0.insert(key, value);
27    }
28
29    /// Returns `true` if the configuration contains the specified key.
30    pub fn contains_key(&self, key: &str) -> bool {
31        self.0.contains_key(key)
32    }
33
34    /// Gets a configuration value by key.
35    ///
36    /// # Errors
37    ///
38    /// Returns `UnknownConfig` if the key does not exist.
39    pub fn get(&self, key: &str) -> Result<&AgentValue, AgentError> {
40        self.0
41            .get(key)
42            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
43    }
44
45    /// Gets a boolean configuration value.
46    ///
47    /// # Errors
48    ///
49    /// Returns `UnknownConfig` if the key does not exist or cannot be converted to boolean.
50    pub fn get_bool(&self, key: &str) -> Result<bool, AgentError> {
51        self.0
52            .get(key)
53            .and_then(|v| v.as_bool())
54            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
55    }
56
57    /// Gets a boolean configuration value, or the specified default if not found.
58    pub fn get_bool_or(&self, key: &str, default: bool) -> bool {
59        self.get_bool(key).unwrap_or(default)
60    }
61
62    /// Gets a boolean configuration value, or `false` if not found.
63    pub fn get_bool_or_default(&self, key: &str) -> bool {
64        self.get_bool(key).unwrap_or_default()
65    }
66
67    /// Gets an integer configuration value.
68    ///
69    /// # Errors
70    ///
71    /// Returns `UnknownConfig` if the key does not exist or cannot be converted to integer.
72    pub fn get_integer(&self, key: &str) -> Result<i64, AgentError> {
73        self.0
74            .get(key)
75            .and_then(|v| v.as_i64())
76            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
77    }
78
79    /// Gets an integer configuration value, or the specified default if not found.
80    pub fn get_integer_or(&self, key: &str, default: i64) -> i64 {
81        self.get_integer(key).unwrap_or(default)
82    }
83
84    /// Gets an integer configuration value, or `0` if not found.
85    pub fn get_integer_or_default(&self, key: &str) -> i64 {
86        self.get_integer(key).unwrap_or_default()
87    }
88
89    /// Gets a number (f64) configuration value.
90    ///
91    /// # Errors
92    ///
93    /// Returns `UnknownConfig` if the key does not exist or cannot be converted to number.
94    pub fn get_number(&self, key: &str) -> Result<f64, AgentError> {
95        self.0
96            .get(key)
97            .and_then(|v| v.as_f64())
98            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
99    }
100
101    /// Gets a number configuration value, or the specified default if not found.
102    pub fn get_number_or(&self, key: &str, default: f64) -> f64 {
103        self.get_number(key).unwrap_or(default)
104    }
105
106    /// Gets a number configuration value, or `0.0` if not found.
107    pub fn get_number_or_default(&self, key: &str) -> f64 {
108        self.get_number(key).unwrap_or_default()
109    }
110
111    /// Gets a string configuration value.
112    ///
113    /// # Errors
114    ///
115    /// Returns `UnknownConfig` if the key does not exist or cannot be converted to string.
116    pub fn get_string(&self, key: &str) -> Result<String, AgentError> {
117        self.0
118            .get(key)
119            .and_then(|v| v.as_str())
120            .map(|v| v.to_string())
121            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
122    }
123
124    /// Gets a string configuration value, or the specified default if not found.
125    pub fn get_string_or(&self, key: &str, default: impl Into<String>) -> String {
126        self.0
127            .get(key)
128            .and_then(|v| v.as_str())
129            .map(|v| v.to_string())
130            .unwrap_or(default.into())
131    }
132
133    /// Gets a string configuration value, or an empty string if not found.
134    pub fn get_string_or_default(&self, key: &str) -> String {
135        self.0
136            .get(key)
137            .and_then(|v| v.as_str())
138            .map(|v| v.to_string())
139            .unwrap_or_default()
140    }
141
142    /// Gets an array configuration value.
143    ///
144    /// # Errors
145    ///
146    /// Returns `UnknownConfig` if the key does not exist or cannot be converted to array.
147    pub fn get_array(&self, key: &str) -> Result<&Vector<AgentValue>, AgentError> {
148        self.0
149            .get(key)
150            .and_then(|v| v.as_array())
151            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
152    }
153
154    /// Gets an array configuration value, or the specified default if not found.
155    pub fn get_array_or<'a>(
156        &'a self,
157        key: &str,
158        default: &'a Vector<AgentValue>,
159    ) -> &'a Vector<AgentValue> {
160        self.0
161            .get(key)
162            .and_then(|v| v.as_array())
163            .unwrap_or(default)
164    }
165
166    /// Gets an array configuration value, or an empty array if not found.
167    pub fn get_array_or_default(&self, key: &str) -> Vector<AgentValue> {
168        self.0
169            .get(key)
170            .and_then(|v| v.as_array())
171            .cloned()
172            .unwrap_or_default()
173    }
174
175    /// Gets an object configuration value.
176    ///
177    /// # Errors
178    ///
179    /// Returns `UnknownConfig` if the key does not exist or cannot be converted to object.
180    pub fn get_object(&self, key: &str) -> Result<&AgentValueMap<String, AgentValue>, AgentError> {
181        self.0
182            .get(key)
183            .and_then(|v| v.as_object())
184            .ok_or_else(|| AgentError::UnknownConfig(key.to_string()))
185    }
186
187    /// Gets an object configuration value, or the specified default if not found.
188    pub fn get_object_or<'a>(
189        &'a self,
190        key: &str,
191        default: &'a AgentValueMap<String, AgentValue>,
192    ) -> &'a AgentValueMap<String, AgentValue> {
193        self.0
194            .get(key)
195            .and_then(|v| v.as_object())
196            .unwrap_or(default)
197    }
198
199    /// Gets an object configuration value, or an empty object if not found.
200    pub fn get_object_or_default(&self, key: &str) -> AgentValueMap<String, AgentValue> {
201        self.0
202            .get(key)
203            .and_then(|v| v.as_object())
204            .cloned()
205            .unwrap_or_default()
206    }
207
208    /// Returns an iterator over the configuration keys.
209    pub fn keys(&self) -> indexmap::map::Keys<'_, String, AgentValue> {
210        self.0.keys()
211    }
212
213    /// Removes a configuration value by key, returning the value if it existed.
214    ///
215    /// Uses `shift_remove` to preserve insertion order.
216    pub fn remove(&mut self, key: &str) -> Option<AgentValue> {
217        self.0.shift_remove(key)
218    }
219
220    /// Retains only the configuration entries for which the predicate returns `true`.
221    pub fn retain<F>(&mut self, f: F)
222    where
223        F: FnMut(&String, &mut AgentValue) -> bool,
224    {
225        self.0.retain(f);
226    }
227}
228
229impl IntoIterator for AgentConfigs {
230    type Item = (String, AgentValue);
231    type IntoIter = indexmap::map::IntoIter<String, AgentValue>;
232
233    fn into_iter(self) -> Self::IntoIter {
234        self.0.into_iter()
235    }
236}
237
238impl<'a> IntoIterator for &'a AgentConfigs {
239    type Item = (&'a String, &'a AgentValue);
240    type IntoIter = indexmap::map::Iter<'a, String, AgentValue>;
241
242    fn into_iter(self) -> Self::IntoIter {
243        self.0.iter()
244    }
245}
246
247impl FromIterator<(String, AgentValue)> for AgentConfigs {
248    fn from_iter<T: IntoIterator<Item = (String, AgentValue)>>(iter: T) -> Self {
249        let mut configs = AgentConfigs::new();
250        for (key, value) in iter {
251            configs.set(key, value);
252        }
253        configs
254    }
255}
256
257impl<'a> FromIterator<(&'a String, &'a AgentValue)> for AgentConfigs {
258    fn from_iter<T: IntoIterator<Item = (&'a String, &'a AgentValue)>>(iter: T) -> Self {
259        let mut configs = AgentConfigs::new();
260        for (key, value) in iter {
261            configs.set(key.clone(), value.clone());
262        }
263        configs
264    }
265}