use serde::{Deserialize, Serialize};
use crate::{Attachment, ToolCapabilities, ToolRuntime};
pub trait Tool: Send + Sync {
fn name(&self) -> &'static str;
fn description(&self) -> &'static str;
fn input_schema(&self) -> serde_json::Value;
fn execute(&self, input: serde_json::Value) -> Result<ToolResult, ToolError>;
fn execute_with_runtime(
&self,
input: serde_json::Value,
runtime: &dyn ToolRuntime,
) -> Result<ToolResult, ToolError> {
let _ = runtime;
self.execute(input)
}
fn timeout_secs(&self) -> Option<u64> {
None
}
fn capabilities(&self) -> ToolCapabilities {
ToolCapabilities::default()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResult {
pub output: String,
pub media: Vec<Attachment>,
pub is_error: bool,
}
impl ToolResult {
#[must_use]
pub fn success(output: impl Into<String>) -> Self {
Self {
output: output.into(),
media: Vec::new(),
is_error: false,
}
}
#[must_use]
pub fn error(output: impl Into<String>) -> Self {
Self {
output: output.into(),
media: Vec::new(),
is_error: true,
}
}
#[must_use]
pub fn with_media(mut self, attachment: Attachment) -> Self {
self.media.push(attachment);
self
}
#[must_use]
pub fn with_media_many(mut self, media: impl IntoIterator<Item = Attachment>) -> Self {
self.media.extend(media);
self
}
}
#[derive(Debug)]
pub enum ToolError {
InvalidInput(String),
ExecutionFailed(String),
}
impl std::fmt::Display for ToolError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::InvalidInput(e) => write!(f, "invalid input: {e}"),
Self::ExecutionFailed(e) => write!(f, "execution failed: {e}"),
}
}
}
impl std::error::Error for ToolError {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginInfo {
pub name: String,
pub version: String,
pub description: String,
}
pub trait MultiToolPlugin: Send + Sync {
fn plugin_info(&self) -> PluginInfo;
fn create_tools(&self) -> Vec<Box<dyn Tool>>;
}