use std::sync::Arc;
use async_trait::async_trait;
use zagens_core::engine::{
EngineToolDispatch, tool_call_input, tool_name_is_mutating, tool_result_to_output,
};
use zagens_protocol::ToolOutput;
use zagens_tools::{FunctionCallError, ToolCall};
use crate::tools::ToolRegistry;
pub(crate) use zagens_core::engine::{
function_call_to_tool_error, tool_output_to_result, value_to_tool_call,
};
pub(crate) struct RegistryToolDispatch<'a> {
registry: &'a ToolRegistry,
}
impl<'a> RegistryToolDispatch<'a> {
#[must_use]
pub(crate) fn new(registry: &'a ToolRegistry) -> Self {
Self { registry }
}
}
pub struct TuiEngineToolDispatch {
registry: Arc<ToolRegistry>,
}
impl TuiEngineToolDispatch {
#[must_use]
pub fn new(registry: Arc<ToolRegistry>) -> Self {
Self { registry }
}
}
#[async_trait]
impl EngineToolDispatch for TuiEngineToolDispatch {
async fn dispatch_tool(
&self,
call: ToolCall,
allow_mutating: bool,
) -> Result<ToolOutput, FunctionCallError> {
RegistryToolDispatch::new(self.registry.as_ref())
.dispatch_tool(call, allow_mutating)
.await
}
}
#[async_trait]
impl EngineToolDispatch for RegistryToolDispatch<'_> {
async fn dispatch_tool(
&self,
call: ToolCall,
allow_mutating: bool,
) -> Result<ToolOutput, FunctionCallError> {
let name = call.name.clone();
if !allow_mutating && tool_name_is_mutating(&name) {
return Err(FunctionCallError::MutatingToolRejected { name });
}
let input = tool_call_input(&call)?;
let result = self
.registry
.execute_full(&name, input)
.await
.map_err(|err| FunctionCallError::ExecutionFailed {
name: name.clone(),
error: zagens_core::engine::dispatch::format_tool_error(&err, &name),
})?;
Ok(tool_result_to_output(result))
}
}