Skip to main content

synapto_interface/
tool.rs

1#![doc = include_str!("tool.md")]
2
3use crate::context::ContextRequest;
4use crate::llm::LLMSafe;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8#[async_trait::async_trait]
9pub trait Tool: Send + Sync + 'static {
10    type Arguments: schemars::JsonSchema
11        + serde::de::DeserializeOwned
12        + LLMSafe
13        + Send
14        + Sync
15        + 'static;
16    const NAME: &'static str;
17    const DESCRIPTION: &'static str;
18    #[doc = " Evaluated dynamically every turn AFTER the ContextProviders have compiled the World State."]
19    #[doc = " `compiled_context` is the JSON value generated by all ContextProviders that the LLM is about to see."]
20    async fn is_available(
21        &self,
22        _ctx_request: &ContextRequest,
23        _compiled_context: &serde_json::Value,
24    ) -> Result<bool, String> {
25        Ok(true)
26    }
27    #[doc = " Executes the tool. The result is serialized and fed back to the LLM."]
28    async fn execute(
29        &self,
30        ctx_request: &ContextRequest,
31        args: Self::Arguments,
32    ) -> Result<serde_json::Value, String>;
33}
34
35#[async_trait::async_trait]
36pub trait ErasedTool: Send + Sync + 'static {
37    fn name(&self) -> &'static str;
38    fn description(&self) -> &'static str;
39    fn schema(&self) -> schemars::Schema;
40    async fn erased_is_available(
41        &self,
42        ctx_request: &ContextRequest,
43        compiled_context: &serde_json::Value,
44    ) -> Result<bool, String>;
45    async fn erased_execute(
46        &self,
47        ctx_request: &ContextRequest,
48        args: serde_json::Value,
49    ) -> Result<serde_json::Value, String>;
50}
51
52#[async_trait::async_trait]
53impl<T> ErasedTool for T
54where
55    T: Tool,
56{
57    fn name(&self) -> &'static str {
58        <T as Tool>::NAME
59    }
60    fn description(&self) -> &'static str {
61        <T as Tool>::DESCRIPTION
62    }
63    fn schema(&self) -> schemars::Schema {
64        schemars::schema_for!(<T as Tool>::Arguments)
65    }
66    async fn erased_is_available(
67        &self,
68        ctx_request: &ContextRequest,
69        compiled_context: &serde_json::Value,
70    ) -> Result<bool, String> {
71        <T as Tool>::is_available(self, ctx_request, compiled_context).await
72    }
73    async fn erased_execute(
74        &self,
75        ctx_request: &ContextRequest,
76        args: serde_json::Value,
77    ) -> Result<serde_json::Value, String> {
78        let parsed_args = serde_json::from_value(args).map_err(|e| e.to_string())?;
79        <T as Tool>::execute(self, ctx_request, parsed_args).await
80    }
81}
82
83#[derive(Default)]
84pub struct ToolRegistryBuilder {
85    pub tools: std::sync::RwLock<std::collections::HashMap<String, std::sync::Arc<dyn ErasedTool>>>,
86}
87
88impl ToolRegistryBuilder {
89    pub fn register<T>(&self, tool: T)
90    where
91        T: ErasedTool + 'static,
92    {
93        let tool_arc: std::sync::Arc<dyn ErasedTool> = std::sync::Arc::new(tool);
94        self.register_erased(tool_arc);
95    }
96    pub fn register_erased(&self, tool: std::sync::Arc<dyn ErasedTool>) {
97        self.tools
98            .write()
99            .unwrap_or_else(|e| panic!("Failed to acquire write lock on tools: {:?}", e))
100            .insert(tool.name().to_string(), tool);
101    }
102    pub fn get(&self, name: &str) -> Option<std::sync::Arc<dyn ErasedTool>> {
103        self.tools
104            .read()
105            .unwrap_or_else(|e| panic!("Failed to acquire read lock on tools: {:?}", e))
106            .get(name)
107            .cloned()
108    }
109    pub fn get_all(&self) -> Vec<std::sync::Arc<dyn ErasedTool>> {
110        self.tools
111            .read()
112            .unwrap_or_else(|e| panic!("Failed to acquire read lock on tools: {:?}", e))
113            .values()
114            .cloned()
115            .collect()
116    }
117}
118
119#[derive(
120    Serialize,
121    Deserialize,
122    JsonSchema,
123    PartialEq,
124    Eq,
125    Debug,
126    Clone,
127    derive_more :: Display,
128    derive_more :: From,
129    derive_more :: Deref,
130)]
131pub struct ToolCallId(pub String);