/** * L3 — the tool registry. * * One registry per agent. It is the ONLY place the kernel learns which tools * exist: nothing is assembled from a list maintained elsewhere, because a * second list is a second truth (the failure class behind the reference * implementation's hand-maintained agent-tool sets and its six copies of the * default tool list — see ADR-0001). * * `registerLive()` adds a LIVE tool source — a function returning an * extension's CURRENT tools array. Any extension whose tool table settles * after load is such a source (the runtime registers every extension's * table this way — agent.ts; a bridge that connects in the background was * the first to need it, 0.1.26); the registry consults the live sources * on every lookup. The registered map wins a name collision * (the agent's built-ins are authoritative); the collision check that * would otherwise fire at registration time cannot run against a live, * still-growing source. */ import type { ToolSpec } from "../protocol/messages.js"; import type { Tool } from "./tool.js"; /** CX-1 F7: a captured tool table — what ONE request advertises and * dispatches from. */ export interface ToolTable { readonly specs: readonly ToolSpec[]; get(name: string): Tool | undefined; } export declare class ToolRegistry { #private; register(tool: Tool): void; /** 0.1.26: a live tool source — consulted on every lookup, never * snapshotted. The source returns the CURRENT array (it may grow). */ registerLive(source: () => readonly Tool[], owner?: string): void; /** CX-1 F7 (audit F7) — ONE table per request. The loop takes a * snapshot at request assembly and dispatches from it: the definition * sent to the model, the schema validated against, the `execute` that * runs and the `effects` the scheduler reads are the SAME captured * values: the declaration data (schema, effects) is COPIED into the * table, the handler stays by reference — an in-place edit to the * source after the snapshot cannot reach a request already under way * (the 2026-09-07 review's P2: a shallow copy shared the nested * objects). Two sources publishing one name is an error the moment * it is observed, naming both owners — never a traversal-order pick; * the one exception is the SAME Tool object reached twice (the 0.1.27 * dedup), which is one tool. */ snapshot(): ToolTable; get(name: string): Tool | undefined; list(): readonly Tool[]; has(name: string): boolean; /** The minimal projection an adapter may see (never the handlers). */ toSpecs(): readonly ToolSpec[]; }