1use crate::context::RunContext;
4use crate::errors::{AgentError, Result};
5use async_trait::async_trait;
6use serde_json::Value;
7use std::sync::Arc;
8
9#[async_trait]
14pub trait Tool: Send + Sync {
15 fn name(&self) -> &str;
17
18 fn description(&self) -> &str;
20
21 fn json_schema(&self) -> Value;
23
24 async fn invoke(&self, ctx: &RunContext, args: &str) -> Result<String>;
33}
34
35pub struct FunctionTool {
37 name: String,
38 description: String,
39 json_schema: Value,
40 handler: Arc<dyn Fn(&RunContext, Value) -> Result<String> + Send + Sync>,
41}
42
43impl FunctionTool {
44 pub fn new(
46 name: impl Into<String>,
47 description: impl Into<String>,
48 json_schema: Value,
49 handler: impl Fn(&RunContext, Value) -> Result<String> + Send + Sync + 'static,
50 ) -> Self {
51 Self {
52 name: name.into(),
53 description: description.into(),
54 json_schema,
55 handler: Arc::new(handler),
56 }
57 }
58
59 pub fn builder(name: impl Into<String>) -> FunctionToolBuilder {
61 FunctionToolBuilder {
62 name: name.into(),
63 description: String::new(),
64 json_schema: Value::Null,
65 handler: None,
66 }
67 }
68}
69
70#[async_trait]
71impl Tool for FunctionTool {
72 fn name(&self) -> &str {
73 &self.name
74 }
75
76 fn description(&self) -> &str {
77 &self.description
78 }
79
80 fn json_schema(&self) -> Value {
81 self.json_schema.clone()
82 }
83
84 async fn invoke(&self, ctx: &RunContext, args: &str) -> Result<String> {
85 let value: Value =
86 serde_json::from_str(args).map_err(|e| AgentError::InvalidJson(e.to_string()))?;
87 (self.handler)(ctx, value)
88 }
89}
90
91pub struct FunctionToolBuilder {
93 name: String,
94 description: String,
95 json_schema: Value,
96 handler: Option<Arc<dyn Fn(&RunContext, Value) -> Result<String> + Send + Sync>>,
97}
98
99impl FunctionToolBuilder {
100 pub fn description(mut self, desc: impl Into<String>) -> Self {
102 self.description = desc.into();
103 self
104 }
105
106 pub fn schema(mut self, schema: Value) -> Self {
108 self.json_schema = schema;
109 self
110 }
111
112 pub fn handler<F>(mut self, f: F) -> Self
114 where
115 F: Fn(&RunContext, Value) -> Result<String> + Send + Sync + 'static,
116 {
117 self.handler = Some(Arc::new(f));
118 self
119 }
120
121 pub fn build(self) -> Result<FunctionTool> {
123 let handler = self
124 .handler
125 .ok_or_else(|| AgentError::Configuration("Tool handler not set".to_string()))?;
126
127 Ok(FunctionTool {
128 name: self.name,
129 description: self.description,
130 json_schema: self.json_schema,
131 handler,
132 })
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use serde_json::json;
140
141 #[tokio::test]
142 async fn test_function_tool() {
143 let tool = FunctionTool::builder("test_tool")
144 .description("A test tool")
145 .schema(json!({"type": "object"}))
146 .handler(|_ctx, _args| Ok("test result".to_string()))
147 .build()
148 .unwrap();
149
150 assert_eq!(tool.name(), "test_tool");
151 assert_eq!(tool.description(), "A test tool");
152
153 let ctx = RunContext::new();
154 let result = tool.invoke(&ctx, "{}").await.unwrap();
155 assert_eq!(result, "test result");
156 }
157}