import type { LLMToolSchema, PreparedToolExecution, ToolAvailability, ToolContext, ToolDefinition, ToolExecutionResult, ToolPreparationResult, ToolRegistryConfig } from '../../types/tool/index.js'; import { ManagedRegistry } from '../ManagedRegistry.js'; export type { ToolExecutionResult }; /** Options for an independent registry membership and availability snapshot. */ export interface ToolRegistryForkOptions { /** * Defer currently active tools outside this exact list. Omission preserves * every availability; an empty list defers every active tool. Listed tools * that are already deferred or suspended keep that state. Names must be * unique, valid registered names; a misspelling is refused. */ readonly deferExcept?: readonly string[]; } /** * What a tool name may be, everywhere it comes from. * * A tool name reaches the provider verbatim, and the major message APIs * accept `[a-zA-Z0-9_-]` up to 64 characters. Nothing checked it: names * were derived by concatenation at three separate construction sites — * the remote-tool bridge, the plugin bridge, the CLI bridge — and any of * them could produce something the wire rejects. * * The rejection is a 400 on the WHOLE request rather than on that tool, * and the tools most likely to carry a bad name are registered deferred, * so it fired the moment one was activated with nothing naming the * culprit. Failing at registration instead names the tool, at the moment * something can still be done about it, and costs the turn nothing. * * One driver already ratified passing names through untouched, on the * grounds that a confusing name is "a naming problem to fix in the * registry, not something to paper over" — which is precisely why the * registry has to be the one that checks. */ export declare const TOOL_NAME_PATTERN: RegExp; export declare function assertToolName(name: string): void; /** * Two sources contributed the same tool name and neither may take it. * * Named, and carrying the name, for the reason `DuplicateProviderError` is: * a host that wants to handle this — fall back to its own tool, log and * continue, surface it in a config error — has to be able to catch it * narrowly rather than match on message text. It also names both remedies, * because a hard collision policy without a way to decline would make * shadowing-by-name the only way to say "I do not want this tool", which is * precisely what now throws. */ export declare class ToolNameCollisionError extends Error { readonly toolName: string; constructor(toolName: string, context: string); } /** * Append a tool's declared return shape to its description. * * No provider's tool wire format has a slot for an output schema, so the * description is the only channel that reaches the model. A remote server * that publishes one had it dropped at the type boundary and the model was * left inferring the return shape from prose — or from the first result it * happened to see, which is worse, because a tool that returns an empty * list once teaches the wrong lesson permanently. * * Rendered from JSON Schema verbatim rather than round-tripped through * anything: this is shown, never validated, so there is nothing to gain by * rebuilding it and fidelity to lose. */ export declare function describeWithOutput(description: string, outputSchema: Record | undefined): string; export declare class ToolRegistry extends ManagedRegistry { private availability; private tierConfig?; private resultGuardrails?; private readonly preparations; constructor(config?: ToolRegistryConfig); /** * Snapshot membership and availability for another turn without changing this * registry. Discovery, registration and suspension then affect only the fork. * Definitions, handlers and configuration remain shared; this is not a deep * clone or an authorization boundary. Prepared executions belong only to the * registry that prepared them and do not transfer to the fork. */ fork(options?: ToolRegistryForkOptions): ToolRegistry; register(id: string, tool: ToolDefinition): void; register(tool: ToolDefinition, initialState?: ToolAvailability): void; register(tools: ToolDefinition[], initialState?: ToolAvailability): void; private registerOne; unregister(id: string): boolean; clear(): void; activate(names: string[]): void; defer(names: string[]): void; suspendAll(): void; hasSuspended(): boolean; getAvailability(name: string): ToolAvailability; /** * Ranked lexical search over DEFERRED tools, score-descending (ties broken * by name) so callers can cap activation at a top-k. Each meaningful query * term (≥3 chars, not a stop token) is scored against the tool name * (exact/substring), description, and argument names; only tools with a * positive score are returned. Description matching is safe here precisely * because the result is RANKED — the `search_tools` builtin activates only * the top slice, so a shared word can no longer drag in the whole catalog. * * PARKED (phase 5 of the tool-loading plan): an embedding-backed semantic * upgrade was evaluated and deliberately NOT built — at ≤~35 deferred * in-house tools with distinct names, weighted lexical scoring sits inside * the literature's safe zone, and a weak retriever underperforms no * retriever at all. Revisit only when (a) the deferred catalog grows past * ~75-100 tools (realistic driver: connector-MCP growth), or (b) telemetry * shows a search_tools miss-rate above ~10%. Sticky activation is also * deliberate: activating inserts the schema into the tools array at its * registry position (a one-time prompt-cache prefix bust); re-defer/TTL * would churn that prefix repeatedly and is rejected. */ searchDeferred(query: string): ToolDefinition[]; /** Active matches use the same ranking, also recognizing exact short or generic names. */ searchActive(query: string): ToolDefinition[]; private searchByAvailability; assignTiers(mapping: Record): void; toTierGuidance(): string | null; listNames(): string[]; toPromptSection(toolNames?: string[]): string; toLLMTools(toolNames?: string[]): LLMToolSchema[]; getCallableTools(toolNames?: string[]): ToolDefinition[]; prepareExecution(toolName: string, rawInput: unknown): ToolPreparationResult; executePrepared(prepared: PreparedToolExecution, context: ToolContext): Promise; execute(toolName: string, rawInput: unknown, context: ToolContext): Promise; private rejectPreparationWithClosedSpan; private executeRetained; private validationFailure; private getByAvailability; } /** * One-line discoverability hint for a deferred tool: the first sentence of * its description, capped at ~100 chars. Used for the `` * prompt listing and for `search_tools` near-miss suggestions, where the * full description would re-import the token weight deferral avoids. */ export declare function toolDiscoveryHint(description: string, maxLength?: number): string; //# sourceMappingURL=execute.d.ts.map