agents_runtime/agent/
config.rs

1//! Configuration structs and types for Deep Agents
2//!
3//! This module contains all the configuration structures used to build Deep Agents,
4//! including parameter structs that mirror the Python SDK API.
5
6use crate::middleware::{AgentMiddleware, HitlPolicy, SubAgentDescriptor, SubAgentRegistration};
7use agents_core::agent::{AgentHandle, PlannerHandle, ToolHandle};
8use agents_core::persistence::Checkpointer;
9use std::collections::{HashMap, HashSet};
10use std::sync::Arc;
11
12/// Parameters for create_deep_agent() that mirror the Python API exactly
13///
14/// This struct matches the Python function signature:
15/// ```python
16/// def create_deep_agent(
17///     tools: Sequence[Union[BaseTool, Callable, dict[str, Any]]] = [],
18///     instructions: str = "",
19///     middleware: Optional[list[AgentMiddleware]] = None,
20///     model: Optional[Union[str, LanguageModelLike]] = None,
21///     subagents: Optional[list[SubAgent | CustomSubAgent]] = None,
22///     context_schema: Optional[Type[Any]] = None,
23///     checkpointer: Optional[Checkpointer] = None,
24///     tool_configs: Optional[dict[str, bool | ToolConfig]] = None,
25/// )
26/// ```
27#[derive(Default)]
28pub struct CreateDeepAgentParams {
29    pub tools: Vec<Arc<dyn ToolHandle>>,
30    pub instructions: String,
31    pub middleware: Vec<Arc<dyn AgentMiddleware>>,
32    pub model: Option<Arc<dyn agents_core::llm::LanguageModel>>,
33    pub subagents: Vec<SubAgentConfig>,
34    pub context_schema: Option<String>,
35    pub checkpointer: Option<Arc<dyn Checkpointer>>,
36    pub tool_configs: HashMap<String, HitlPolicy>,
37}
38
39/// Configuration for building a deep agent instance.
40///
41/// This is the internal configuration used by the builder and runtime.
42pub struct DeepAgentConfig {
43    pub instructions: String,
44    pub planner: Arc<dyn PlannerHandle>,
45    pub tools: Vec<Arc<dyn ToolHandle>>,
46    pub subagents: Vec<SubAgentRegistration>,
47    pub summarization: Option<SummarizationConfig>,
48    pub tool_interrupts: HashMap<String, HitlPolicy>,
49    pub builtin_tools: Option<HashSet<String>>,
50    pub auto_general_purpose: bool,
51    pub enable_prompt_caching: bool,
52    pub checkpointer: Option<Arc<dyn Checkpointer>>,
53}
54
55impl DeepAgentConfig {
56    pub fn new(instructions: impl Into<String>, planner: Arc<dyn PlannerHandle>) -> Self {
57        Self {
58            instructions: instructions.into(),
59            planner,
60            tools: Vec::new(),
61            subagents: Vec::new(),
62            summarization: None,
63            tool_interrupts: HashMap::new(),
64            builtin_tools: None,
65            auto_general_purpose: true,
66            enable_prompt_caching: false,
67            checkpointer: None,
68        }
69    }
70
71    pub fn with_tool(mut self, tool: Arc<dyn ToolHandle>) -> Self {
72        self.tools.push(tool);
73        self
74    }
75
76    pub fn with_subagent(
77        mut self,
78        descriptor: SubAgentDescriptor,
79        agent: Arc<dyn AgentHandle>,
80    ) -> Self {
81        self.subagents
82            .push(SubAgentRegistration { descriptor, agent });
83        self
84    }
85
86    pub fn with_summarization(mut self, config: SummarizationConfig) -> Self {
87        self.summarization = Some(config);
88        self
89    }
90
91    pub fn with_tool_interrupt(mut self, tool_name: impl Into<String>, policy: HitlPolicy) -> Self {
92        self.tool_interrupts.insert(tool_name.into(), policy);
93        self
94    }
95
96    /// Limit which built-in tools are exposed. When omitted, all built-ins are available.
97    /// Built-ins: write_todos, ls, read_file, write_file, edit_file.
98    /// The `task` tool (for subagents) is always available when subagents are registered.
99    pub fn with_builtin_tools<I, S>(mut self, names: I) -> Self
100    where
101        I: IntoIterator<Item = S>,
102        S: Into<String>,
103    {
104        let set: HashSet<String> = names.into_iter().map(|s| s.into()).collect();
105        self.builtin_tools = Some(set);
106        self
107    }
108
109    /// Enable or disable automatic registration of a "general-purpose" subagent.
110    /// Enabled by default; set to false to opt out.
111    pub fn with_auto_general_purpose(mut self, enabled: bool) -> Self {
112        self.auto_general_purpose = enabled;
113        self
114    }
115
116    /// Enable or disable Anthropic prompt caching middleware.
117    /// Disabled by default; set to true to enable caching for better performance.
118    pub fn with_prompt_caching(mut self, enabled: bool) -> Self {
119        self.enable_prompt_caching = enabled;
120        self
121    }
122
123    /// Set the checkpointer for persisting agent state between runs.
124    pub fn with_checkpointer(mut self, checkpointer: Arc<dyn Checkpointer>) -> Self {
125        self.checkpointer = Some(checkpointer);
126        self
127    }
128
129    /// Convenience: construct and register a subagent from a simple configuration bundle.
130    pub fn with_subagent_config<I>(mut self, cfgs: I) -> Self
131    where
132        I: IntoIterator<Item = SubAgentConfig>,
133    {
134        for cfg in cfgs {
135            let planner = cfg.planner.unwrap_or_else(|| self.planner.clone());
136            let mut sub_cfg = DeepAgentConfig::new(cfg.instructions, planner)
137                .with_auto_general_purpose(false)
138                .with_prompt_caching(self.enable_prompt_caching);
139            if let Some(ref selected) = self.builtin_tools {
140                sub_cfg = sub_cfg.with_builtin_tools(selected.iter().cloned());
141            }
142            if let Some(ref sum) = self.summarization {
143                sub_cfg = sub_cfg.with_summarization(sum.clone());
144            }
145            if let Some(tools) = cfg.tools {
146                for t in tools {
147                    sub_cfg = sub_cfg.with_tool(t);
148                }
149            } else {
150                for t in &self.tools {
151                    sub_cfg = sub_cfg.with_tool(t.clone());
152                }
153            }
154
155            let sub_agent = super::api::create_deep_agent_from_config(sub_cfg);
156            self = self.with_subagent(
157                SubAgentDescriptor {
158                    name: cfg.name,
159                    description: cfg.description,
160                },
161                Arc::new(sub_agent),
162            );
163        }
164        self
165    }
166}
167
168/// Configuration for creating and registering a subagent using a simple, Python-like shape.
169///
170/// This mirrors the Python SubAgent TypedDict:
171/// ```python
172/// class SubAgent(TypedDict):
173///     name: str
174///     description: str
175///     prompt: str
176///     tools: NotRequired[list[str]]
177///     model_settings: NotRequired[dict[str, Any]]
178/// ```
179pub struct SubAgentConfig {
180    pub name: String,
181    pub description: String,
182    pub instructions: String,
183    pub tools: Option<Vec<Arc<dyn ToolHandle>>>,
184    pub planner: Option<Arc<dyn PlannerHandle>>,
185}
186
187impl IntoIterator for SubAgentConfig {
188    type Item = SubAgentConfig;
189    type IntoIter = std::iter::Once<SubAgentConfig>;
190
191    fn into_iter(self) -> Self::IntoIter {
192        std::iter::once(self)
193    }
194}
195
196/// Configuration for summarization middleware
197#[derive(Clone)]
198pub struct SummarizationConfig {
199    pub messages_to_keep: usize,
200    pub summary_note: String,
201}