Skip to content
8 min read · 1,583 words

Class: ToolRegistry

Defined in: src/lib/classes/tool_registry.ts:51

A mutable, turn-scoped collection of @nhtio/adk!Tool instances.

Remarks

Each TurnRunner.run() call constructs a fresh ToolRegistry from the runner's configured baseline tools, so middleware edits are isolated to the current turn and cannot bleed across concurrent or subsequent turns.

Tool instances are immutable, so all() returns a fresh array without deep-cloning.

register() throws @nhtio/adk!E_TOOL_ALREADY_REGISTERED if a tool with the same name is already present — pass overwrite: true to replace it explicitly.

Tools can be hidden — registered and callable, but excluded from the default tool list rendered to the model. This is useful for discovery patterns where an agent has a tool that enumerates available tools, and the model picks one to call by name in a subsequent iteration. Hidden state is a property of the registry, not the tool: the same tool can be visible in one registry and hidden in another. See hide, visible, hidden.

Constructors

Constructor

ts
new ToolRegistry(tools?: Tool<SpooledArtifact>[]): ToolRegistry;

Defined in: src/lib/classes/tool_registry.ts:70

Parameters

ParameterTypeDescription
tools?Tool<SpooledArtifact>[]Optional initial tools. Insertion order is preserved. Duplicate names throw @nhtio/adk!E_TOOL_ALREADY_REGISTERED — ensure each tool has a unique name.

Returns

ToolRegistry

Throws

@nhtio/adk!E_TOOL_ALREADY_REGISTERED when two tools in tools share a name.

Methods

[ENCODE_METHOD]()

ts
ENCODE_METHOD: unknown;

Defined in: src/lib/classes/tool_registry.ts:349

Serialise this ToolRegistry into an @nhtio/encoder snapshot.

Returns

unknown

A { tools, hidden } snapshot.

Remarks

