use std::time::Duration;
use agent_base::ReasoningEffort;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum AgentAutonomy {
#[default]
Auto,
Manual,
}
#[derive(Clone, Debug)]
pub struct ControlConfig {
pub child_max_tokens: Option<u64>,
pub max_spawns: Option<usize>,
pub max_concurrency: Option<usize>,
pub task_timeout: Option<Duration>,
pub autonomy: AgentAutonomy,
pub write_tools: Vec<String>,
}
impl Default for ControlConfig {
fn default() -> Self {
Self {
child_max_tokens: None,
max_spawns: None,
max_concurrency: None,
task_timeout: None,
autonomy: AgentAutonomy::default(),
write_tools: super::preset::default_write_tools(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ChildPermissionMode {
#[default]
Full,
None,
PerSpawn,
}
#[derive(Clone, Debug)]
pub struct MultiAgentConfig {
pub enabled: bool,
pub max_sub_agents: usize,
pub max_agent_depth: i32,
pub child_permission_mode: ChildPermissionMode,
pub child_excluded_tools: Vec<String>,
pub child_reasoning_effort: Option<ReasoningEffort>,
pub child_read_only: bool,
pub child_fork_history: Option<String>,
pub control: ControlConfig,
}
impl Default for MultiAgentConfig {
fn default() -> Self {
Self {
enabled: true,
max_sub_agents: 8,
max_agent_depth: 1,
child_permission_mode: ChildPermissionMode::Full,
child_excluded_tools: Vec::new(),
child_reasoning_effort: None,
child_read_only: true,
child_fork_history: None,
control: ControlConfig::default(),
}
}
}
impl MultiAgentConfig {
pub fn enabled() -> Self {
Self {
enabled: true,
..Default::default()
}
}
pub fn with_limits(max_sub_agents: usize, max_agent_depth: i32) -> Self {
Self {
enabled: true,
max_sub_agents,
max_agent_depth,
child_permission_mode: ChildPermissionMode::Full,
child_excluded_tools: Vec::new(),
child_reasoning_effort: None,
child_read_only: true,
child_fork_history: None,
control: ControlConfig::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_enabled() {
let config = MultiAgentConfig::default();
assert!(config.enabled);
assert_eq!(config.max_sub_agents, 8);
assert_eq!(config.max_agent_depth, 1);
}
#[test]
fn default_children_are_read_only() {
assert!(MultiAgentConfig::default().child_read_only);
assert!(MultiAgentConfig::enabled().child_read_only);
assert!(MultiAgentConfig::with_limits(4, 2).child_read_only);
}
#[test]
fn default_permission_mode_is_full() {
assert_eq!(
MultiAgentConfig::default().child_permission_mode,
ChildPermissionMode::Full
);
assert_eq!(
MultiAgentConfig::enabled().child_permission_mode,
ChildPermissionMode::Full
);
assert_eq!(
MultiAgentConfig::with_limits(4, 2).child_permission_mode,
ChildPermissionMode::Full
);
}
#[test]
fn enabled_shortcut() {
let config = MultiAgentConfig::enabled();
assert!(config.enabled);
assert_eq!(config.max_sub_agents, 8);
assert_eq!(config.max_agent_depth, 1);
}
#[test]
fn with_limits() {
let config = MultiAgentConfig::with_limits(4, 2);
assert!(config.enabled);
assert_eq!(config.max_sub_agents, 4);
assert_eq!(config.max_agent_depth, 2);
}
#[test]
fn control_defaults_to_all_none() {
let c = ControlConfig::default();
assert!(c.child_max_tokens.is_none());
assert!(c.max_spawns.is_none());
assert!(c.max_concurrency.is_none());
assert!(c.task_timeout.is_none());
assert!(
MultiAgentConfig::default()
.control
.max_concurrency
.is_none()
);
}
#[test]
fn multi_agent_config_carries_control() {
let config = MultiAgentConfig {
control: ControlConfig {
max_concurrency: Some(3),
..Default::default()
},
..MultiAgentConfig::enabled()
};
assert_eq!(config.control.max_concurrency, Some(3));
}
}