1pub mod brave;
2pub mod calculator;
3pub mod duckduckgo;
4pub mod filter;
5mod handle_error;
6pub mod jina_reader;
7mod parallel_executor;
8mod return_direct;
9pub mod wikipedia;
10
11pub use brave::BraveSearchTool;
12pub use calculator::CalculatorTool;
13pub use duckduckgo::DuckDuckGoTool;
14pub use filter::{
15 AllowListFilter, CompositeFilter, DenyListFilter, FilterContext, StateMachineFilter, ToolFilter,
16};
17pub use handle_error::HandleErrorTool;
18pub use jina_reader::JinaReaderTool;
19pub use parallel_executor::ParallelToolExecutor;
20pub use return_direct::ReturnDirectTool;
21pub use wikipedia::WikipediaTool;
22
23use std::{
24 collections::HashMap,
25 sync::{Arc, RwLock},
26};
27
28use synaptic_core::{SynapticError, Tool};
29
30#[derive(Default, Clone)]
32pub struct ToolRegistry {
33 inner: Arc<RwLock<HashMap<String, Arc<dyn Tool>>>>,
34}
35
36impl ToolRegistry {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn register(&self, tool: Arc<dyn Tool>) -> Result<(), SynapticError> {
42 let mut guard = self
43 .inner
44 .write()
45 .map_err(|e| SynapticError::Tool(format!("registry lock poisoned: {e}")))?;
46 guard.insert(tool.name().to_string(), tool);
47 Ok(())
48 }
49
50 pub fn get(&self, name: &str) -> Option<Arc<dyn Tool>> {
51 let guard = self.inner.read().ok()?;
52 guard.get(name).cloned()
53 }
54}
55
56#[derive(Clone)]
58pub struct SerialToolExecutor {
59 registry: ToolRegistry,
60}
61
62impl SerialToolExecutor {
63 pub fn new(registry: ToolRegistry) -> Self {
64 Self { registry }
65 }
66
67 pub async fn execute(
68 &self,
69 tool_name: &str,
70 args: serde_json::Value,
71 ) -> Result<serde_json::Value, SynapticError> {
72 let tool = self
73 .registry
74 .get(tool_name)
75 .ok_or_else(|| SynapticError::ToolNotFound(tool_name.to_string()))?;
76 tool.call(args).await
77 }
78}