Emits the live @nhtio/adk!Tool instances (the encoder recurses into each — so every tool's handler-closure caveat from Tool.[ENCODE_METHOD] applies) plus the hidden-set names. Both @nhtio/adk!Tool and @nhtio/adk!ArtifactTool entries round-trip to their correct subtype. Round-trips via ToolRegistry.[DECODE_METHOD].


all()

ts
all(): Tool<SpooledArtifact>[];

Defined in: src/lib/classes/tool_registry.ts:135

Returns a fresh array of all registered tools in insertion order.

Returns

Tool<SpooledArtifact>[]

Remarks

Includes both visible and hidden tools. Use visible to get only non-hidden tools, or hidden to get only hidden tools.

Since @nhtio/adk!Tool instances are immutable, no deep-cloning is needed.


bindContext()

ts
bindContext(ctx: DispatchContext): () => void;

Defined in: src/lib/classes/tool_registry.ts:267

Binds this registry to a @nhtio/adk!DispatchContext so that pruneEphemeral runs automatically when the context is acked.

Parameters

ParameterTypeDescription
ctxDispatchContextThe execution context whose ack event should trigger pruning.

Returns

An unsubscribe function — calling it before ctx.ack() prevents pruning. Rarely useful outside of tests.

() => void

Remarks

The handler does NOT fire on @nhtio/adk!DispatchContext.nack — failed executor runs leave any forged tools in place so the consumer can inspect what was registered when debugging the failure. Subscriptions are short-lived and die with the context regardless.

ARTIFACT READERS ARE FORGED BY THE CORE. As of the core-forge change, the DispatchRunner forges artifact-reader tools from prior-turn SpooledArtifact results into ctx.tools (and calls ctx.tools.bindContext(ctx)) once per iteration, BEFORE the input pipeline — so a battery executor no longer forges or binds; it reads the already-forged ctx.tools for both representation (rendering the tool declarations) and resolution (looking up an incoming call by name). The lifecycle is unchanged: ephemeral readers are still pruned on ack, and the core re-forges each iteration (prune-then-forge) so the callId enum never goes stale.

bindContext remains the public seam for a CUSTOM consumer that forges its own ephemeral tools outside the core path. If you forge into a long-lived registry yourself, bind it (or prune manually) or the ephemeral tools accumulate and later forgeTools(ctx) calls see a stale callId enum. The pattern for a hand-rolled forge is:

ts
// Custom forge (the core already does this for artifact readers on ctx.tools):
const forged = SpooledArtifact.forgeTools(ctx);
for (const tool of forged.all()) ctx.tools.register(tool, true);
ctx.tools.bindContext(ctx); // prune the ephemeral readers when the dispatch acks

See


clearHidden()

ts
clearHidden(): void;

Defined in: src/lib/classes/tool_registry.ts:209

Unhides every tool in the registry.

Returns

void


get()

ts
get(name: string):
  | Tool<SpooledArtifact>
  | undefined;

Defined in: src/lib/classes/tool_registry.ts:113

Returns the tool registered under name, or undefined if not present.

Parameters

ParameterTypeDescription
namestringThe tool name to look up.

Returns

| Tool<SpooledArtifact> | undefined


has()

ts
has(name: string): boolean;

Defined in: src/lib/classes/tool_registry.ts:122

Returns true if a tool with the given name is registered.

Parameters

ParameterTypeDescription
namestringThe tool name to test.

Returns

boolean


hidden()

ts
hidden(): Tool<SpooledArtifact>[];

Defined in: src/lib/classes/tool_registry.ts:158

Returns a fresh array of registered tools that are hidden, in insertion order.

Returns

Tool<SpooledArtifact>[]

Remarks

The converse of visible. Useful for discovery tools that enumerate all available tools, and for propagating hidden state across merge.


hide()

ts
hide(...names: string[]): void;

Defined in: src/lib/classes/tool_registry.ts:172

Marks one or more registered tools as hidden.

Parameters

ParameterTypeDescription
...namesstring[]One or more tool names to hide.

Returns

void

Remarks

Hidden tools remain registered and callable via get, but are excluded from visible (and therefore from the LLM tool list). No-ops for any name that is not currently registered — the end result (the tool is not visible) matches the intent.


pruneEphemeral()

ts
pruneEphemeral(): void;

Defined in: src/lib/classes/tool_registry.ts:222

Removes every tool whose @nhtio/adk!Tool.ephemeral flag is true.

Returns

void

Remarks

Also removes pruned tool names from the hidden set. Synchronous and idempotent — calling it twice in a row is a no-op the second time. The canonical caller is ToolRegistry.bindContext, which schedules this method to run at @nhtio/adk!DispatchContext.ack. Non-ephemeral tools are left untouched.


register()

ts
register(tool: Tool, overwrite?: boolean): void;

Defined in: src/lib/classes/tool_registry.ts:87

Adds a tool to the registry.

Parameters

ParameterTypeDescription
toolToolThe tool to register.
overwrite?booleanWhen true, silently replaces an existing tool with the same name. Defaults to false.

Returns

void

Throws

@nhtio/adk!E_TOOL_ALREADY_REGISTERED when a tool with the same name is already registered and overwrite is not true.


setHidden()

ts
setHidden(...names: string[]): void;

Defined in: src/lib/classes/tool_registry.ts:202

Replaces the entire hidden set with the given tool names.

Parameters

ParameterTypeDescription
...namesstring[]The complete set of tool names to hide.

Returns

void

Remarks

Any previously hidden tool not in names becomes visible. Names that are not registered are silently ignored — they are added to the set but have no effect until a tool with that name is registered.


unhide()

ts
unhide(...names: string[]): void;

Defined in: src/lib/classes/tool_registry.ts:186

Unmarks one or more tools as hidden, making them visible again.

Parameters

ParameterTypeDescription
...namesstring[]One or more tool names to unhide.

Returns

void

Remarks

No-ops for any name that is not currently hidden.


unregister()

ts
unregister(name: string): void;

Defined in: src/lib/classes/tool_registry.ts:103

Removes the tool with the given name from the registry.

Parameters

ParameterTypeDescription
namestringThe name of the tool to remove.

Returns

void

Remarks

Also removes the name from the hidden set if present. No-ops if no tool with that name is registered.


visible()

ts
visible(): Tool<SpooledArtifact>[];

Defined in: src/lib/classes/tool_registry.ts:147

Returns a fresh array of registered tools that are not hidden, in insertion order.

Returns

Tool<SpooledArtifact>[]

Remarks

This is the accessor LLM batteries should use when building the tool list for the model. Hidden tools are still callable (they resolve via get) but are excluded from the rendered tool definitions.


[DECODE_METHOD]()

ts
static DECODE_METHOD: ToolRegistry;

Defined in: src/lib/classes/tool_registry.ts:362

Reconstruct a ToolRegistry from a ToolRegistry.[ENCODE_METHOD] snapshot.

Parameters

ParameterTypeDescription
dataunknownThe snapshot produced by ToolRegistry.[ENCODE_METHOD].

Returns

ToolRegistry

A fresh ToolRegistry with the same tools and hidden set.


isToolRegistry()

ts
static isToolRegistry(value: unknown): value is ToolRegistry;

Defined in: src/lib/classes/tool_registry.ts:61

Returns true if value is a ToolRegistry instance.

Parameters

ParameterTypeDescription
valueunknownThe value to test.

Returns

value is ToolRegistry

true when value is a ToolRegistry instance.


merge()

ts
static merge(registries: ToolRegistry[], options?: MergeOptions): ToolRegistry;

Defined in: src/lib/classes/tool_registry.ts:299

Combines multiple ToolRegistry instances into a fresh registry without mutating any input.

Parameters

ParameterTypeDescription
registriesToolRegistry[]Registries to merge, in priority order (left-to-right insertion).
options?MergeOptionsMerge-level collision policy. Defaults to { onCollision: 'throw' }.

Returns

ToolRegistry

A fresh ToolRegistry containing the resolved union of all inputs.

Remarks

Iteration is left-to-right across registries and then in each registry's insertion order. Collisions are resolved by consulting the incoming tool's @nhtio/adk!Tool.onCollision first:

  • 'replace' (per-tool): the incoming tool wins, replacing the existing entry.
  • 'keep' (per-tool): the existing entry wins; the incoming tool is dropped.
  • 'throw' (per-tool, the default): fall back to the merge-level options.onCollision.

The merge-level options.onCollision defaults to 'throw', which mirrors register.

The result is a brand-new registry; no input is mutated and no event subscription is propagated. Each Tool's ephemeral flag carries through unchanged — the flag lives on the tool, not the registry, so bindContext(ctx) on the merged registry will prune the forged tools as expected.

Hidden state is also propagated: a tool that is hidden in any source registry remains hidden in the merged result, provided it survives collision resolution.

Throws

@nhtio/adk!E_TOOL_ALREADY_REGISTERED when the resolved collision policy is 'throw' and a collision occurs.