ToolRegistry reference
The tool registry holds every tool the agent can invoke, filters by personality toolset, and runs parallel execution with budget enforcement and output reduction.
Source
Interface in packages/types/src/tool.ts (ToolRegistry, ToolFilterOpts). Implementation in packages/core/src/tool-registry.ts (DefaultToolRegistry). Reducer registry in packages/core/src/tool-reducer-registry.ts (DefaultToolResultReducerRegistry).
ToolRegistry
Signature
import type {
Attachment,
Tool,
ToolContext,
ToolFilterOpts,
ToolRegistry,
ToolResult,
} from '@ethosagent/types';
import type { ToolDefinitionLite } from '@ethosagent/types';
export interface ToolRegistry {
register(tool: Tool, opts?: { pluginId?: string }): void;
registerAll(tools: Tool[]): void;
unregister(name: string): void;
get(name: string): Tool | undefined;
getAvailable(): Tool[];
getForToolset(toolset: string): Tool[];
executeParallel(
calls: Array<{ toolCallId: string; name: string; args: unknown }>,
ctx: ToolContext,
allowedTools?: string[],
filterOpts?: ToolFilterOpts,
turnAttachments?: Attachment[],
): Promise<Array<{ toolCallId: string; name: string; result: ToolResult }>>;
toDefinitions(
allowedTools?: string[],
filterOpts?: ToolFilterOpts,
): ToolDefinitionLite[];
}
Methods
| Method | Signature | Description |
|---|---|---|
register | (tool: Tool, opts?: { pluginId?: string }): void | Register a tool. Optional pluginId tags it for per-personality plugin gating. |
registerAll | (tools: Tool[]): void | Register multiple tools. |
unregister | (name: string): void | Remove a tool by name. |
get | (name: string): Tool | undefined | Lookup by name. |
getAvailable | (): Tool[] | All tools where isAvailable() returns true (or is absent). |
getForToolset | (toolset: string): Tool[] | All tools in a given toolset group. |
executeParallel | (calls, ctx, allowedTools?, filterOpts?, turnAttachments?): Promise<...> | Run tool calls concurrently with budget split and reduction. See executeParallel. |
toDefinitions | (allowedTools?, filterOpts?): ToolDefinitionLite[] | Build LLM tool definitions, filtered by personality toolset. See toDefinitions. |
DefaultToolRegistry
The concrete implementation in packages/core/src/tool-registry.ts.
Constructor
import type { CapabilityBackends } from '@ethosagent/core';
import type { ToolResultReducerRegistry } from '@ethosagent/types';
const tools = new DefaultToolRegistry(capabilityBackends?, reducerRegistry?);
| Parameter | Type | Description |
|---|---|---|
capabilityBackends | CapabilityBackends | undefined | Optional backends for tools that declare capabilities (network, secrets, storage, fs_reach, process, attachments). |
reducerRegistry | ToolResultReducerRegistry | undefined | Optional registry of result reducers. When present, executeParallel applies reducers after execution and before budget trim. |
executeParallel
The core method. Runs every requested tool call concurrently via Promise.allSettled. Returns results in input order. Never throws -- failures become { ok: false } results.
Pipeline
- Budget split --
perCallBudget = Math.floor(ctx.resultBudgetChars / Math.max(calls.length, 1)). Default total budget: 80,000 chars. - Unknown tool check -- If the tool name is not in the registry:
{ ok: false, error: 'Unknown tool: ...', code: 'not_available' }. - Allowlist check -- Each call is checked against
allowedTools+filterOpts. Built-in tools (notmcp__*, nopluginId) must appear inallowedToolswhen that list is non-empty. MCP and plugin tools are gated byfilterOptsviapassesFilter(). Rejected calls get{ ok: false, error: '...not permitted...', code: 'not_available' }. - Availability check -- If the tool declares
isAvailable()and it returnsfalse:{ ok: false, error: '...not currently available', code: 'not_available' }. - Capability backend check -- If the tool declares capabilities that need backends (
network,secrets,storage,fs_reach,process,attachments) and no backends are configured:{ ok: false, code: 'not_available' }. - Dry-run mode -- If
ctx.dryRun, returns a synthetic result without execution. - Per-call budget --
Math.min(perCallBudget, tool.maxResultChars ?? perCallBudget). - Capability resolution -- If the tool declares capabilities and backends are configured, backends are resolved and injected into the tool context.
- Execution --
tool.execute(args, ctx). - Reducer pipeline -- After execution, before budget trim. Looks up
ToolResultReducerby tool name in the reducer registry. If found, callssafeReduce(reducer, result, { args, turnCount }). Safe: catches reducer errors and returns the original result. - Post-trim -- If the result value exceeds the per-call budget, truncates and appends
\n[truncated — N chars total].
toDefinitions
Filters the registry by personality toolset (allowedTools) + MCP/plugin filters (filterOpts). Returns ToolDefinitionLite[] for the LLM request.
Filtering gates (applied in order)
isAvailable()gate -- Tools that declareisAvailableand returnfalseare dropped.- Toolset gate (built-in tools only) -- Built-in tools (name does not start with
mcp__, nopluginId) must appear inallowedToolswhen that list is non-empty.alwaysInclude: truebypasses this gate. filterOptsgate --allowedMcpServersfiltersmcp__<server>__*tools by server name.allowedPluginsfilters plugin-tagged tools bypluginId.
Surviving entries are mapped to { name, description, parameters: tool.schema }.
DefaultToolResultReducerRegistry
The reducer registry implementation in packages/core/src/tool-reducer-registry.ts. Provides exact-match lookup of ToolResultReducer by tool name.
Signature
import type { ToolResultReducer, ToolResultReducerRegistry } from '@ethosagent/types';
export class DefaultToolResultReducerRegistry implements ToolResultReducerRegistry {
register(reducer: ToolResultReducer): () => void;
get(toolName: string): ToolResultReducer | undefined;
}
Methods
| Method | Signature | Description |
|---|---|---|
register | (reducer: ToolResultReducer): () => void | Register a reducer. Throws if one is already registered for the same tool name. Returns a cleanup function that unregisters the reducer. |
get | (toolName: string): ToolResultReducer | undefined | Lookup reducer by tool name. Exact match. |
Built-in reducers
| Reducer | Tool name | Source | Strategy |
|---|---|---|---|
| Bash reducer | terminal | extensions/tools-terminal/src/reducers/bash.ts | Recognizes git status, test runs, package installs; head+tail fallback for output exceeding 8 KB. |
| Read-file reducer | read_file | extensions/tools-code/src/reducers/read-file.ts | Prepends file-size hint, truncates to 200 lines on unconstrained reads (no lineStart/lineEnd). |
| Kanban-list reducer | kanban_list | extensions/tools-kanban/src/reducers/kanban-list.ts | Status counts + top 5 open tickets when list exceeds 10 items. |
Wiring
How it is assembled at startup in packages/wiring/src/index.ts:
import { DefaultToolRegistry, DefaultToolResultReducerRegistry } from '@ethosagent/core';
import { bashReducer } from '@ethosagent/tools-terminal/reducers/bash';
import { readFileReducer } from '@ethosagent/tools-code/reducers/read-file';
import { kanbanListReducer } from '@ethosagent/tools-kanban/reducers/kanban-list';
const reducerRegistry = new DefaultToolResultReducerRegistry();
reducerRegistry.register(bashReducer);
reducerRegistry.register(readFileReducer);
reducerRegistry.register(kanbanListReducer);
const tools = new DefaultToolRegistry(capabilityBackends, reducerRegistry);
See also
- Tool interface reference --
Tool,ToolResult,ToolResultReducercontracts. - Why is there an 80k tool result budget?
- Context cost optimization -- the seven-layer defense.
- HookRegistry reference -- the parallel registry for hooks.
- Architecture in 90 seconds