Skip to main content

synaptic_tools/
lib.rs

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