/**
 * The frozen tool kernel.
 *
 * Every built-in capability is authored as a declarative {@link ToolSpec}: a
 * name, a model-facing description, a JSON-Schema parameter shape, and a single
 * async `run`. The bespoke per-tool plumbing — advertising a descriptor to the
 * model, coercing the model's raw arguments, running under cancellation, and
 * shaping the result back into the runtime's tool boundary — is concentrated in
 * one adapter, {@link defineTool}. A tool author writes only `run`; the kernel
 * supplies the rest uniformly.
 *
 * The two outward contracts are imported, never redefined here: the runtime's
 * {@link ToolCall} / {@link ToolOutcome} boundary and the gateway's
 * {@link ToolDescriptor} / {@link JsonSchema} model-facing shape.
 */
import type { ToolCall, ToolOutcome } from "../../runtime/contract";
import type { ToolDescriptor, JsonSchema } from "../../llmgateway/contract";
import type { Fs, Shell } from "./backends";
import type { OutputBudget } from "./output";
/** A plain-text fragment a tool returns to the model. */
export interface TextContentBlock {
    readonly kind: "text";
    readonly text: string;
}
/** A structured fragment a tool returns; serialized when handed to the model. */
export interface JsonContentBlock {
    readonly kind: "json";
    readonly value: unknown;
}
/** One unit of a {@link ToolResult}: either prose or structured data. */
export type ToolContentBlock = TextContentBlock | JsonContentBlock;
/**
 * The value a tool's `run` resolves to.
 *
 * `content` is the ordered set of fragments shown to the model. `isError`, when
 * true, marks the whole result as a failure the model should be told about; the
 * kernel propagates it onto the {@link ToolOutcome}.
 */
export interface ToolResult {
    readonly content: ToolContentBlock[];
    readonly isError?: boolean;
}
/**
 * The per-session record a {@link ReadStateHandle} keeps for one file.
 *
 * It captures just enough to detect that a file has drifted on disk since it was
 * last read: the floored modification time and byte size at read time, an
 * optional content hash for a future exact-match fallback, and the wall-clock
 * moment the read happened. The handle keys these by absolute path.
 */
export interface ReadStateRecord {
    /** Last-modified time at read, epoch milliseconds (floored). */
    readonly mtimeMs: number;
    /** Byte size at read time. */
    readonly size: number;
    /** Optional content hash for an exact-equality fallback; absent today. */
    readonly contentHash?: string;
    /** Wall-clock moment the read was recorded, epoch milliseconds. */
    readonly readAt: number;
}
/**
 * The minimal, duck-typed handle a host may stash on {@link ToolContext.framework}
 * under {@link READ_STATE_HANDLE_KEY} to enable the read-before-edit gate.
 *
 * Deliberately tiny — `get` / `set` / `has` keyed by absolute path — so the
 * framework consumer and the product injector can agree on the *shape* without a
 * cross-package type import. The product supplies a concrete store; the framework
 * only ever reads/writes through these three methods.
 */
export interface ReadStateHandle {
    /** The recorded state for a path, or undefined if it was never read. */
    get(absPath: string): ReadStateRecord | undefined;
    /** Record (or refresh) the state for a path. */
    set(absPath: string, record: ReadStateRecord): void;
    /** Whether a path has any recorded read state this session. */
    has(absPath: string): boolean;
}
/**
 * The string-literal key under which a {@link ReadStateHandle} lives on
 * {@link ToolContext.framework}.
 *
 * Mirrors the existing `DELEGATE_HANDLE_KEY = "delegate"` /
 * `MEMORY_HANDLE_KEY = "memoryStore"` convention: a shared literal both the
 * framework consumer and the product injector reference so they agree without a
 * cross-package type import.
 */
export declare const READ_STATE_HANDLE_KEY: "readState";
/**
 * Everything a tool's `run` is handed besides its own parsed input.
 *
 * It carries the working directory, the two coarse I/O backends, a cancellation
 * `signal`, and the default {@link OutputBudget} a tool should apply when its
 * output risks overflowing the model's window.
 *
 * `framework` is an open bag of optional host-injected handles, keyed by string
 * literals (e.g. {@link READ_STATE_HANDLE_KEY}). It is the additive seam through
 * which a host can opt a session into behaviors like the read-before-edit gate
 * without changing any tool signature; when a handle is absent the tools behave
 * exactly as they did before.
 */
export interface ToolContext {
    readonly cwd: string;
    readonly fs: Fs;
    readonly shell: Shell;
    readonly signal: AbortSignal;
    readonly budget: OutputBudget;
    /** Open record of optional, host-injected framework handles. */
    readonly framework?: {
        readonly [key: string]: unknown;
    };
}
/**
 * The declarative description of one tool.
 *
 * `I` is the input shape `run` expects after coercion. The kernel validates the
 * raw call against `parameters` loosely (presence and basic typing) and hands a
 * best-effort `I` to `run`; rigorous validation, where a tool wants it, lives in
 * `run` itself.
 */
export interface ToolSpec<I = unknown> {
    /** The name advertised to and invoked by the model. */
    readonly name: string;
    /** The model-facing description of what the tool does and when to use it. */
    readonly description: string;
    /** The JSON-Schema object describing the tool's parameters. */
    readonly parameters: JsonSchema;
    /** The tool's behavior; receives coerced input and the live context. */
    run(input: I, ctx: ToolContext): Promise<ToolResult>;
}
/**
 * A {@link ToolSpec} after {@link defineTool} has wrapped it.
 *
 * `descriptor()` yields the model-facing advertisement; `invoke()` is the
 * runner-side entry point that turns a {@link ToolCall} into a
 * {@link ToolOutcome}.
 */
export interface DefinedTool {
    /** The tool's name (mirrors the spec, exposed for registry bookkeeping). */
    readonly name: string;
    /** The descriptor handed to the model on each invocation. */
    descriptor(): ToolDescriptor;
    /** Execute one call under the given context and normalize the result. */
    invoke(call: ToolCall, ctx: ToolContext): Promise<ToolOutcome>;
    /** Display label for the facade (mirrors the name). */
    readonly label: string;
    /** Top-level description for the facade's tool validation + the model schema. */
    readonly description: string;
    /** Top-level JSON-schema parameters for the facade's tool validation. */
    readonly parameters: JsonSchema;
    /** Facade execution entry point: run the tool and return facade-shaped content. */
    execute(toolCallId: string, params: unknown, signal?: AbortSignal, onUpdate?: (partial: unknown) => void): Promise<{
        content: Array<{
            type: "text";
            text: string;
        }>;
        details: Record<string, unknown>;
        isError: boolean;
    }>;
}
/**
 * Wrap a {@link ToolSpec} into a {@link DefinedTool}.
 *
 * The returned `invoke` coerces the call's input, honors an already-aborted
 * signal up front, runs the spec, and folds both the success result and any
 * thrown failure into a {@link ToolOutcome}. No spec ever has to write this
 * boilerplate itself.
 */
export declare function defineTool<I = unknown>(spec: ToolSpec<I>): DefinedTool;
