Skip to main content

ftooling/
tool.rs

1//! Tool trait contract for registry-managed capabilities.
2//!
3//! ```rust
4//! use fprovider::ToolDefinition;
5//! use ftooling::{FunctionTool, Tool};
6//!
7//! let tool = FunctionTool::new(
8//!     ToolDefinition {
9//!         name: "echo".to_string(),
10//!         description: "Echoes input".to_string(),
11//!         input_schema: r#"{"type":"string"}"#.to_string(),
12//!     },
13//!     |args, _ctx| async move { Ok(args) },
14//! );
15//!
16//! assert_eq!(tool.definition().name, "echo");
17//! ```
18
19use std::future::Future;
20use std::sync::Arc;
21
22use fcommon::BoxFuture;
23use fprovider::ToolDefinition;
24
25use crate::{ToolError, ToolExecutionContext};
26
27pub type ToolFuture<'a, T> = BoxFuture<'a, T>;
28
29pub trait Tool: Send + Sync {
30    fn definition(&self) -> ToolDefinition;
31
32    fn invoke<'a>(
33        &'a self,
34        args_json: &'a str,
35        context: &'a ToolExecutionContext,
36    ) -> ToolFuture<'a, Result<String, ToolError>>;
37}
38
39type ToolHandler = dyn Fn(String, ToolExecutionContext) -> ToolFuture<'static, Result<String, ToolError>>
40    + Send
41    + Sync;
42
43pub struct FunctionTool {
44    definition: ToolDefinition,
45    handler: Arc<ToolHandler>,
46}
47
48impl FunctionTool {
49    pub fn new<F, Fut>(definition: ToolDefinition, handler: F) -> Self
50    where
51        F: Fn(String, ToolExecutionContext) -> Fut + Send + Sync + 'static,
52        Fut: Future<Output = Result<String, ToolError>> + Send + 'static,
53    {
54        let handler: Arc<ToolHandler> =
55            Arc::new(move |args_json, context| Box::pin(handler(args_json, context)));
56
57        Self {
58            definition,
59            handler,
60        }
61    }
62}
63
64impl Tool for FunctionTool {
65    fn definition(&self) -> ToolDefinition {
66        self.definition.clone()
67    }
68
69    fn invoke<'a>(
70        &'a self,
71        args_json: &'a str,
72        context: &'a ToolExecutionContext,
73    ) -> ToolFuture<'a, Result<String, ToolError>> {
74        let args_json = args_json.to_string();
75        let context = context.clone();
76        (self.handler)(args_json, context)
77    }
78}