/** * buildToolRegistry — pure function that composes the agent's * augmented tool registry from three sources: * * 1. **Static registry** — tools registered via `.tool()`. Always * visible to the LLM; always executable. * 2. **`read_skill`** — auto-attached when ≥1 Skill is registered. * Activation tool for LLM-guided Skills. * 3. **Skill-supplied tools** (`Skill.inject.tools[]`) — visible * only when the Skill is active (filtered by tools-slot subflow); * MUST always be in the executor registry so when the LLM calls * one, the tool-calls handler can dispatch. * * Tool-name uniqueness is enforced across all three sources at build * time. The LLM only sees `tool.schema.name` (no ids), so names ARE * the runtime dispatch key — collisions break the LLM's ability to * call the right tool. Throw early instead of subtly shadowing. * * **Block C runtime — `autoActivate: 'currentSkill'` semantics:** * When a skill's `defineSkill({ autoActivate: 'currentSkill' })` is * set, its tools are EXCLUDED from the static registry. They flow * into the LLM's tool list ONLY through `dynamicSchemas` (the * buildToolsSlot path that reads activeInjections), which means * they're visible ONLY on iterations after the skill is activated by * `read_skill('id')`. Without this, the LLM sees every skill's tools * on every iteration and the per-skill-narrowing autoActivate * promised in `defineSkill` doesn't actually narrow anything. Skills * WITHOUT autoActivate keep the v2.4 behavior (tools always visible) * for back-compat. * * **autoActivate dispatch invariant:** autoActivate skill tools live * OUTSIDE the LLM-visible registry (so they don't pollute the * per-iteration tool list before the skill activates), but they MUST * still be findable by the dispatch handler — the LLM calls them by * name once the skill is active, and dispatch looks up by name. We * add them to the dispatch map (`registryByName`) so `lookupTool` * resolves correctly. */ import type { Injection } from '../../lib/injection-engine/types.js'; import type { LLMToolSchema } from '../../adapters/types.js'; import { type Tool, type ToolRegistryEntry } from '../tools.js'; export interface ToolRegistryArtifacts { /** All tools the LLM sees in the static portion of its tool list * (registry + read_skill + non-autoActivate skill tools). */ readonly augmentedRegistry: readonly ToolRegistryEntry[]; /** Dispatch map by name — used by the tool-calls handler at run * time to resolve a tool the LLM called. INCLUDES autoActivate * skill tools (which aren't in `augmentedRegistry`) so dispatch * works once the skill is active. */ readonly registryByName: ReadonlyMap; /** Static tool schemas for the LLM call. Mirrors `augmentedRegistry` * shape; passed to `buildToolsSlot` + the seed stage as the * per-iteration default before the dynamic tools slot has run. */ readonly toolSchemas: readonly LLMToolSchema[]; } /** * Compose the augmented tool registry from the static `.tool()` * registry + the agent's injections (skills only). Throws on tool- * name collisions across sources. */ export declare function buildToolRegistry(registry: readonly ToolRegistryEntry[], injections: readonly Injection[]): ToolRegistryArtifacts;