langchain_rust/tools/function_tool/
mod.rs1use std::{error::Error, future::Future, marker::PhantomData};
2
3use async_trait::async_trait;
4use serde::de::DeserializeOwned;
5use serde_json::{json, Value};
6
7use super::Tool;
8
9pub struct FunctionTool<T, F> {
39 name: String,
40 description: String,
41 parameters: Value,
42 func: F,
43 _input: PhantomData<fn() -> T>,
45}
46
47impl<T, F> FunctionTool<T, F> {
48 pub fn new<N: Into<String>, D: Into<String>>(
49 name: N,
50 description: D,
51 parameters: Value,
52 func: F,
53 ) -> Self {
54 Self {
55 name: name.into(),
56 description: description.into(),
57 parameters,
58 func,
59 _input: PhantomData,
60 }
61 }
62}
63
64impl<F> FunctionTool<String, F> {
65 pub fn text<N: Into<String>, D: Into<String>>(name: N, description: D, func: F) -> Self {
68 let description = description.into();
69 let parameters = json!({
70 "type": "object",
71 "properties": {
72 "input": { "type": "string", "description": description }
73 },
74 "required": ["input"]
75 });
76 Self::new(name, description, parameters, func)
77 }
78}
79
80impl<T: DeserializeOwned, F> FunctionTool<T, F> {
81 fn decode(&self, value: Value) -> Result<T, Box<dyn Error>> {
86 let first_err = match serde_json::from_value::<T>(value.clone()) {
87 Ok(input) => return Ok(input),
88 Err(e) => e,
89 };
90 let fallbacks = [
91 value.get("input").cloned(),
92 value.as_str().and_then(|s| serde_json::from_str(s).ok()),
93 (!value.is_string()).then(|| Value::String(value.to_string())),
94 ];
95 fallbacks
96 .into_iter()
97 .flatten()
98 .find_map(|candidate| serde_json::from_value::<T>(candidate).ok())
99 .ok_or_else(|| {
100 format!(
101 "invalid input for tool `{}`: {first_err}. Expected arguments matching: {}",
102 self.name, self.parameters
103 )
104 .into()
105 })
106 }
107}
108
109#[async_trait]
110impl<T, F, Fut, O, E> Tool for FunctionTool<T, F>
111where
112 T: DeserializeOwned + Send + 'static,
113 F: Fn(T) -> Fut + Send + Sync,
114 Fut: Future<Output = Result<O, E>> + Send,
115 O: ToString,
116 E: Into<Box<dyn Error>>,
117{
118 fn name(&self) -> String {
119 self.name.clone()
120 }
121
122 fn description(&self) -> String {
123 self.description.clone()
124 }
125
126 fn parameters(&self) -> Value {
127 self.parameters.clone()
128 }
129
130 async fn parse_input(&self, input: &str) -> Value {
133 serde_json::from_str(input).unwrap_or_else(|_| Value::String(input.to_string()))
134 }
135
136 async fn run(&self, input: Value) -> Result<String, Box<dyn Error>> {
137 let input = self.decode(input)?;
138 (self.func)(input)
139 .await
140 .map(|output| output.to_string())
141 .map_err(Into::into)
142 }
143}
144
145#[cfg(test)]
146mod tests;