brainwires_tool_system/executor.rs
1//! Tool Executor trait
2//!
3//! Defines the [`ToolExecutor`] trait for abstracted tool execution.
4//! Framework crates like `brainwires-agents` depend on this trait
5//! to call tools without coupling to any concrete implementation.
6
7use anyhow::Result;
8use async_trait::async_trait;
9
10use brainwires_core::{Tool, ToolContext, ToolResult, ToolUse};
11
12/// Trait for executing tools in an agent context.
13///
14/// Implement this on your tool executor to integrate with framework agents
15/// like `TaskAgent`. The trait is object-safe and can be used as
16/// `Arc<dyn ToolExecutor>`.
17///
18/// # Example
19///
20/// ```rust,ignore
21/// use brainwires_tool_system::ToolExecutor;
22/// use brainwires_core::{Tool, ToolContext, ToolResult, ToolUse};
23/// use async_trait::async_trait;
24///
25/// struct MyExecutor;
26///
27/// #[async_trait]
28/// impl ToolExecutor for MyExecutor {
29/// async fn execute(&self, tool_use: &ToolUse, context: &ToolContext) -> anyhow::Result<ToolResult> {
30/// Ok(ToolResult::success(tool_use.id.clone(), "done".to_string()))
31/// }
32///
33/// fn available_tools(&self) -> Vec<Tool> {
34/// vec![]
35/// }
36/// }
37/// ```
38#[async_trait]
39pub trait ToolExecutor: Send + Sync {
40 /// Execute a tool and return its result.
41 ///
42 /// The `tool_use` contains the tool name and input parameters.
43 /// The `context` provides working directory and execution metadata.
44 async fn execute(&self, tool_use: &ToolUse, context: &ToolContext) -> Result<ToolResult>;
45
46 /// Return the list of tools available for the AI to invoke.
47 fn available_tools(&self) -> Vec<Tool>;
48}
49
50/// Decision returned by a [`ToolPreHook`] before a tool call.
51#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
52pub enum PreHookDecision {
53 /// Allow the tool call to proceed normally.
54 Allow,
55 /// Reject the call; inject this message as `ToolResult::error`.
56 Reject(String),
57}
58
59/// Pluggable pre-execution hook for semantic tool validation.
60///
61/// Implement this to intercept tool calls before execution and validate
62/// call intent against current agent state (not just JSON schema).
63/// Hook is set via `AgentContext::with_pre_execute_hook()`.
64#[async_trait]
65pub trait ToolPreHook: Send + Sync {
66 /// Called before tool execution to validate or reject the call.
67 async fn before_execute(
68 &self,
69 tool_use: &ToolUse,
70 context: &ToolContext,
71 ) -> Result<PreHookDecision>;
72}