pub trait ToolExecutor: Send + Sync {
// Required method
fn execute(
&self,
response: &str,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send;
// Provided methods
fn execute_confirmed(
&self,
response: &str,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send { ... }
fn tool_definitions(&self) -> Vec<ToolDef> { ... }
fn execute_tool_call(
&self,
_call: &ToolCall,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send { ... }
fn execute_tool_call_confirmed(
&self,
call: &ToolCall,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send { ... }
fn set_skill_env(&self, _env: Option<HashMap<String, String>>) { ... }
fn set_effective_trust(&self, _level: SkillTrustLevel) { ... }
fn is_tool_retryable(&self, _tool_id: &str) -> bool { ... }
}Expand description
Async trait for tool execution backends.
Implementations include ShellExecutor,
WebScrapeExecutor, CompositeExecutor,
and FileExecutor.
§Contract
executeandexecute_tool_callreturnOk(None)when the executor does not handle the given input — callers must not treatNoneas an error.- All methods must be
Send + Syncand free of blocking I/O. - Implementations must enforce their own security controls (blocklists, sandboxes, SSRF protection) before executing any side-effectful operation.
execute_confirmedandexecute_tool_call_confirmedbypass confirmation gates only — all other security controls remain active.
§Two Invocation Paths
Legacy fenced blocks: The agent loop passes the raw LLM response string to execute.
The executor parses ```bash or ```scrape blocks and executes each one.
Structured tool calls: The agent loop constructs a ToolCall from the LLM’s
JSON tool-use response and dispatches it via execute_tool_call.
This is the preferred path for new code.
§Example
use zeph_tools::{ToolExecutor, ToolCall, ToolOutput, ToolError, executor::ClaimSource};
#[derive(Debug)]
struct EchoExecutor;
impl ToolExecutor for EchoExecutor {
async fn execute(&self, _response: &str) -> Result<Option<ToolOutput>, ToolError> {
Ok(None) // not a fenced-block executor
}
async fn execute_tool_call(&self, call: &ToolCall) -> Result<Option<ToolOutput>, ToolError> {
if call.tool_id != "echo" {
return Ok(None);
}
let text = call.params.get("text")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_owned();
Ok(Some(ToolOutput {
tool_name: "echo".into(),
summary: text,
blocks_executed: 1,
filter_stats: None,
diff: None,
streamed: false,
terminal_id: None,
locations: None,
raw_response: None,
claim_source: None,
}))
}
}Required Methods§
Provided Methods§
Sourcefn execute_confirmed(
&self,
response: &str,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send
fn execute_confirmed( &self, response: &str, ) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send
Sourcefn tool_definitions(&self) -> Vec<ToolDef>
fn tool_definitions(&self) -> Vec<ToolDef>
Return the tool definitions this executor can handle.
Used to populate the LLM’s tool schema at context-assembly time.
Returns an empty Vec by default (for executors that only handle fenced blocks).
Sourcefn execute_tool_call(
&self,
_call: &ToolCall,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send
fn execute_tool_call( &self, _call: &ToolCall, ) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send
Sourcefn execute_tool_call_confirmed(
&self,
call: &ToolCall,
) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send
fn execute_tool_call_confirmed( &self, call: &ToolCall, ) -> impl Future<Output = Result<Option<ToolOutput>, ToolError>> + Send
Execute a structured tool call bypassing confirmation checks.
Called after the user has explicitly approved the tool invocation.
Default implementation delegates to execute_tool_call.
§Errors
Returns ToolError on execution failure.
Sourcefn set_skill_env(&self, _env: Option<HashMap<String, String>>)
fn set_skill_env(&self, _env: Option<HashMap<String, String>>)
Inject environment variables for the currently active skill. No-op by default.
Called by the agent loop before each turn when the active skill specifies env vars.
Implementations that ignore this (e.g. WebScrapeExecutor) may leave the default.
Sourcefn set_effective_trust(&self, _level: SkillTrustLevel)
fn set_effective_trust(&self, _level: SkillTrustLevel)
Set the effective trust level for the currently active skill. No-op by default.
Trust level affects which operations are permitted (e.g. network access, file writes).
Sourcefn is_tool_retryable(&self, _tool_id: &str) -> bool
fn is_tool_retryable(&self, _tool_id: &str) -> bool
Whether the executor can safely retry this tool call on a transient error.
Only idempotent operations (e.g. read-only HTTP GET) should return true.
Shell commands and other non-idempotent operations must keep the default false
to prevent double-execution of side-effectful commands.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.