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::{SynapticError, Tool};
15
16#[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<(), SynapticError> {
28 let mut guard = self
29 .inner
30 .write()
31 .map_err(|e| SynapticError::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#[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, SynapticError> {
58 let tool = self
59 .registry
60 .get(tool_name)
61 .ok_or_else(|| SynapticError::ToolNotFound(tool_name.to_string()))?;
62 tool.call(args).await
63 }
64}