The tool system in Agent Air is built around the Executable trait, providing a standardized way to define, register, and execute tools that the LLM can invoke.

The Executable Trait

At the heart of the tool system is the Executable trait. Any functionality that needs to be exposed as a tool must implement this trait.

#[async_trait]
pub trait Executable: Send + Sync {
    /// The unique name of the tool
    fn name(&self) -> &str;

    /// A detailed description of what the tool does
    fn description(&self) -> &str;

    /// The JSON schema defining the tool's input parameters
    fn input_schema(&self) -> serde_json::Value;

    /// The execution logic for the tool
    async fn execute(&self, context: ToolContext, input: serde_json::Value) -> ToolResult;
}

Key Components

  • name: Used by the LLM to identify and call the tool.
  • description: Helps the LLM understand when and how to use the tool.
  • input_schema: A JSON Schema that ensures the LLM provides correctly typed arguments.
  • execute: The async function that performs the actual work, receiving a ToolContext for system interactions.

ToolContext

The ToolContext is passed to every tool execution. It provides access to system-level resources and state without exposing the entire controller.

pub struct ToolContext {
    pub session_id: String,
    pub interaction_registry: Arc<UserInteractionRegistry>,
    pub permission_registry: Arc<PermissionRegistry>,
    pub cancellation_token: CancellationToken,
}

Tools use this context to:

  • Request user input via the interaction_registry.
  • Check or request permissions via the permission_registry.
  • Respect execution timeouts or user cancellations via the cancellation_token.

ToolDefinition

While Executable defines the implementation, ToolDefinition is the data structure used to communicate tool capabilities to the LLM providers.

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolDefinition {
    pub name: String,
    pub description: String,
    pub input_schema: serde_json::Value,
}

The system automatically derives ToolDefinition from any Executable implementation to ensure consistency between implementation and what the LLM “sees”.