1#[derive(Debug, Clone, Serialize, Deserialize)]
2pub struct A2aConfig {
3 #[serde(default = "default_true")]
4 pub enabled: bool,
5 #[serde(default = "default_a2a_max_msg_size")]
6 pub max_message_size: usize,
7 #[serde(default = "default_a2a_rate_limit")]
8 pub rate_limit_per_peer: u32,
9 #[serde(default = "default_a2a_session_timeout")]
10 pub session_timeout_seconds: u64,
11 #[serde(default = "default_true")]
12 pub require_on_chain_identity: bool,
13 #[serde(default = "default_a2a_nonce_ttl")]
14 pub nonce_ttl_seconds: u64,
15}
16
17impl Default for A2aConfig {
18 fn default() -> Self {
19 Self {
20 enabled: true,
21 max_message_size: default_a2a_max_msg_size(),
22 rate_limit_per_peer: default_a2a_rate_limit(),
23 session_timeout_seconds: default_a2a_session_timeout(),
24 require_on_chain_identity: true,
25 nonce_ttl_seconds: default_a2a_nonce_ttl(),
26 }
27 }
28}
29
30fn default_a2a_max_msg_size() -> usize {
31 65536
32}
33fn default_a2a_rate_limit() -> u32 {
34 10
35}
36fn default_a2a_session_timeout() -> u64 {
37 3600
38}
39fn default_a2a_nonce_ttl() -> u64 {
40 7200
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct SkillsConfig {
45 #[serde(default = "default_skills_dir")]
46 pub skills_dir: PathBuf,
47 #[serde(default = "default_script_timeout")]
48 pub script_timeout_seconds: u64,
49 #[serde(default = "default_script_max_output")]
50 pub script_max_output_bytes: usize,
51 #[serde(default = "default_interpreters")]
52 pub allowed_interpreters: Vec<String>,
53 #[serde(default = "default_true")]
54 pub sandbox_env: bool,
55 #[serde(default = "default_true")]
56 pub hot_reload: bool,
57 #[serde(default = "default_script_max_memory")]
60 pub script_max_memory_bytes: Option<u64>,
61 #[serde(default)]
65 pub network_allowed: bool,
66 #[serde(default)]
70 pub workspace_dir: Option<PathBuf>,
71}
72
73impl Default for SkillsConfig {
74 fn default() -> Self {
75 Self {
76 skills_dir: default_skills_dir(),
77 script_timeout_seconds: default_script_timeout(),
78 script_max_output_bytes: default_script_max_output(),
79 allowed_interpreters: default_interpreters(),
80 sandbox_env: true,
81 hot_reload: true,
82 script_max_memory_bytes: default_script_max_memory(),
83 network_allowed: false,
84 workspace_dir: None,
85 }
86 }
87}
88
89fn default_skills_dir() -> PathBuf {
90 dirs_next().join("skills")
91}
92fn default_script_timeout() -> u64 {
93 30
94}
95fn default_script_max_output() -> usize {
96 1_048_576
97}
98fn default_script_max_memory() -> Option<u64> {
99 Some(256 * 1024 * 1024) }
101fn default_interpreters() -> Vec<String> {
102 #[cfg(windows)]
103 {
104 vec![
105 "bash".into(),
106 "python".into(),
107 "python3".into(),
108 "node".into(),
109 ]
110 }
111 #[cfg(not(windows))]
112 {
113 vec!["bash".into(), "python3".into(), "node".into()]
114 }
115}
116
117#[derive(Debug, Clone, Default, Serialize, Deserialize)]
118pub struct VoiceChannelConfig {
119 #[serde(default)]
120 pub enabled: bool,
121 #[serde(default)]
122 pub stt_model: Option<String>,
123 #[serde(default)]
124 pub tts_model: Option<String>,
125 #[serde(default)]
126 pub tts_voice: Option<String>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct ChannelsConfig {
131 #[serde(default)]
132 pub telegram: Option<TelegramConfig>,
133 #[serde(default)]
134 pub whatsapp: Option<WhatsAppConfig>,
135 #[serde(default)]
136 pub discord: Option<DiscordConfig>,
137 #[serde(default)]
138 pub signal: Option<SignalConfig>,
139 #[serde(default)]
140 pub email: EmailConfig,
141 #[serde(default)]
142 pub voice: VoiceChannelConfig,
143 #[serde(default)]
147 pub trusted_sender_ids: Vec<String>,
148 #[serde(default = "default_thinking_threshold")]
152 pub thinking_threshold_seconds: u64,
153 #[serde(default)]
157 pub startup_announcements: Option<StartupAnnouncementsConfig>,
158}
159
160impl Default for ChannelsConfig {
161 fn default() -> Self {
162 Self {
163 telegram: None,
164 whatsapp: None,
165 discord: None,
166 signal: None,
167 email: EmailConfig::default(),
168 voice: VoiceChannelConfig::default(),
169 trusted_sender_ids: Vec::new(),
170 thinking_threshold_seconds: default_thinking_threshold(),
171 startup_announcements: None,
172 }
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177#[serde(untagged)]
178pub enum StartupAnnouncementsConfig {
179 Flag(bool),
180 Text(String),
181 Channels(Vec<String>),
182}
183
184impl ChannelsConfig {
185 pub fn startup_announcement_channels(&self) -> Vec<String> {
186 fn normalize_channel(s: &str) -> Option<String> {
187 let v = s.trim().to_ascii_lowercase();
188 if v.is_empty() || v == "none" || v == "null" || v == "false" {
189 None
190 } else {
191 Some(v)
192 }
193 }
194
195 let mut out = match &self.startup_announcements {
196 None => Vec::new(),
197 Some(StartupAnnouncementsConfig::Flag(_)) => Vec::new(),
198 Some(StartupAnnouncementsConfig::Text(v)) => {
199 normalize_channel(v).map(|s| vec![s]).unwrap_or_default()
200 }
201 Some(StartupAnnouncementsConfig::Channels(v)) => {
202 v.iter().filter_map(|s| normalize_channel(s)).collect()
203 }
204 };
205 out.sort();
206 out.dedup();
207 out
208 }
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct TelegramConfig {
213 #[serde(default = "default_true")]
214 pub enabled: bool,
215 #[serde(default)]
216 pub token_env: String,
217 #[serde(default)]
218 pub token_ref: Option<String>,
219 #[serde(default)]
220 pub allowed_chat_ids: Vec<i64>,
221 #[serde(default = "default_poll_timeout")]
222 pub poll_timeout_seconds: u64,
223 #[serde(default)]
224 pub webhook_mode: bool,
225 #[serde(default)]
226 pub webhook_path: Option<String>,
227 #[serde(default)]
228 pub webhook_secret: Option<String>,
229}
230
231fn default_thinking_threshold() -> u64 {
232 30
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct WhatsAppConfig {
237 #[serde(default)]
238 pub enabled: bool,
239 #[serde(default)]
240 pub token_env: String,
241 #[serde(default)]
242 pub token_ref: Option<String>,
243 #[serde(default)]
244 pub phone_number_id: String,
245 #[serde(default)]
246 pub verify_token: String,
247 #[serde(default)]
248 pub allowed_numbers: Vec<String>,
249 #[serde(default)]
251 pub app_secret: Option<String>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct DiscordConfig {
256 #[serde(default = "default_true")]
257 pub enabled: bool,
258 #[serde(default)]
259 pub token_env: String,
260 #[serde(default)]
261 pub token_ref: Option<String>,
262 #[serde(default)]
263 pub application_id: String,
264 #[serde(default)]
265 pub allowed_guild_ids: Vec<String>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct SignalConfig {
272 #[serde(default)]
273 pub enabled: bool,
274 #[serde(default)]
276 pub phone_number: String,
277 #[serde(default = "default_signal_daemon_url")]
279 pub daemon_url: String,
280 #[serde(default)]
282 pub allowed_numbers: Vec<String>,
283}
284
285fn default_signal_daemon_url() -> String {
286 "http://127.0.0.1:8080".into()
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct EmailConfig {
291 #[serde(default)]
292 pub enabled: bool,
293 #[serde(default)]
294 pub imap_host: String,
295 #[serde(default = "default_imap_port")]
296 pub imap_port: u16,
297 #[serde(default)]
298 pub smtp_host: String,
299 #[serde(default = "default_smtp_port")]
300 pub smtp_port: u16,
301 #[serde(default)]
302 pub username: String,
303 #[serde(default)]
304 pub password_env: String,
305 #[serde(default)]
306 pub from_address: String,
307 #[serde(default)]
308 pub allowed_senders: Vec<String>,
309 #[serde(default = "default_poll_interval")]
310 pub poll_interval_seconds: u64,
311 #[serde(default)]
313 pub oauth2_token_env: String,
314 #[serde(default)]
316 pub use_oauth2: bool,
317 #[serde(default = "default_imap_idle_enabled")]
319 pub imap_idle_enabled: bool,
320}
321
322fn default_imap_idle_enabled() -> bool {
323 true
324}
325
326impl Default for EmailConfig {
327 fn default() -> Self {
328 Self {
329 enabled: false,
330 imap_host: String::new(),
331 imap_port: default_imap_port(),
332 smtp_host: String::new(),
333 smtp_port: default_smtp_port(),
334 username: String::new(),
335 password_env: String::new(),
336 from_address: String::new(),
337 allowed_senders: Vec::new(),
338 poll_interval_seconds: default_poll_interval(),
339 oauth2_token_env: String::new(),
340 use_oauth2: false,
341 imap_idle_enabled: default_imap_idle_enabled(),
342 }
343 }
344}
345
346fn default_imap_port() -> u16 {
347 993
348}
349fn default_smtp_port() -> u16 {
350 587
351}
352fn default_poll_interval() -> u64 {
353 30
354}
355
356fn default_poll_timeout() -> u64 {
357 30
358}
359