1use harness_core::{Action, Tool, ToolError, ToolResult, ToolRisk, ToolSchema, World};
4use std::collections::HashMap;
5use std::sync::Arc;
6
7#[derive(Default)]
8pub struct ToolRegistry {
9 tools: HashMap<String, Arc<dyn Tool>>,
10}
11
12impl ToolRegistry {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn insert(&mut self, t: Arc<dyn Tool>) {
18 self.tools.insert(t.name().to_string(), t);
19 }
20
21 pub fn schemas(&self) -> Vec<ToolSchema> {
26 let mut v: Vec<ToolSchema> = self.tools.values().map(|t| t.schema().clone()).collect();
27 v.sort_by(|a, b| a.name.cmp(&b.name));
28 v
29 }
30
31 pub async fn dispatch(
32 &self,
33 action: &Action,
34 world: &mut World,
35 ) -> Result<ToolResult, ToolError> {
36 let tool = self
37 .tools
38 .get(&action.tool)
39 .ok_or_else(|| ToolError::NotFound {
40 name: action.tool.clone(),
41 })?
42 .clone();
43 tool.invoke(action.args.clone(), world).await
44 }
45
46 pub fn risk(&self, name: &str) -> Option<ToolRisk> {
48 self.tools.get(name).map(|t| t.risk())
49 }
50
51 pub fn len(&self) -> usize {
52 self.tools.len()
53 }
54 pub fn is_empty(&self) -> bool {
55 self.tools.is_empty()
56 }
57}