The ToolRegistry is a centralized, thread-safe repository for all tools available to an agent. It manages the lifecycle of Executable implementations and provides an interface for the LLM controller to discover and retrieve tools.

Implementation Details

The ToolRegistry is implemented using an RwLock to allow for concurrent reads and synchronized writes. It stores tools as Arc<dyn Executable>, ensuring they can be safely shared across threads.

pub struct ToolRegistry {
    tools: RwLock<HashMap<String, Arc<dyn Executable>>>,
}

Key Operations

Registration

Tools are typically registered during the agent’s initialization phase. The registry ensures that each tool has a unique name.

impl ToolRegistry {
    pub fn register(&self, tool: Arc<dyn Executable>) {
        let mut tools = self.tools.write().unwrap();
        tools.insert(tool.name().to_string(), tool);
    }
}

Lookup

When the LLM requests a tool call, the controller uses the registry to find the corresponding implementation.

pub fn get(&self, name: &str) -> Option<Arc<dyn Executable>> {
    let tools = self.tools.read().unwrap();
    tools.get(name).cloned()
}

Listing Tool Definitions

To inform the LLM about available capabilities, the registry can generate a list of ToolDefinition objects. This is used during the provider’s request construction.

pub fn get_definitions(&self) -> Vec<ToolDefinition> {
    let tools = self.tools.read().unwrap();
    tools.values()
        .map(|t| ToolDefinition {
            name: t.name().to_string(),
            description: t.description().to_string(),
            input_schema: t.input_schema(),
        })
        .collect()
}

Global vs. Local Registration

While most tools are registered globally when the AgentAir is built, the system also supports dynamic tool registration if needed by specific extensions or plugins. This is handled via the ExtensionContext.

Thread Safety

Since tool execution can happen in parallel and the LLM controller might be processing multiple requests, the ToolRegistry uses std::sync::RwLock (or tokio::sync::RwLock depending on the specific runtime requirements) to ensure that tool lookups are fast and non-blocking for concurrent readers.