pub mod backend;
#[cfg(feature = "config-builder")]
pub mod builder;
pub mod middleware;
pub mod skill;
pub mod tools;
use std::sync::Arc;
use synaptic_core::{ChatModel, Store, SynapticError, Tool};
use synaptic_graph::{create_agent, AgentOptions, Checkpointer, CompiledGraph, MessageState};
use synaptic_macros::traceable;
use synaptic_middleware::AgentMiddleware;
use backend::Backend;
pub use middleware::subagent::SubAgentDef;
#[cfg(feature = "config-builder")]
pub use builder::build_agent_from_config;
pub struct DeepAgentOptions {
pub backend: Arc<dyn Backend>,
pub system_prompt: Option<String>,
pub tools: Vec<Arc<dyn Tool>>,
pub middleware: Vec<Arc<dyn AgentMiddleware>>,
pub checkpointer: Option<Arc<dyn Checkpointer>>,
pub store: Option<Arc<dyn Store>>,
pub max_input_tokens: usize,
pub summarization_threshold: f64,
pub eviction_threshold: usize,
pub max_subagent_depth: usize,
pub skills_dir: Option<String>,
pub memory_file: Option<String>,
pub subagents: Vec<SubAgentDef>,
pub enable_subagents: bool,
pub enable_filesystem: bool,
pub enable_skills: bool,
pub enable_memory: bool,
pub parallel_tools: bool,
}
impl DeepAgentOptions {
pub fn new(backend: Arc<dyn Backend>) -> Self {
Self {
backend,
system_prompt: None,
tools: Vec::new(),
middleware: Vec::new(),
checkpointer: None,
store: None,
max_input_tokens: 128_000,
summarization_threshold: 0.85,
eviction_threshold: 20_000,
max_subagent_depth: 3,
skills_dir: Some(".skills".to_string()),
memory_file: Some("AGENTS.md".to_string()),
subagents: Vec::new(),
enable_subagents: true,
enable_filesystem: true,
enable_skills: true,
enable_memory: true,
parallel_tools: false,
}
}
}
#[traceable(skip = "model,options")]
pub fn create_deep_agent(
model: Arc<dyn ChatModel>,
options: DeepAgentOptions,
) -> Result<CompiledGraph<MessageState>, SynapticError> {
let mut all_middleware: Vec<Arc<dyn AgentMiddleware>> = Vec::new();
let mut all_tools: Vec<Arc<dyn Tool>> = Vec::new();
if options.enable_memory {
let memory_file = options
.memory_file
.clone()
.unwrap_or_else(|| "AGENTS.md".to_string());
all_middleware.push(Arc::new(middleware::memory::DeepMemoryMiddleware::new(
options.backend.clone(),
memory_file,
)));
}
if options.enable_skills {
let skills_dir = options
.skills_dir
.clone()
.unwrap_or_else(|| ".skills".to_string());
all_middleware.push(Arc::new(middleware::skills::SkillsMiddleware::new(
options.backend.clone(),
skills_dir,
)));
}
if options.enable_filesystem {
let fs_tools = tools::create_filesystem_tools(options.backend.clone());
all_tools.extend(fs_tools);
all_middleware.push(Arc::new(middleware::filesystem::FilesystemMiddleware::new(
options.backend.clone(),
options.eviction_threshold,
)));
}
if options.enable_subagents {
let subagent_mw = middleware::subagent::SubAgentMiddleware::new(
options.backend.clone(),
model.clone(),
options.max_subagent_depth,
options.subagents.clone(),
);
all_tools.push(subagent_mw.create_task_tool());
}
all_middleware.push(Arc::new(
middleware::summarization::DeepSummarizationMiddleware::new(
options.backend.clone(),
model.clone(),
options.max_input_tokens,
options.summarization_threshold,
),
));
all_middleware.push(Arc::new(
middleware::patch_tool_calls::PatchToolCallsMiddleware,
));
all_middleware.extend(options.middleware);
all_tools.extend(options.tools);
let agent_options = AgentOptions {
checkpointer: options.checkpointer,
interrupt_before: Vec::new(),
interrupt_after: Vec::new(),
system_prompt: options.system_prompt,
middleware: all_middleware,
store: options.store,
name: Some("deep_agent".to_string()),
pre_model_hook: None,
post_model_hook: None,
response_format: None,
parallel_tools: options.parallel_tools,
};
create_agent(model, all_tools, agent_options)
}