use super::{ToolCapabilities, ToolContext, ToolRegistry, ToolResult};
use async_trait::async_trait;
use serde_json::Value;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum HostDirectPolicy {
TrustedControlPlane,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum InvocationOrigin {
Agent,
Nested,
HostDirect(HostDirectPolicy),
}
#[derive(Debug, Clone)]
pub(crate) struct ToolInvocation {
pub(crate) id: String,
pub(crate) name: String,
pub(crate) args: Value,
pub(crate) origin: InvocationOrigin,
pub(crate) recent_tools: Vec<String>,
}
impl ToolInvocation {
pub(crate) fn agent(
id: impl Into<String>,
name: impl Into<String>,
args: Value,
recent_tools: Vec<String>,
) -> Self {
Self {
id: id.into(),
name: name.into(),
args,
origin: InvocationOrigin::Agent,
recent_tools,
}
}
pub(crate) fn nested(name: impl Into<String>, args: Value) -> Self {
let name = name.into();
Self {
id: format!("nested-{name}-{}", uuid::Uuid::new_v4()),
name,
args,
origin: InvocationOrigin::Nested,
recent_tools: Vec::new(),
}
}
pub(crate) fn host_direct(id: impl Into<String>, name: impl Into<String>, args: Value) -> Self {
Self {
id: id.into(),
name: name.into(),
args,
origin: InvocationOrigin::HostDirect(HostDirectPolicy::TrustedControlPlane),
recent_tools: Vec::new(),
}
}
}
#[async_trait]
pub(crate) trait ToolInvoker: Send + Sync {
async fn invoke(&self, invocation: ToolInvocation, ctx: &ToolContext) -> ToolResult;
fn available_tools(&self) -> Vec<String>;
fn capabilities(&self, _name: &str, _args: &Value) -> Option<ToolCapabilities> {
None
}
}
struct RegistryToolInvoker {
registry: Arc<ToolRegistry>,
}
#[async_trait]
impl ToolInvoker for RegistryToolInvoker {
async fn invoke(&self, invocation: ToolInvocation, ctx: &ToolContext) -> ToolResult {
let invocation_ctx = match ctx.enter_tool_invocation(&invocation.name) {
Ok(ctx) => ctx,
Err(message) => return ToolResult::error(&invocation.name, message),
};
match self
.registry
.execute_with_context(&invocation.name, &invocation.args, &invocation_ctx)
.await
{
Ok(result) => result,
Err(error) => {
ToolResult::error(&invocation.name, format!("Tool execution error: {error}"))
}
}
}
fn available_tools(&self) -> Vec<String> {
self.registry.list()
}
fn capabilities(&self, name: &str, args: &Value) -> Option<ToolCapabilities> {
self.registry.capabilities(name, args)
}
}
pub(crate) fn registry_tool_invoker(registry: Arc<ToolRegistry>) -> Arc<dyn ToolInvoker> {
Arc::new(RegistryToolInvoker { registry })
}