enact_core/tool/
function.rs1use super::Tool;
4use async_trait::async_trait;
5use serde_json::Value;
6use std::future::Future;
7use std::pin::Pin;
8use std::sync::Arc;
9
10pub type ToolFn =
12 Arc<dyn Fn(Value) -> Pin<Box<dyn Future<Output = anyhow::Result<Value>> + Send>> + Send + Sync>;
13
14pub struct FunctionTool {
16 name: String,
17 description: String,
18 parameters: Value,
19 func: ToolFn,
20}
21
22impl FunctionTool {
23 pub fn new<F, Fut>(
25 name: impl Into<String>,
26 description: impl Into<String>,
27 parameters: Value,
28 func: F,
29 ) -> Self
30 where
31 F: Fn(Value) -> Fut + Send + Sync + 'static,
32 Fut: Future<Output = anyhow::Result<Value>> + Send + 'static,
33 {
34 let func = Arc::new(move |args: Value| {
35 let fut = func(args);
36 Box::pin(fut) as Pin<Box<dyn Future<Output = anyhow::Result<Value>> + Send>>
37 });
38
39 Self {
40 name: name.into(),
41 description: description.into(),
42 parameters,
43 func,
44 }
45 }
46
47 pub fn simple<F, Fut>(name: impl Into<String>, description: impl Into<String>, func: F) -> Self
49 where
50 F: Fn(Value) -> Fut + Send + Sync + 'static,
51 Fut: Future<Output = anyhow::Result<Value>> + Send + 'static,
52 {
53 Self::new(
54 name,
55 description,
56 serde_json::json!({
57 "type": "object",
58 "properties": {},
59 "required": []
60 }),
61 func,
62 )
63 }
64}
65
66#[async_trait]
67impl Tool for FunctionTool {
68 fn name(&self) -> &str {
69 &self.name
70 }
71
72 fn description(&self) -> &str {
73 &self.description
74 }
75
76 fn parameters_schema(&self) -> Value {
77 self.parameters.clone()
78 }
79
80 async fn execute(&self, args: Value) -> anyhow::Result<Value> {
81 (self.func)(args).await
82 }
83}
84
85#[macro_export]
87macro_rules! tool {
88 ($name:expr, $desc:expr, |$args:ident| $body:expr) => {
89 FunctionTool::new(
90 $name,
91 $desc,
92 serde_json::json!({"type": "object", "properties": {}}),
93 |$args| async move { $body },
94 )
95 };
96}