/**
 * tools/runChain — INTERNAL. The one place a chain is walked.
 *
 * Pattern: Chain of Responsibility driver.
 * Role:    tools/ layer. Both stages (tool dispatch, message boundary) and
 *          the MCP server call in here, so the ordering law, the
 *          throw-is-a-denial law and the ledger row shape are written once
 *          and cannot drift between the three callers.
 * Emits:   N/A — it RETURNS rows; the caller commits and emits them, so a
 *          middleware still never touches scope.
 *
 * ## The rules this file implements
 *
 * **Order is declaration order.** The chain is walked front to back, and
 * each link is handed the previous link's output — so a scrubber placed
 * first is a scrubber every later rule sees the effect of.
 *
 * **The first non-allow answer wins.** A deny or an ask stops the walk;
 * the links behind it do not run. There is no "second opinion" pass,
 * because a refusal that a later middleware could overturn is not a
 * refusal.
 *
 * **A middleware that throws is a denial, never a pass.** The thrown
 * message becomes the reason. This is the same deny-by-default the
 * permission gate has always applied to a checker that throws: a
 * governance layer whose failure mode is "allow" is not a governance
 * layer.
 *
 * **A middleware that malfunctions is a denial too** (8.18.0). Two ways to
 * malfunction at the message boundary: answer `ask` where no pause exists to
 * carry it, or `allow` a value that is not text. Both used to fall through to
 * the allow branch — the ask filed an allow row for a rule that thought it had
 * paused, and the non-string became `content: undefined` on the wire. Same law,
 * same row: a link whose answer cannot be honoured has not permitted anything.
 *
 * **The result comes back through the onion.** `runToolAfterChain` walks the
 * SAME list in reverse, so the first-declared link gets the first word about
 * the call and the last word about the result. An outer rule is the one that
 * sees what every inner rule already did — which is the only order in which
 * "wrap" means anything.
 *
 * **A link that has no hook for a moment files no row.** It did not decide;
 * saying it allowed would be inventing a decision, and the ledger's whole
 * value is that a row means somebody looked.
 */
import type { LLMMessage } from '../provider-contract/types.js';
import type { MemoryIdentity } from '../memory/identity/types.js';
import type { AskPayload, MessageMiddleware, MiddlewareDecision, ToolMiddleware } from '../core/agent/middleware/types.js';
/** Tool args, as they travel the chain. */
export type ToolArgs = Readonly<Record<string, unknown>>;
/**
 * What to do when a middleware answers `ask` somewhere that cannot pause.
 *
 * `'pause'` — the caller will checkpoint (the normal dispatch path).
 * `'refuse'` — the ask is converted into a deny naming the middleware. Used
 * on the resume path (footprintjs's `PausableHandler.resume` returns void,
 * so a resumed dispatch cannot suspend a second time) and by `mcpServe`
 * (MCP is request/response — there is no pause to carry the ask).
 */
export type AskPolicy = 'pause' | 'refuse';
export type ToolChainResult = {
    readonly kind: 'allow';
    readonly args: ToolArgs;
    readonly decisions: MiddlewareDecision[];
} | {
    readonly kind: 'deny';
    readonly reason: string;
    readonly middleware: string;
    readonly args: ToolArgs;
    readonly decisions: MiddlewareDecision[];
    /**
     * Set when the link did not deny but ASKED, and `askPolicy: 'refuse'`
     * turned the ask into this denial — the call needed a person and there
     * was no pause to carry the question. Absent on every link's own deny.
     */
    readonly refusedAsk?: true;
} | {
    readonly kind: 'ask';
    readonly payload: AskPayload;
    readonly middleware: string;
    /** Index of the link that asked — resume continues from `index + 1`. */
    readonly index: number;
    /** Args as transformed up to the ask. These ride the checkpoint. */
    readonly args: ToolArgs;
    readonly decisions: MiddlewareDecision[];
};
export interface ToolChainInput {
    readonly toolName: string;
    /** `Tool.source` for the tool being dispatched, when it has one. */
    readonly toolSource?: string;
    readonly toolCallId: string;
    readonly iteration: number;
    readonly args: ToolArgs;
    readonly history: readonly LLMMessage[];
    readonly identity?: MemoryIdentity;
    readonly signal?: AbortSignal;
    /**
     * Where to start walking. `0` for a fresh dispatch; `n` on resume, to
     * continue the chain AFTER the link that asked without re-running the
     * links whose decisions the checkpoint already carries.
     */
    readonly startIndex?: number;
    readonly askPolicy?: AskPolicy;
}
/** Walk the tool chain. Never throws — a throwing link becomes a denial. */
export declare function runToolChain(chain: readonly ToolMiddleware[], input: ToolChainInput): Promise<ToolChainResult>;
export type ToolAfterChainResult = {
    readonly kind: 'allow';
    readonly result: unknown;
    readonly decisions: MiddlewareDecision[];
} | {
    readonly kind: 'deny';
    readonly reason: string;
    readonly middleware: string;
    /** The tool's REAL result. The side effect happened; the record says so. */
    readonly result: unknown;
    readonly decisions: MiddlewareDecision[];
};
export interface ToolAfterChainInput {
    readonly toolName: string;
    readonly toolSource?: string;
    readonly toolCallId: string;
    readonly iteration: number;
    /** The args the tool ACTUALLY ran with — every before-transform applied. */
    readonly args: ToolArgs;
    readonly result: unknown;
    /** `true` when the tool threw and `result` is the error's message. */
    readonly error?: true;
    readonly history: readonly LLMMessage[];
    readonly identity?: MemoryIdentity;
    readonly signal?: AbortSignal;
}
/**
 * Walk the chain BACKWARDS over a finished call. Never throws — a throwing
 * link becomes a denial, which at this moment means the model reads the
 * reason instead of the result.
 *
 * Only called for a call that actually executed. A call the chain denied, or
 * one still waiting on a person, has no result to decide about, and asking a
 * rule about a result that does not exist would be the same fabrication the
 * outcome union exists to prevent.
 */
export declare function runToolAfterChain(chain: readonly ToolMiddleware[], input: ToolAfterChainInput): Promise<ToolAfterChainResult>;
export type MessageChainResult = {
    readonly kind: 'allow';
    readonly content: string;
    readonly decisions: MiddlewareDecision[];
} | {
    readonly kind: 'deny';
    readonly reason: string;
    readonly middleware: string;
    /** Content as transformed by the links BEFORE the refusal. */
    readonly content: string;
    readonly decisions: MiddlewareDecision[];
};
export interface MessageChainInput {
    readonly phase: 'input' | 'output';
    readonly content: string;
    readonly history: readonly LLMMessage[];
    /** ReAct iteration for the ledger row. `0` at `'input'` (before iter 1). */
    readonly iteration: number;
    readonly identity?: MemoryIdentity;
    readonly signal?: AbortSignal;
}
/** Walk the message chain. Never throws — a throwing link becomes a denial. */
export declare function runMessageChain(chain: readonly MessageMiddleware[], input: MessageChainInput): Promise<MessageChainResult>;
//# sourceMappingURL=runChain.d.ts.map