use std::future::Future;
use std::pin::Pin;
use opi_ai::message::{OutputContent, ToolDef};
use tokio_util::sync::CancellationToken;
pub type UpdateCallback = Box<dyn Fn(serde_json::Value) + Send + Sync>;
pub trait Tool: Send + Sync {
fn definition(&self) -> ToolDef;
fn execute(
&self,
call_id: &str,
arguments: serde_json::Value,
signal: CancellationToken,
on_update: Option<UpdateCallback>,
) -> Pin<Box<dyn Future<Output = Result<ToolResult, ToolError>> + Send>>;
fn execution_mode(&self) -> ExecutionMode {
ExecutionMode::Parallel
}
}
#[derive(Clone)]
pub struct ToolResult {
pub content: Vec<OutputContent>,
pub details: Option<serde_json::Value>,
pub is_error: bool,
pub terminate: bool,
}
impl ToolResult {
pub fn from_validation_error(err: crate::validation::ValidationError) -> Self {
let message = err.to_string();
Self {
content: vec![OutputContent::Text { text: message }],
details: None,
is_error: true,
terminate: false,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum ToolError {
#[error("execution failed: {0}")]
ExecutionFailed(String),
#[error("cancelled")]
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExecutionMode {
Sequential,
Parallel,
}