Documentation/Tool Catalog: Dynamic Tool Loading/Unloading
v2.0.0-beta.1Snapshot bebdcd1Markdown ↗

Tool Catalog: Dynamic Tool Loading/Unloading

Tool Catalog: Dynamic Tool Loading/Unloading

When agents need 100+ tools, sending all tool definitions to the LLM wastes tokens and degrades performance. The Tool Catalog lets agents dynamically discover and load only the tool categories they need.

Quick Start

typescript
const agent = Agent.create({
  connector: 'openai',
  model: 'gpt-4.1',
  tools: [readFile, writeFile],  // always-on tools (outside catalog)
  identities: [{ connector: 'github' }],  // connector scope
  context: {
    model: 'gpt-4.1',
    features: { toolCatalog: true },
    toolCategories: ['web', 'code'],  // built-in category scope
    plugins: {
      toolCatalog: {
        pinned: ['web'],  // always loaded, LLM can't unload
      },
    },
  },
});

The agent gets 3 metatools: tool_catalog_search, tool_catalog_load, tool_catalog_unload. It can browse available categories, load what it needs, and unload when done.

Important: Plugin tools (memory, context, instructions, etc.) are always available and completely separate from the catalog. They cannot be unloaded.

How Scoping Works

The Tool Catalog has two independent scoping mechanisms:

Scope Controls Config
toolCategories Built-in categories (filesystem, web, code, shell, etc.) context.toolCategories
identities Connector categories (connector:github, connector:slack, etc.) Agent.create({ identities })
typescript
const agent = Agent.create({
  connector: 'openai',
  model: 'gpt-4.1',

  // Controls which connector categories appear in catalog
  identities: [
    { connector: 'github' },
    { connector: 'slack' },
    { connector: 'microsoft', accountId: 'work' },
  ],

  context: {
    model: 'gpt-4.1',
    features: { toolCatalog: true },
    // Controls which built-in categories appear in catalog
    toolCategories: ['filesystem', 'web', 'code'],
  },
});

// LLM sees: filesystem, web, code, connector:github, connector:slack, connector:microsoft:work

Scoping syntax for toolCategories:

text
// Allowlist (string[] shorthand)
toolCategories: ['web', 'knowledge']

// Explicit allowlist
toolCategories: { include: ['web', 'knowledge'] }

// Blocklist (all except these)
toolCategories: { exclude: ['desktop', 'shell'] }

// No scope = all built-in categories visible

Pinned Categories

Pinned categories are always loaded and the LLM cannot unload them. Use this for tools the agent must always have access to:

typescript
const contextConfig = {
  features: { toolCatalog: true },
  toolCategories: ['filesystem', 'web', 'code'],
  plugins: {
    toolCatalog: {
      pinned: ['filesystem'],  // always loaded, can't unload
    },
  },
};

Pinned vs always-on tools (tools array):

  • tools: [myTool] on Agent.create() — individual tools always available, outside the catalog entirely
  • pinned: ['filesystem'] — entire category loaded via catalog, visible in catalog listings as [PINNED], but cannot be unloaded

Behavior:

  • Pinned categories are loaded automatically when the plugin initializes
  • tool_catalog_unload returns an error for pinned categories
  • Pinned categories don't count toward maxLoadedCategories limit
  • During compaction, pinned categories are never evicted

Auto-Loading Categories

Pre-load categories so the agent doesn't need an extra turn. Unlike pinned, auto-loaded categories can be unloaded by the LLM:

typescript
const pluginConfigs = {
  plugins: {
  toolCatalog: {
    pinned: ['filesystem'],                     // always loaded
    autoLoadCategories: ['web', 'knowledge'],   // pre-loaded, can be unloaded
    maxLoadedCategories: 10,                    // limit (excludes pinned)
  },
  },
};

Dynamic Instructions

The LLM receives dynamic instructions that list exactly which categories are available, with markers:

text
## Tool Catalog

Your core tools (memory, context, instructions, etc.) are always available.
Additional tool categories can be loaded on demand from the catalog below.

**Available categories:**
- filesystem (6 tools) [PINNED]: Read, write, edit, search, and list files
- web (1 tool): Fetch and process web content
- code (1 tool): Execute JavaScript code in sandboxed VM
- connector:github (9 tools): Authenticated API + 8 GitHub tools
- connector:slack (11 tools): Authenticated API + 10 Slack tools

**Best practices:**
- Search first to find the right category before loading.
- Unload categories you no longer need to keep context lean.
- Categories marked [PINNED] are always available and cannot be unloaded.

ToolCatalogRegistry

Static global registry for tool categories (like Connector and StorageRegistry). Register your custom categories at app startup:

typescript
import { ToolCatalogRegistry } from 'oneringai';

ToolCatalogRegistry.registerCategory({
  name: 'knowledge',
  displayName: 'Knowledge Graph',
  description: 'Search entities, get facts, manage references',
});

ToolCatalogRegistry.registerTools('knowledge', [
  { name: 'entity_search', displayName: 'Entity Search', description: 'Search people/orgs', tool: entitySearch, safeByDefault: true },
]);

Built-in tools from registry.generated.ts are auto-registered on first access.

Resolving Tool Names

For executors that resolve string[] tool names to ToolFunction[]:

typescript
const tools = ToolCatalogRegistry.resolveTools(
  ['entity_search', 'github_api'],
  { includeConnectors: true }
);

Tools

Tool Description Permission
tool_catalog_search Browse categories, list tools, keyword search Always allowed
tool_catalog_load Load a category's tools into the agent Always allowed
tool_catalog_unload Unload a category to free token budget Always allowed

Full Configuration Reference

typescript
interface ToolCatalogPluginConfig {
  /** Scope for built-in categories (does NOT affect connector categories) */
  categoryScope?: string[] | { include: string[] } | { exclude: string[] };
  /** Categories pre-loaded on init (can be unloaded by LLM) */
  autoLoadCategories?: string[];
  /** Categories always loaded (cannot be unloaded by LLM) */
  pinned?: string[];
  /** Max loaded categories at once, excluding pinned (default: 10) */
  maxLoadedCategories?: number;
  /** Auth identities for connector filtering (usually set via Agent.create) */
  identities?: AuthIdentity[];
}

Documentation snapshot · 2026-11-02Suggest a correction ↗

Search documentation

Type to search the v2 documentation.