Skip to main content

Tool

Trait Tool 

Source
pub trait Tool: Send + Sync {
    // Required methods
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn input_schema(&self) -> Value;
    fn execute<'life0, 'life1, 'async_trait>(
        &'life0 self,
        input: Value,
        ctx: &'life1 ToolContext,
    ) -> Pin<Box<dyn Future<Output = Result<ToolOutput, ToolError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;

    // Provided methods
    fn class(&self) -> ToolClass { ... }
    fn is_recursive(&self) -> bool { ... }
}
Expand description

Trait for tools that the agent can use.

Implement this trait to create custom tools.

§Example

use tkach::{Tool, ToolContext, ToolOutput, ToolError};
use serde_json::{json, Value};

struct MyTool;

#[async_trait::async_trait]
impl Tool for MyTool {
    fn name(&self) -> &str { "my_tool" }
    fn description(&self) -> &str { "Does something useful" }
    fn input_schema(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "query": { "type": "string" }
            },
            "required": ["query"]
        })
    }
    async fn execute(&self, input: Value, ctx: &ToolContext) -> Result<ToolOutput, ToolError> {
        let query = input["query"].as_str().unwrap_or_default();
        Ok(ToolOutput::text(format!("Result for: {query}")))
    }
}

Required Methods§

Source

fn name(&self) -> &str

Unique name of the tool (used by the LLM to invoke it).

Source

fn description(&self) -> &str

Human-readable description of what the tool does.

Source

fn input_schema(&self) -> Value

JSON Schema describing the tool’s input parameters.

Source

fn execute<'life0, 'life1, 'async_trait>( &'life0 self, input: Value, ctx: &'life1 ToolContext, ) -> Pin<Box<dyn Future<Output = Result<ToolOutput, ToolError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Execute the tool with the given input.

Provided Methods§

Source

fn class(&self) -> ToolClass

Side-effect class. Defaults to Mutating — the safe choice for tools that are not explicitly marked read-only. Override to return ToolClass::ReadOnly only when you are certain the tool has no observable side effects.

Source

fn is_recursive(&self) -> bool

Whether this tool itself drives nested executor work — i.e. the tool’s execute body holds the executor task open while running another Agent::run underneath. The canonical example is SubAgent.

The executor uses this to admit recursive tools through the concurrent-mutator pool regardless of explicit promotion, because non-recursive admission classes (the width-1 serial_mut pool, in particular) are shared across the agent tree and would deadlock when a parent’s permit is pinned during the child’s nested execute. Routing recursive tools through concurrent_mut — which the executor forks per nesting level — keeps nested fan-out free of pool contention while still bounding it by the max_concurrent_mutations cap of the current level.

Defaults to false. Override to true for tools whose execute body drives nested executor work.

When you override this, the recursive call site must run against an executor obtained from ctx.executor.fork_for_subagent() — not directly against ctx.executor. The fork is what gives the nested level its own concurrent_mut and per-tool semaphores; without it, a parent saturating those pools would deadlock the moment any child tried to acquire a permit from the same shared semaphore. The canonical pattern is to construct an Agent::builder().executor(ctx.executor.fork_for_subagent()) and agent.run(...) from inside execute; SubAgent implements exactly this shape.

Implementors§