pub mod builtin;
pub mod knowledge_tool;
pub mod planning_tools;
pub mod search;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use crate::error::{AgentError, Result};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ToolStatus {
Success,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResult {
pub status: ToolStatus,
pub data: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl ToolResult {
pub fn ok(data: serde_json::Value) -> Self {
Self {
status: ToolStatus::Success,
data,
error: None,
}
}
pub fn ok_string(s: impl Into<String>) -> Self {
Self::ok(serde_json::Value::String(s.into()))
}
pub fn err(msg: impl Into<String>) -> Self {
Self {
status: ToolStatus::Error,
data: serde_json::Value::Null,
error: Some(msg.into()),
}
}
pub fn to_json_string(&self) -> String {
serde_json::to_string(self).unwrap_or_else(|_| format!("{:?}", self))
}
pub fn status_str(&self) -> &str {
match self.status {
ToolStatus::Success => "success",
ToolStatus::Error => "error",
}
}
}
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn parameters_schema(&self) -> serde_json::Value;
async fn execute(&self, args: serde_json::Value) -> ToolResult;
fn to_definition(&self) -> llm_cascade::ToolDefinition {
llm_cascade::ToolDefinition {
name: self.name().to_owned(),
description: self.description().to_owned(),
parameters: self.parameters_schema(),
}
}
}
pub struct ToolRegistry {
tools: Arc<std::sync::Mutex<HashMap<String, Arc<dyn Tool>>>>,
}
impl Default for ToolRegistry {
fn default() -> Self {
Self::new()
}
}
impl ToolRegistry {
pub fn new() -> Self {
Self {
tools: Arc::new(std::sync::Mutex::new(HashMap::new())),
}
}
pub fn register<T: Tool + 'static>(&self, tool: T) {
self.tools
.lock()
.unwrap()
.insert(tool.name().to_owned(), Arc::new(tool));
}
pub fn register_arc(&self, tool: Arc<dyn Tool>) {
self.tools
.lock()
.unwrap()
.insert(tool.name().to_owned(), tool);
}
pub fn get(&self, name: &str) -> Option<Arc<dyn Tool>> {
self.tools.lock().unwrap().get(name).cloned()
}
pub fn tool_names(&self) -> Vec<String> {
self.tools.lock().unwrap().keys().cloned().collect()
}
pub fn all_tools(&self) -> Vec<Arc<dyn Tool>> {
self.tools.lock().unwrap().values().cloned().collect()
}
pub fn tool_definitions(&self) -> Vec<llm_cascade::ToolDefinition> {
self.tools
.lock()
.unwrap()
.values()
.map(|t| t.to_definition())
.collect()
}
pub async fn execute(&self, name: &str, args: serde_json::Value) -> Result<ToolResult> {
let tool = self.get(name).ok_or_else(|| AgentError::ToolFailed {
tool: name.to_owned(),
reason: format!("Tool '{}' is not registered", name),
})?;
Ok(tool.execute(args).await)
}
pub fn register_list_tools(&self) {
let names = self.tool_names();
let tools = self.all_tools();
self.register(builtin::ListToolsTool::new(names, tools));
}
}