/**
 * pause — runner-level pause/resume primitives.
 *
 * Pattern: Control-flow exception (PauseRequest) + typed outcome (RunnerPauseOutcome).
 * Role:    core/ layer. Bridges footprintjs.s pause signal into the agentfootprint
 *          Runner contract: tools call `pauseHere(data)` to raise a pause
 *          intent; runners detect the paused executor result and return a
 *          `RunnerPauseOutcome` instead of `TOut`. Consumers call
 *          `runner.resume(checkpoint, input)` to continue.
 * Emits:   N/A (types + helpers only). Event emission happens in RunnerBase.
 *
 * Why a control-flow "throw": tool.execute(args, ctx) doesn't receive the
 * typed scope, so it cannot call `scope.$pause()` directly. A thrown
 * `PauseRequest` is caught inside the Agent's tool-call stage, which then
 * forwards the pause into the flowchart via `scope.$pause()`. This keeps
 * the tool API clean (tools are pure-ish) while still supporting pause.
 */
import type { FlowchartCheckpoint } from 'footprintjs';
import type { AskComponent } from '../tools/askComponent.js';
import type { CheckInRequest } from './checkin.js';
import type { AwaitingInput, InputRequestDeclaration } from '../tools/inputRequest.js';
/**
 * Outcome returned by `runner.run()` / `runner.resume()` when execution
 * has paused mid-flow. The shape mirrors footprintjs's `PausedResult` but
 * surfaces `pauseData` as a first-class field for consumers who don't
 * want to reach into the checkpoint.
 */
export interface RunnerPauseOutcome {
    readonly paused: true;
    /** Serializable checkpoint — store anywhere (Redis, Postgres, localStorage). */
    readonly checkpoint: FlowchartCheckpoint;
    /** Data passed to `scope.$pause()` / `pauseHere()`. Consumer-typed. */
    readonly pauseData: unknown;
    /** Typed data collection; answers are values, never approval decisions. */
    readonly awaitingInput?: AwaitingInput;
    /**
     * Present ONLY when this pause is an evidence-carrying check-in (a tool
     * declared `checkIn`). Carries the typed ask + evidence pack. Absent for
     * plain `askHuman` / `pauseHere` pauses — that's the clean discriminant
     * between the two pause kinds. Resume with a `CheckInDecision` built from
     * it (`checkInApproved({ request: outcome.checkIn, by })` /
     * `checkInDeclined(...)`) — `checkIn.id` names the request it answers.
     */
    readonly checkIn?: CheckInRequest;
    /**
     * Present ONLY when a `toolMiddleware` answered `ask` — the question it put
     * to a person, plus the middleware that asked. Absent for every other pause,
     * which is the discriminant.
     *
     * Resume with a `CheckInDecision` built from it
     * (`checkInApproved({ request: outcome.ask, by })` / `checkInDeclined(...)`).
     * That is deliberate rather than a second decision type: a person approving
     * is a person approving, whether the gate was a tool's `checkIn` or a
     * middleware's `ask`, and one word for one thing beats a synonym.
     *
     * The answer is a DECISION, not a result. Approve and the chain resumes from
     * the next middleware and the REAL tool runs; decline and the model receives
     * a denial it can adapt to. Nobody — not the middleware, not the person —
     * gets to write the tool's answer.
     */
    readonly ask?: MiddlewareAsk;
}
/** The question a `toolMiddleware` put to a person, as it rides the checkpoint. */
export interface MiddlewareAsk {
    /**
     * Names this request: the id a decision quotes
     * (`checkInApproved({ request: outcome.ask, by })`). Minted when the run
     * paused, unique to this pause, and bound to the exact call that runs on
     * approval — see `core/consentRequest.ts`.
     */
    readonly id: string;
    /** The question, in the middleware author's own words. */
    readonly question: string;
    /** Anything else the answering UI should render. Never interpreted here. */
    readonly detail?: unknown;
    /**
     * Which REGISTERED screen component collects the answer (9.24.0) — the
     * typed half of the question, carried from `ask({ question, component })`.
     * Absent means what it always meant: render the prose. The answer comes
     * back through the same `CheckInDecision` either way.
     */
    readonly component?: AskComponent;
    /** `name` of the middleware that asked. */
    readonly middleware: string;
}
/** Type guard — discriminates `RunnerPauseOutcome` from a normal `TOut`. */
export declare function isPaused<T>(result: T | RunnerPauseOutcome): result is RunnerPauseOutcome;
/** A missing-input pause, distinct from every consent gate. */
export declare function isInputPause(result: unknown): result is RunnerPauseOutcome & {
    readonly awaitingInput: AwaitingInput;
};
/**
 * Collect declared fields using a dedicated tool. The query itself runs afterwards.
 *
 * When a lookup does raise about its own miss (the dedicated collection tool
 * stays the documented shape), it still declares what it looked at
 * (9.114.0): pass the envelope `absent()` returns as `absence`. The dispatch
 * door files it at the raise — the rows a returned `absent(…)` files — and it
 * never rides `awaitingInput`. A value the absence recognizer cannot read
 * throws `InputRequestError` here (`absence: null` is the field omitted); an
 * envelope it reads whose lists cannot be copied (a hand-built
 * `checked: [null]`) errors the call at the door instead of pausing, as the
 * same value returned would.
 */
