1use super::*;
2
3pub(crate) fn default_rtk_binary_path() -> String {
4 "rtk".to_string()
5}
6
7#[derive(Clone, Debug, Serialize, Deserialize)]
13pub struct RtkConfig {
14 #[serde(default)]
15 pub enabled: bool,
16 #[serde(default = "default_rtk_binary_path")]
18 pub binary_path: String,
19}
20
21impl Default for RtkConfig {
22 fn default() -> Self {
23 Self {
24 enabled: false,
25 binary_path: default_rtk_binary_path(),
26 }
27 }
28}
29
30pub(crate) fn default_a2a_enabled() -> bool {
31 false
32}
33
34pub(crate) fn default_clawhub_registry() -> String {
35 "https://clawhub.ai".into()
36}
37
38pub(crate) fn default_true() -> bool {
39 true
40}
41
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
49#[serde(rename_all = "lowercase")]
50pub enum ClawHubVerifyMode {
51 Off,
52 Warn,
53 #[default]
54 Block,
55}
56
57#[derive(Clone, Debug, Serialize, Deserialize)]
58pub struct ClawHubConfig {
59 #[serde(default = "default_clawhub_registry", rename = "clawhub_registry")]
61 pub registry: String,
62 #[serde(default, rename = "clawhub_token")]
64 pub token: Option<String>,
65 #[serde(default = "default_true", rename = "clawhub_agent_tools_enabled")]
67 pub agent_tools_enabled: bool,
68 #[serde(default, rename = "clawhub_skip_security_warnings")]
70 pub skip_security_warnings: bool,
71 #[serde(default, rename = "clawhub_verify_on_load")]
73 pub verify_on_load: ClawHubVerifyMode,
74}
75
76impl Default for ClawHubConfig {
77 fn default() -> Self {
78 Self {
79 registry: default_clawhub_registry(),
80 token: None,
81 agent_tools_enabled: default_true(),
82 skip_security_warnings: false,
83 verify_on_load: ClawHubVerifyMode::default(),
84 }
85 }
86}
87
88#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
95#[serde(rename_all = "lowercase")]
96pub enum A2ATrust {
97 Trusted,
98 #[default]
99 Limited,
100 Sandboxed,
101}
102
103#[derive(Clone, Debug, Serialize, Deserialize, Default)]
104pub struct A2APeerConfig {
105 #[serde(default = "default_true")]
106 pub enabled: bool,
107 #[serde(default)]
108 pub base_url: String,
109 #[serde(default)]
110 pub bearer_token: Option<String>,
111 #[serde(default)]
112 pub description: Option<String>,
113 #[serde(default)]
114 pub default_session_key: Option<String>,
115 #[serde(default)]
117 pub trust: A2ATrust,
118}
119
120#[derive(Clone, Debug, Serialize, Deserialize)]
121pub struct A2AConfig {
122 #[serde(default = "default_a2a_enabled")]
123 pub enabled: bool,
124 #[serde(default)]
125 pub public_base_url: Option<String>,
126 #[serde(default)]
127 pub agent_name: Option<String>,
128 #[serde(default)]
129 pub agent_description: Option<String>,
130 #[serde(default)]
131 pub shared_tokens: Vec<String>,
132 #[serde(default)]
133 pub peers: HashMap<String, A2APeerConfig>,
134}
135
136impl Default for A2AConfig {
137 fn default() -> Self {
138 Self {
139 enabled: default_a2a_enabled(),
140 public_base_url: None,
141 agent_name: None,
142 agent_description: None,
143 shared_tokens: Vec::new(),
144 peers: HashMap::new(),
145 }
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 #[allow(unused_imports)]
153 use crate::config::test_prelude::*;
154
155 #[test]
156 fn test_post_deserialize_normalizes_a2a_config() {
157 let mut config = Config::test_defaults();
158 config.a2a.enabled = true;
159 config.a2a.public_base_url = Some(" https://mc.example.com/ ".into());
160 config.a2a.agent_name = Some(" Planner ".into());
161 config.a2a.agent_description = Some(" Plans ".into());
162 config.a2a.shared_tokens = vec![" ".into(), " secret ".into()];
163 config.a2a.peers.insert(
164 " Worker ".into(),
165 A2APeerConfig {
166 enabled: true,
167 base_url: " https://worker.example.com/ ".into(),
168 bearer_token: Some(" token ".into()),
169 description: Some(" executes ".into()),
170 default_session_key: Some(" team/work ".into()),
171 trust: Default::default(),
172 },
173 );
174
175 config.post_deserialize().unwrap();
176
177 assert_eq!(
178 config.a2a.public_base_url.as_deref(),
179 Some("https://mc.example.com")
180 );
181 assert_eq!(config.a2a.agent_name.as_deref(), Some("Planner"));
182 assert_eq!(config.a2a.agent_description.as_deref(), Some("Plans"));
183 assert_eq!(config.a2a.shared_tokens, vec!["secret".to_string()]);
184 let peer = config.a2a.peers.get("worker").unwrap();
185 assert_eq!(peer.base_url, "https://worker.example.com");
186 assert_eq!(peer.bearer_token.as_deref(), Some("token"));
187 assert_eq!(peer.description.as_deref(), Some("executes"));
188 assert_eq!(peer.default_session_key.as_deref(), Some("team/work"));
189 }
190}