1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
use std::error::Error;
use std::string::String;
use async_trait::async_trait;
use serde_json::{json, Value};
#[async_trait]
pub trait Tool: Send + Sync {
/// Returns the name of the tool.
fn name(&self) -> String;
/// Provides a description of what the tool does and when to use it.
fn description(&self) -> String;
/// This are the parametters for OpenAi-like function call.
/// You should return a jsnon like this one
/// ```json
/// {
/// "type": "object",
/// "properties": {
/// "command": {
/// "type": "string",
/// "description": "The raw command you want executed"
/// }
/// },
/// "required": ["command"]
/// }
///
/// If there s no implementation the defaul will be the self.description()
///```
fn parameters(&self) -> Value {
json!({
"type": "object",
"properties": {
"input": {
"type": "string",
"description":self.description()
}
},
"required": ["input"]
})
}
/// Processes an input string and executes the tool's functionality, returning a `Result`.
///
/// This function utilizes `parse_input` to parse the input and then calls `run`.
/// Its used by the Agent
async fn call(&self, input: &str) -> Result<String, Box<dyn Error>> {
let input = self.parse_input(input).await;
self.run(input).await
}
/// Executes the core functionality of the tool.
///
/// Example implementation:
/// ```rust,ignore
/// async fn run(&self, input: Value) -> Result<String, Box<dyn Error>> {
/// let input_str = input.as_str().ok_or("Input should be a string")?;
/// self.simple_search(input_str).await
/// }
/// ```
async fn run(&self, input: Value) -> Result<String, Box<dyn Error>>;
/// Parses the input string, which could be a JSON value or a raw string, depending on the LLM model.
///
/// Implement this function to extract the parameters needed for your tool. If a simple
/// string is sufficient, the default implementation can be used.
async fn parse_input(&self, input: &str) -> Value {
log::info!("Using default implementation: {}", input);
match serde_json::from_str::<Value>(input) {
Ok(input) => {
if input["input"].is_string() {
Value::String(input["input"].as_str().unwrap().to_string())
} else {
Value::String(input.to_string())
}
}
Err(_) => Value::String(input.to_string()),
}
}
}