/** * The AI engine: the wired pipeline and the orchestrator behind `grid.runPrompt`. * * `createAIEngine(api)` bundles the default rule reasoner, the tool registry + * executor, an in-memory {@link Memory}, a {@link ContextBuilder}, and a rule-first * {@link Router}. `runPrompt` builds the context, routes to a reasoner, executes the * resulting {@link Plan} through the tools, records the turn to memory (so the next * turn can resolve "it"/"the other way"/"undo"), and returns a clean {@link AIResult} * (control: applied + warnings + undo; ask: answer). `previewPrompt` is a dry-run: * it builds the plan without executing it. Push an LLM reasoner (P4) to go hybrid. * * @see plans/ai-reasoning-layer-spec.md (section 4.9) */ import type { ContextBuilder } from './context.js'; import type { GridApi } from './grid-api.js'; import type { Memory } from './memory.js'; import type { Reasoner } from './reasoner.js'; import type { Router, RoutingPolicy } from './router.js'; import type { ToolExecutor, ToolRegistry } from './tools/registry.js'; import type { AIMode, Plan } from './types.js'; /** Options for {@link AIEngine.runPrompt} / {@link AIEngine.previewPrompt}. */ export interface RunPromptOptions { /** Force ask (read-only) mode even if the reasoner planned a control action. */ mode?: AIMode; /** Cooperative cancellation (forwarded to any LLM reasoner). */ signal?: AbortSignal; /** Override the rows sampled into context for this call. */ maxDataRows?: number; } /** The outcome of a {@link AIEngine.runPrompt} call: a discriminated union by `mode`. */ export type AIResult = { mode: 'control'; /** The plan that was executed (inspectable). */ plan: Plan; /** Human-readable descriptions of what was applied. */ applied: string[]; /** Slices present but not applied. */ skipped: string[]; /** Reasoner notes plus per-tool warnings, merged. */ warnings: string[]; /** Restore the pre-prompt snapshot. Idempotent. */ undo: () => void; } | { mode: 'ask'; plan: Plan; answer: string; /** * True when the pipeline could neither map an action nor ground a real answer: * an honest "I could not do that" rather than a silent no-op. The `answer` holds * a plain-text note; the host UI should show a localized abstention message. */ abstained?: boolean; }; /** The wired pipeline. Fields are exposed so a host can inspect or swap parts. */ export interface AIEngine { api: GridApi; contextBuilder: ContextBuilder; memory: Memory; registry: ToolRegistry; executor: ToolExecutor; reasoners: Reasoner[]; router: Router; runPrompt(prompt: string, options?: RunPromptOptions): Promise; previewPrompt(prompt: string, options?: RunPromptOptions): Promise; } /** Options for {@link createAIEngine}. */ export interface CreateAIEngineOptions { /** Reasoners in priority order. Defaults to `[rule]`; push an LLM reasoner to go hybrid. */ reasoners?: Reasoner[]; /** Routing policy. Default `'rule-first'`. */ policy?: RoutingPolicy; /** Escalation threshold for `rule-first` / `llm-first`. Default `0.5`. */ threshold?: number; /** Conversation + grid-state memory. Defaults to a bounded in-memory store. */ memory?: Memory; /** Tool registry. Defaults to the built-in catalog. */ registry?: ToolRegistry; /** Rows sampled into context by default. */ maxDataRows?: number; /** Injected clock; defaults to `Date.now`. The pure components never read time themselves. */ now?: () => number; } /** Build a fully wired {@link AIEngine} over a {@link GridApi}. */ export declare function createAIEngine(api: GridApi, options?: CreateAIEngineOptions): AIEngine;