Skip to main content

synaptic_tools/
lib.rs

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