use super::*;
pub(crate) fn default_rtk_binary_path() -> String {
"rtk".to_string()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RtkConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_rtk_binary_path")]
pub binary_path: String,
}
impl Default for RtkConfig {
fn default() -> Self {
Self {
enabled: false,
binary_path: default_rtk_binary_path(),
}
}
}
pub(crate) fn default_a2a_enabled() -> bool {
false
}
pub(crate) fn default_clawhub_registry() -> String {
"https://clawhub.ai".into()
}
pub(crate) fn default_true() -> bool {
true
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ClawHubVerifyMode {
Off,
Warn,
#[default]
Block,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ClawHubConfig {
#[serde(default = "default_clawhub_registry", rename = "clawhub_registry")]
pub registry: String,
#[serde(default, rename = "clawhub_token")]
pub token: Option<String>,
#[serde(default = "default_true", rename = "clawhub_agent_tools_enabled")]
pub agent_tools_enabled: bool,
#[serde(default, rename = "clawhub_skip_security_warnings")]
pub skip_security_warnings: bool,
#[serde(default, rename = "clawhub_verify_on_load")]
pub verify_on_load: ClawHubVerifyMode,
}
impl Default for ClawHubConfig {
fn default() -> Self {
Self {
registry: default_clawhub_registry(),
token: None,
agent_tools_enabled: default_true(),
skip_security_warnings: false,
verify_on_load: ClawHubVerifyMode::default(),
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum A2ATrust {
Trusted,
#[default]
Limited,
Sandboxed,
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct A2APeerConfig {
#[serde(default = "default_true")]
pub enabled: bool,
#[serde(default)]
pub base_url: String,
#[serde(default)]
pub bearer_token: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub default_session_key: Option<String>,
#[serde(default)]
pub trust: A2ATrust,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct A2AConfig {
#[serde(default = "default_a2a_enabled")]
pub enabled: bool,
#[serde(default)]
pub public_base_url: Option<String>,
#[serde(default)]
pub agent_name: Option<String>,
#[serde(default)]
pub agent_description: Option<String>,
#[serde(default)]
pub shared_tokens: Vec<String>,
#[serde(default)]
pub peers: HashMap<String, A2APeerConfig>,
}
impl Default for A2AConfig {
fn default() -> Self {
Self {
enabled: default_a2a_enabled(),
public_base_url: None,
agent_name: None,
agent_description: None,
shared_tokens: Vec::new(),
peers: HashMap::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use crate::config::test_prelude::*;
#[test]
fn test_post_deserialize_normalizes_a2a_config() {
let mut config = Config::test_defaults();
config.a2a.enabled = true;
config.a2a.public_base_url = Some(" https://mc.example.com/ ".into());
config.a2a.agent_name = Some(" Planner ".into());
config.a2a.agent_description = Some(" Plans ".into());
config.a2a.shared_tokens = vec![" ".into(), " secret ".into()];
config.a2a.peers.insert(
" Worker ".into(),
A2APeerConfig {
enabled: true,
base_url: " https://worker.example.com/ ".into(),
bearer_token: Some(" token ".into()),
description: Some(" executes ".into()),
default_session_key: Some(" team/work ".into()),
trust: Default::default(),
},
);
config.post_deserialize().unwrap();
assert_eq!(
config.a2a.public_base_url.as_deref(),
Some("https://mc.example.com")
);
assert_eq!(config.a2a.agent_name.as_deref(), Some("Planner"));
assert_eq!(config.a2a.agent_description.as_deref(), Some("Plans"));
assert_eq!(config.a2a.shared_tokens, vec!["secret".to_string()]);
let peer = config.a2a.peers.get("worker").unwrap();
assert_eq!(peer.base_url, "https://worker.example.com");
assert_eq!(peer.bearer_token.as_deref(), Some("token"));
assert_eq!(peer.description.as_deref(), Some("executes"));
assert_eq!(peer.default_session_key.as_deref(), Some("team/work"));
}
}