export declare function requestInput(declaration: InputRequestDeclaration): never;
/**
 * Type guard — is this a check-in pause (evidence-carrying human consent),
 * as opposed to a plain `askHuman` pause? Narrows `checkIn` to present.
 *
 * @example
 *   const out = await agent.run({ message });
 *   if (isCheckInPause(out)) {
 *     showToHuman(out.checkIn.evidence);       // the receipts
 *     const decision = checkInApproved({ request: out.checkIn, by: 'alice' });
 *     await agent.resume(out.checkpoint, decision);
 *   }
 */
export declare function isCheckInPause(result: unknown): result is RunnerPauseOutcome & {
    readonly checkIn: CheckInRequest;
};
/**
 * Type guard — is this a middleware-ask pause (a `toolMiddleware` answered
 * `ask`), as opposed to a check-in or a plain `askHuman` pause? Narrows `ask`
 * to present.
 *
 * @example
 *   const out = await agent.run({ message });
 *   if (isAskPause(out)) {
 *     const yes = await showToHuman(out.ask.question);      // asked by out.ask.middleware
 *     await agent.resume(out.checkpoint, yes
 *       ? checkInApproved({ request: out.ask, by: 'alice' })
 *       : checkInDeclined({ request: out.ask, by: 'alice', note: 'not this one' }));
 *   }
 */
export declare function isAskPause(result: unknown): result is RunnerPauseOutcome & {
    readonly ask: MiddlewareAsk;
};
/**
 * The two pause kinds whose answer is a DECISION rather than a value.
 *
 * A **`'checkIn'`** pause is the tool's own consent demand, and its identity is
 * the evidence pack. A **`'ask'`** pause is a `toolMiddleware`'s own question.
 * Both are answered with `checkInApproved()` / `checkInDeclined()`, built from
 * the paused request so the decision names it (`ResumeDecisionError`).
 *
 * Everything else — `pauseHere()` / `askHuman()`, and the 3LO credential-consent
 * pause — is NOT a consent gate in this sense: there the human's answer either
 * IS the tool's result or is ignored entirely, and any value is accepted.
 */
export type ConsentGateKind = 'checkIn' | 'ask';
/** What {@link pauseDemandsDecision} reports about a pause that is a consent gate. */
export interface ConsentGate {
    readonly kind: ConsentGateKind;
    /** The tool the gate is about, when the pause payload named one. */
    readonly toolName?: string;
    /** `'ask'` only — the `name` of the middleware that asked. */
    readonly middleware?: string;
}
/**
 * Read a pause payload and say whether answering it requires a
 * `CheckInDecision` — and if so, which gate is outstanding.
 *
 * THE ONE reader of that shape. `RunnerBase.detectPause` builds
 * `outcome.checkIn` / `outcome.ask` from this, and `Agent.resume` refuses a
 * mis-shaped answer from this, so the surface a consumer is told about and the
 * surface the library enforces cannot drift apart.
 *
 * Keyed on the PAUSE, never on the input: a plain `askHuman` answer is a string
 * and must stay one, so "is this the right answer?" can only be decided by
 * knowing what was asked.
 *
 * @returns the gate, or `undefined` when this pause takes any value.
 */
/**
 * Refuse an answer chosen against different bytes than the question was asked
 * against. See {@link StaleDecisionError}.
 *
 * Silent in every case but one, deliberately: the ask has to have pinned a ref
 * AND the answer has to name one. Either side absent means nobody claimed the
 * two were about the same artifact, and inventing that claim here would refuse
 * answers that are perfectly good.
 */
export declare function assertDecisionIsNotStale(pauseData: unknown, input: unknown): void;
export declare function pauseDemandsDecision(pauseData: unknown): ConsentGate | undefined;
/**
 * Raised by `agent.resume()` when a run paused on a CONSENT GATE and the resume
 * input is not a `CheckInDecision`.
 *
 * Before 8.13.0 that resume silently DECLINED, attributed to `by: 'unknown'` —
 * a `checkin.decision` record naming a person who was never asked. A governance
 * layer that invents a decision is worse than one that drops it: the run reads
 * as consented-and-refused when nobody consented to anything.
 *
 * **Nothing was executed and the checkpoint is unchanged** — this refuses at the
 * API boundary, before the engine is handed the checkpoint. Answer the gate and
 * resume the same checkpoint again.
 *
 * A plain `askHuman()` / `pauseHere()` pause never raises this: there the
 * human's answer IS the tool's result, so any value is accepted. The 3LO
 * credential-consent pause never raises it either — it re-asks the provider and
 * ignores the input by design.
 */
