Skip to main content

agent_works/multi_agent/
config.rs

1//! Multi-agent configuration.
2//!
3//! Controls whether multi-agent capabilities are enabled and sets resource limits.
4//! Multi-agent is enabled by default — users who don't need it can disable via
5//! `.without_multi_agent()` or feature gate.
6
7/// Permission mode for spawned child agents.
8///
9/// Controls whether sub-agents run with full tool access or are restricted by
10/// the parent's [`ToolPolicy`](agent_base::ToolPolicy). The mode is resolved at
11/// the runtime layer on every spawn, so it cannot be bypassed by the LLM.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum ChildPermissionMode {
14    /// Child agents have full permission — every tool auto-approves.
15    ///
16    /// This matches the historical behaviour (children carried no tool policy),
17    /// so it is the default to avoid surprising existing users.
18    #[default]
19    Full,
20    /// Child agents have no permission — the parent's "dangerous tools" are
21    /// denied when the parent has a [`ToolPolicy`](agent_base::ToolPolicy); if
22    /// the parent has none, every tool is denied via [`DenyAllToolPolicy`](agent_base::DenyAllToolPolicy).
23    None,
24    /// The parent agent decides per-spawn via `SpawnAgentArgs.full_permission`.
25    PerSpawn,
26}
27
28/// Configuration for the multi-agent subsystem.
29///
30/// # Default
31///
32/// Multi-agent is **enabled** by default with limits of 8 sub-agents and depth 1.
33/// Disable it with:
34///
35/// ```rust,ignore
36/// use agent_works::AgentBuilder;
37///
38/// let agent = AgentBuilder::new(client)
39///     .without_multi_agent()
40///     .build()?;
41/// ```
42///
43/// # Limits
44///
45/// Limits only take effect when `enabled` is `true`.
46#[derive(Clone, Debug)]
47pub struct MultiAgentConfig {
48    /// Enable multi-agent capabilities.
49    ///
50    /// When `true` (default): all 6 multi-agent tools are registered, and the main
51    /// agent's system prompt is augmented with usage guidance.
52    ///
53    /// When `false`: no multi-agent tools are registered, and the system
54    /// prompt does not mention multi-agent capabilities.
55    pub enabled: bool,
56
57    /// Maximum number of concurrent sub-agents.
58    ///
59    /// Default: 8. Only enforced when `enabled` is `true`.
60    pub max_sub_agents: usize,
61
62    /// Maximum nesting depth for sub-agents.
63    ///
64    /// Default: 1 (only direct children of root can spawn). A value of 0 means
65    /// no sub-agents can be spawned at all. Only enforced when `enabled` is `true`.
66    pub max_agent_depth: i32,
67
68    /// Permission mode for spawned child agents.
69    ///
70    /// Default: [`ChildPermissionMode::Full`].
71    pub child_permission_mode: ChildPermissionMode,
72}
73
74impl Default for MultiAgentConfig {
75    fn default() -> Self {
76        Self {
77            enabled: true,
78            max_sub_agents: 8,
79            max_agent_depth: 1,
80            child_permission_mode: ChildPermissionMode::Full,
81        }
82    }
83}
84
85impl MultiAgentConfig {
86    /// Create a config with multi-agent enabled and default limits.
87    pub fn enabled() -> Self {
88        Self {
89            enabled: true,
90            ..Default::default()
91        }
92    }
93
94    /// Create a config with multi-agent enabled and custom limits.
95    pub fn with_limits(max_sub_agents: usize, max_agent_depth: i32) -> Self {
96        Self {
97            enabled: true,
98            max_sub_agents,
99            max_agent_depth,
100            child_permission_mode: ChildPermissionMode::Full,
101        }
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn default_is_enabled() {
111        let config = MultiAgentConfig::default();
112        assert!(config.enabled);
113        assert_eq!(config.max_sub_agents, 8);
114        assert_eq!(config.max_agent_depth, 1);
115    }
116
117    #[test]
118    fn default_permission_mode_is_full() {
119        assert_eq!(
120            MultiAgentConfig::default().child_permission_mode,
121            ChildPermissionMode::Full
122        );
123        assert_eq!(
124            MultiAgentConfig::enabled().child_permission_mode,
125            ChildPermissionMode::Full
126        );
127        assert_eq!(
128            MultiAgentConfig::with_limits(4, 2).child_permission_mode,
129            ChildPermissionMode::Full
130        );
131    }
132
133    #[test]
134    fn enabled_shortcut() {
135        let config = MultiAgentConfig::enabled();
136        assert!(config.enabled);
137        assert_eq!(config.max_sub_agents, 8);
138        assert_eq!(config.max_agent_depth, 1);
139    }
140
141    #[test]
142    fn with_limits() {
143        let config = MultiAgentConfig::with_limits(4, 2);
144        assert!(config.enabled);
145        assert_eq!(config.max_sub_agents, 4);
146        assert_eq!(config.max_agent_depth, 2);
147    }
148}