1pub mod backend;
21pub mod middleware;
22pub mod tools;
23
24use std::sync::Arc;
25
26use synaptic_core::{ChatModel, Store, SynapticError, Tool};
27use synaptic_graph::{create_agent, AgentOptions, Checkpointer, CompiledGraph, MessageState};
28use synaptic_macros::traceable;
29use synaptic_middleware::AgentMiddleware;
30
31use backend::Backend;
32pub use middleware::subagent::SubAgentDef;
33
34pub struct DeepAgentOptions {
36 pub backend: Arc<dyn Backend>,
38 pub system_prompt: Option<String>,
40 pub tools: Vec<Arc<dyn Tool>>,
42 pub middleware: Vec<Arc<dyn AgentMiddleware>>,
44 pub checkpointer: Option<Arc<dyn Checkpointer>>,
46 pub store: Option<Arc<dyn Store>>,
48 pub max_input_tokens: usize,
50 pub summarization_threshold: f64,
52 pub eviction_threshold: usize,
54 pub max_subagent_depth: usize,
56 pub skills_dir: Option<String>,
58 pub memory_file: Option<String>,
60 pub subagents: Vec<SubAgentDef>,
62 pub enable_subagents: bool,
64 pub enable_filesystem: bool,
66 pub enable_skills: bool,
68 pub enable_memory: bool,
70}
71
72impl DeepAgentOptions {
73 pub fn new(backend: Arc<dyn Backend>) -> Self {
75 Self {
76 backend,
77 system_prompt: None,
78 tools: Vec::new(),
79 middleware: Vec::new(),
80 checkpointer: None,
81 store: None,
82 max_input_tokens: 128_000,
83 summarization_threshold: 0.85,
84 eviction_threshold: 20_000,
85 max_subagent_depth: 3,
86 skills_dir: Some(".skills".to_string()),
87 memory_file: Some("AGENTS.md".to_string()),
88 subagents: Vec::new(),
89 enable_subagents: true,
90 enable_filesystem: true,
91 enable_skills: true,
92 enable_memory: true,
93 }
94 }
95}
96
97#[traceable(skip = "model,options")]
108pub fn create_deep_agent(
109 model: Arc<dyn ChatModel>,
110 options: DeepAgentOptions,
111) -> Result<CompiledGraph<MessageState>, SynapticError> {
112 let mut all_middleware: Vec<Arc<dyn AgentMiddleware>> = Vec::new();
113 let mut all_tools: Vec<Arc<dyn Tool>> = Vec::new();
114
115 if options.enable_memory {
117 let memory_file = options
118 .memory_file
119 .clone()
120 .unwrap_or_else(|| "AGENTS.md".to_string());
121 all_middleware.push(Arc::new(middleware::memory::DeepMemoryMiddleware::new(
122 options.backend.clone(),
123 memory_file,
124 )));
125 }
126
127 if options.enable_skills {
129 let skills_dir = options
130 .skills_dir
131 .clone()
132 .unwrap_or_else(|| ".skills".to_string());
133 all_middleware.push(Arc::new(middleware::skills::SkillsMiddleware::new(
134 options.backend.clone(),
135 skills_dir,
136 )));
137 }
138
139 if options.enable_filesystem {
141 let fs_tools = tools::create_filesystem_tools(options.backend.clone());
142 all_tools.extend(fs_tools);
143 all_middleware.push(Arc::new(middleware::filesystem::FilesystemMiddleware::new(
144 options.backend.clone(),
145 options.eviction_threshold,
146 )));
147 }
148
149 if options.enable_subagents {
151 let subagent_mw = middleware::subagent::SubAgentMiddleware::new(
152 options.backend.clone(),
153 model.clone(),
154 options.max_subagent_depth,
155 options.subagents.clone(),
156 );
157 all_tools.push(subagent_mw.create_task_tool());
158 }
159
160 all_middleware.push(Arc::new(
162 middleware::summarization::DeepSummarizationMiddleware::new(
163 options.backend.clone(),
164 model.clone(),
165 options.max_input_tokens,
166 options.summarization_threshold,
167 ),
168 ));
169
170 all_middleware.push(Arc::new(
172 middleware::patch_tool_calls::PatchToolCallsMiddleware,
173 ));
174
175 all_middleware.extend(options.middleware);
177
178 all_tools.extend(options.tools);
180
181 let agent_options = AgentOptions {
183 checkpointer: options.checkpointer,
184 interrupt_before: Vec::new(),
185 interrupt_after: Vec::new(),
186 system_prompt: options.system_prompt,
187 middleware: all_middleware,
188 store: options.store,
189 name: Some("deep_agent".to_string()),
190 pre_model_hook: None,
191 post_model_hook: None,
192 response_format: None,
193 };
194
195 create_agent(model, all_tools, agent_options)
196}