/**
 * The person answered about something the ask was not about.
 *
 * A typed ask can pin the data the answer is to be chosen FROM — the
 * `propsRef` on its {@link AskComponent}, a 200-row picker's options living in
 * the artifact store rather than in every stored session envelope. A
 * {@link DecisionValue} can say which artifact the choice was made AGAINST.
 * When both are present and they disagree, the answer is about different bytes
 * than the question.
 *
 * That happens for an ordinary reason: time passes between asking and
 * answering. A refresh lands, a filter moves, rows re-sort, the ask is re-raised
 * with new options — and "the third row" now names something else. Accepting it
 * would resume the run with a value the person never chose, and there is no
 * later signal that anything went wrong: the id is well-formed, the type checks,
 * the loop continues.
 *
 * So it refuses, and the refusal is the feature. A person asked again is mildly
 * annoyed; a person whose gesture was silently reinterpreted has been
 * misrepresented, and in a consent record that is the one failure nothing
 * downstream can recover from.
 *
 * Only ever raised when the ask pinned a ref AND the answer named one. An
 * approve/decline, a plain `askHuman` value, or an answer that names no
 * artifact are all byte-identical to every earlier release.
 */
export declare class StaleDecisionError extends Error {
    readonly code: "ERR_STALE_DECISION";
    /** The artifact the QUESTION was asked against. */
    readonly asked: string;
    /** The artifact the ANSWER was chosen against. */
    readonly answered: string;
    constructor(asked: string, answered: string);
}
export declare class DecisionRequiredError extends Error {
    readonly code: "ERR_DECISION_REQUIRED";
    /** Which gate is outstanding. */
    readonly gate: ConsentGateKind;
    /** The tool the gate is about, when the pause named one. */
    readonly toolName?: string;
    /** `'ask'` only — the middleware that asked. */
    readonly middleware?: string;
    /**
     * What arrived instead, as a TYPE NAME only (`'a string'`, `'nothing'`, …).
     *
     * Never the value. A resume payload is caller data that may carry anything a
     * person typed, and an error message is copied into logs, tickets and crash
     * reporters by default.
     */
    readonly received: string;
    constructor(gate: ConsentGate, input: unknown);
}
/**
 * Why a decision could not answer the request a run is paused on — the
 * {@link ResumeDecisionError} `reason`:
 *
 *   - `'no-request'` — the decision names no request (`requestId` missing):
 *     one built by an older release, or by hand.
 *   - `'request-not-recorded'` — the PAUSE recorded no request to answer: a
 *     checkpoint written before requests were named, or one whose record was
 *     removed.
 *   - `'other-request'` — the decision names a different request: another
 *     conversation's, an earlier pause of this run, a parallel sibling's.
 *   - `'call-changed'` — the decision names this request, but the paused call
 *     is no longer the one the person was asked about (the checkpoint's tool,
 *     arguments, call id, served party, or — for an ask — the middleware
 *     position or the rules recorded after it changed).
 *   - `'chain-changed'` — an ask only: the decision names this request and
 *     the checkpoint is intact, but the agent resuming it would continue the
 *     middleware chain under other rules than the ones the person was asked
 *     under — the link that asked, or a link after it, was removed, added,
 *     renamed or moved (a redeploy). An approval holds for the rules it was
 *     given under, so a rule it was given under is never skipped.
 *   - `'already-answered'` — a resume already used a decision for this
 *     request, approved or declined. Whether that resume finished — and so
 *     whether the call ran — is not known to the one refused.
 *   - `'ledger-changed'` — the decision names this request and the call is
 *     intact, but the agent resuming it spends decisions in another ledger
 *     than the one the request was asked under, while that one can prove
 *     whether the call ran (a shared ledger with a `storeId`, or this
 *     process's own default) — a redeploy or a ledger migration. Spent
 *     elsewhere, the call could run where that ledger never saw it; the
 *     person is asked again instead.
 *   - `'closed-by-host'` — a host that kept the pause closed it, because no
 *     answer could reach it any more, and proved its call never ran: it spent
 *     the request in the ledger the request was minted under, so no decision
 *     can run it. The call did not run, and nothing ran now.
 */
