/** * Tool Registry and Tool Executor. * * The registry is the operation catalog: each {@link Tool} wraps one grid * operation with the metadata a planner (and, later, an LLM) needs (name, * description, an argument JSON Schema, a validator, and an executor that returns * its own inverse). The {@link ToolExecutor} runs a {@link Plan} step by step, * validating each step's arguments, aggregating the outcomes, and composing a * single LIFO undo. Both are grid-agnostic: they act only through {@link GridApi} * (carried on {@link ToolContext}), so they are unit-testable with a fake grid. * * @see plans/ai-reasoning-layer-spec.md (section 4.7) */ import type { JSONSchema } from '../../ai-schema.js'; import type { GridContext } from '../context.js'; import type { GridApi } from '../grid-api.js'; import type { Plan } from '../types.js'; /** What a {@link Tool.execute} receives: the grid boundary plus the reasoning context. */ export interface ToolContext { api: GridApi; ctx: GridContext; } /** The result of running one tool: what changed, any notes, an optional answer, and its inverse. */ export interface ToolOutcome { applied: string[]; skipped?: string[]; warnings?: string[]; /** Set by read-only tools (e.g. `answer`). */ answer?: string; /** Restores the state this tool changed. A no-op for read-only / side-effect tools. */ undo: () => void; } /** The outcome of validating a tool's raw arguments. */ export type ToolValidation = { ok: true; value: A; } | { ok: false; errors: string[]; }; /** * One registered operation. `A` is the validated argument shape; built-ins type it * precisely and the registry stores tools type-erased. */ export interface Tool> { name: string; description: string; /** JSON Schema for the arguments (metadata; drives LLM tool definitions later). */ parameters: JSONSchema; /** True if the tool never mutates the grid (answer / analyze). Ask mode runs only these. */ readOnly?: boolean; /** Capability gate: is this operation possible for the current grid? */ available(ctx: GridContext): boolean; /** Turn raw (untrusted) arguments into a typed value, or a list of errors. */ validate(args: unknown, ctx: GridContext): ToolValidation; /** Perform the operation through the grid boundary and return its inverse. */ execute(args: A, tc: ToolContext): ToolOutcome; } /** An LLM-facing tool definition (the generalization of `toJSONSchema`). */ export interface ToolDefinition { name: string; description: string; input_schema: JSONSchema; } /** The catalog: register operations, look them up, and enumerate the available ones. */ export interface ToolRegistry { register(tool: Tool): void; get(name: string): Tool | undefined; /** Only the tools currently available for the given context. */ list(ctx: GridContext): Tool[]; /** Tool definitions for the available tools (for an LLM reasoner). */ toToolDefinitions(ctx: GridContext): ToolDefinition[]; } /** The aggregated result of executing a whole plan. */ export interface ExecutionResult { outcomes: ToolOutcome[]; applied: string[]; skipped: string[]; warnings: string[]; answer?: string; /** Undo every step's change, most-recent-first. Idempotent. */ undo(): void; } /** Runs a {@link Plan} against a {@link ToolContext} using a {@link ToolRegistry}. */ export interface ToolExecutor { run(plan: Plan, tc: ToolContext): ExecutionResult; } /** Create an empty {@link ToolRegistry}. */ export declare function createToolRegistry(): ToolRegistry; /** Create a {@link ToolExecutor} bound to a registry. */ export declare function createToolExecutor(registry: ToolRegistry): ToolExecutor;