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