export type ResumeDecisionRefusal = 'no-request' | 'request-not-recorded' | 'other-request' | 'call-changed' | 'chain-changed' | 'already-answered' | 'ledger-changed' | 'closed-by-host';
/**
 * Raised by a resume when the decision cannot answer the request the run is
 * paused on. **The tool never runs**: the refusal comes before it, and a
 * decision is never re-read as a decline or as anyone else's answer.
 *
 * A consent gate (a tool's `checkIn`, a middleware's `ask`) mints a request id
 * when it pauses (`CheckInRequest.id`, `MiddlewareAsk.id`). The id is unique to
 * that pause and bound to the exact call that runs on approval — the tool, its
 * arguments, the call id, the served party and, for an ask, where the chain
 * resumes and the names of the rules from there on. A decision names it
 * (`checkInApproved({ request, by })`), and a resume holds the decision to it:
 * the same request, the same call, once.
 *
 * Every refusal but `'already-answered'` is decided before anything moves on
 * an agent's own `resume()`; the checkpoint is unchanged and can be answered
 * with the right decision. `'already-answered'` — and every refusal of a
 * composition's nested agent — is decided where the decision is used, inside
 * the resumed run and still before the tool. See {@link ResumeDecisionRefusal}.
 *
 * **It names no request id** — not in its message, not on a field — and a
 * host sends its message as the refusal's body. A refusal that named the
 * request the run is paused on would hand out the very id it exists to
 * require: a client that retried with it would approve a request nobody was
 * shown. The paused request is the server's to show; it is in the stored
 * pause (`PendingAsk.checkIn` / `.ask`), never in an error.
 */
export declare class ResumeDecisionError extends Error {
    readonly code: "ERR_RESUME_DECISION";
    /** Which rule refused the decision. */
    readonly reason: ResumeDecisionRefusal;
    /** Which kind of consent gate the run is paused on. */
    readonly gate: ConsentGateKind;
    constructor(reason: ResumeDecisionRefusal, gate: ConsentGateKind);
}
/**
 * Raised when an `askHuman()` / `pauseHere()` pause is resumed with NO answer.
 *
 * That pause exists to collect a value, and the value it collects becomes the
 * paused tool's result — the model reads it as what the tool said. Resuming
 * with nothing has two live readings, "the person gave no answer" and "just
 * carry on", and they produce different conversations. So the caller says
 * which; the library does not choose.
 *
 * Until 8.18.0 it chose, and chose invisibly: the missing answer became a
 * `role: 'tool'` message with `content: undefined`, and the run died on the
 * next turn inside the messages slot with a `TypeError` that named neither the
 * tool nor the resume.
 *
 * Nothing ran before this raised and the checkpoint is unchanged — answer it
 * and resume the same checkpoint again.
 */
export declare class PauseAnswerRequiredError extends Error {
    readonly code: "ERR_PAUSE_ANSWER_REQUIRED";
    /** The tool whose `execute()` paused. */
    readonly toolName: string;
    /** The tool call id the pause is filed under. */
    readonly toolCallId: string;
    constructor(ctx: {
        toolName: string;
        toolCallId: string;
    });
}
/**
 * Control-flow error raised by `pauseHere()` inside a tool's `execute()`.
 * Caught by the Agent's tool-call stage, which forwards to `scope.$pause()`.
 * Never propagates to the consumer.
 */
export declare class PauseRequest extends Error {
    readonly data: unknown;
    constructor(data: unknown);
}
/**
 * Called from inside a tool's `execute()` to request a pause. Throws a
 * `PauseRequest` that the Agent catches and forwards to the flowchart.
 *
 * @example
 *   const approveTool: Tool<{ action: string }, string> = {
 *     schema: { name: 'approve', description: 'Ask human', inputSchema: {...} },
 *     execute: async (args) => {
 *       pauseHere({ question: `Approve ${args.action}?`, risk: 'high' });
 *       return ''; // unreachable — pauseHere always throws
 *     },
 *   };
 */
export declare function pauseHere(data: unknown): never;
/** Type guard for a thrown `PauseRequest`. */
export declare function isPauseRequest(err: unknown): err is PauseRequest;
/**
 * Ergonomic alias for `pauseHere(data)` — the human-in-the-loop name.
 *
 * `pauseHere` describes the mechanism (control-flow throw); `askHuman`
 * describes the intent (ask a person to decide). Both work identically.
 *
 * @example
 *   const approveRefund: Tool<{ amount: number }, string> = {
 *     schema: { name: 'approve_refund', description: '...', inputSchema: {...} },
 *     execute: async ({ amount }) => {
 *       if (amount > 1000) askHuman({ question: `Approve $${amount}?` });
 *       return 'auto-approved';
 *     },
 *   };
 */
export declare const askHuman: typeof pauseHere;
