Skip to content

ToolRegistry

Central registry for managing tools available to agents. Handles registration, lookup, execution, parameter validation, metadata inspection, and scoped sub-registries.

Import

import { ToolRegistry } from "@modernpath/agent-framework";

Constructor

class ToolRegistry {
  constructor()
}

The ToolRegistry is instantiated with no arguments. Tools are added after construction via register() or registerMultiple().

Methods

Registration

Method Signature Description
register (name: string, tool: ITool, metadata?: ToolMetadata): void Register a tool by name. If metadata is provided, it is used directly; otherwise metadata is read from the @Tool() decorator. Throws if the name is already registered or the tool lacks an execute method.
registerMultiple (tools: Array<{ name: string; tool: ITool }>): void Register multiple tools atomically. If any registration fails, all previously registered tools in the batch are rolled back.
unregister (name: string): void Remove a tool and its metadata from the registry.
clear (): void Remove all tools and metadata.

Lookup

Method Signature Description
get (name: string): ITool \| undefined Retrieve a tool instance by name.
has (name: string): boolean Check whether a tool is registered.
list (): string[] Return all registered tool names.

Execution

Method Signature Description
execute (name: string, params: Record<string, any>): Promise<any> Execute a tool by name with the given parameters. Calls tool.validate(params) first if the tool defines a validator. Throws if the tool is not found.
validateParameters (name: string, params: Record<string, any>): void Validate parameters against the tool's metadata schema without executing. Falls back to tool.validate() if no metadata parameters are defined.

Metadata

Method Signature Description
getMetadata (name: string): ToolMetadata \| undefined Get metadata for a specific tool. Checks the explicit metadata map first, then falls back to reading @Tool() decorator metadata from the instance.
getAllMetadata (): Map<string, ToolMetadata \| undefined> Get metadata for all registered tools.

Search & Filtering

Method Signature Description
search (criteria: { tags?: string[]; category?: string }): string[] Find tools by category or tags. Returns tool names that match the category exactly or share at least one tag.
hasCapability (requiredTools: string[]): boolean Check whether all of the given tool names are registered. Used by BaseAgent.hasCapability().
createScoped (toolNames: string[]): ToolRegistry Create a new ToolRegistry containing only the specified tools. The new registry shares tool instances (not copies) with the original.

Statistics

Method Signature Description
getStats (): RegistryStats Returns summary statistics about the registry.

RegistryStats shape:

{
  totalTools: number;
  categories: string[];   // distinct category values
  tags: string[];          // distinct tag values
}

Usage

Basic Registration and Execution

import { ToolRegistry, Tool, ITool } from "@modernpath/agent-framework";

@Tool({
  name: "weather",
  description: "Get current weather for a city",
  parameters: {
    city: { type: "string", description: "City name", required: true },
  },
  category: "external",
  tags: ["weather", "api"],
})
class WeatherTool implements ITool {
  async execute(params: Record<string, any>): Promise<any> {
    const response = await fetch(`https://api.weather.example/${params.city}`);
    return response.json();
  }
}

const registry = new ToolRegistry();
registry.register("weather", new WeatherTool());

// Execute directly
const forecast = await registry.execute("weather", { city: "Helsinki" });

// Validate without executing
registry.validateParameters("weather", { city: "Helsinki" }); // OK
registry.validateParameters("weather", {});                   // throws: Missing required parameter: city

Batch Registration

registry.registerMultiple([
  { name: "weather", tool: new WeatherTool() },
  { name: "geocode", tool: new GeocodeTool() },
  { name: "alerts",  tool: new AlertsTool() },
]);
// If any registration fails, all three are rolled back

Providing Explicit Metadata

When registering a tool that does not use the @Tool decorator (e.g., a plain object), pass metadata as the third argument:

const simpleTool: ITool = {
  async execute(params) {
    return { echo: params.message };
  },
};

registry.register("echo", simpleTool, {
  name: "echo",
  description: "Echoes the input message",
  parameters: {
    message: { type: "string", description: "Message to echo" },
  },
});

Searching Tools

// Find by category
const externalTools = registry.search({ category: "external" });
// => ["weather"]

// Find by tags
const apiTools = registry.search({ tags: ["api"] });
// => ["weather"]

// Check if all required tools are present
const ready = registry.hasCapability(["weather", "geocode"]);
// => true

Scoped Sub-registries

Use createScoped() to give an agent access to a subset of tools:

const allTools = new ToolRegistry();
allTools.register("weather", new WeatherTool());
allTools.register("geocode", new GeocodeTool());
allTools.register("admin-delete", new AdminDeleteTool());

// Create a scoped registry without the admin tool
const userRegistry = allTools.createScoped(["weather", "geocode"]);

const agent = new MyAgent(userRegistry);
// agent.getAvailableTools() => ["weather", "geocode"]

Scoped registries share tool instances

createScoped() does not clone tool objects. The scoped registry references the same instances as the parent. This is efficient but means tool state is shared.

Inspecting the Registry

// List all tools
console.log(registry.list());
// => ["weather", "geocode", "alerts"]

// Get metadata for one tool
const meta = registry.getMetadata("weather");
console.log(meta?.description); // "Get current weather for a city"

// Get all metadata
const allMeta = registry.getAllMetadata();
for (const [name, meta] of allMeta) {
  console.log(`${name}: ${meta?.description}`);
}

// Statistics
console.log(registry.getStats());
// { totalTools: 3, categories: ["external"], tags: ["weather", "api"] }