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