Skip to main content

synaptic_tools/
lib.rs

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/// Thread-safe registry for tool definitions and implementations, backed by `Arc<RwLock<HashMap>>`.
31#[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/// Executes tool calls sequentially, looking up tools in a `ToolRegistry`.
57#[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}