/**
 * replay — who may send an MCP tool call again, and what is known of what each
 * attempt did: two facts, decided apart and recorded apart.
 *
 * Pattern: a declaration read once + one permission rule + one accumulator.
 * Role:    Layer-3 tool transport. `mcpClient({ replay })` reads the app's
 *          declaration (`replayDeclarationOf`) when the client is built. The
 *          call's retry series (`throttleRetry.ts` · `Series`) asks `permit`
 *          before every repeat and records the answer beside the attempt;
 *          `SeriesKnowledge` carries what is known of the series' effect from
 *          one attempt to the next.
 *
 * ── THE LAW ──────────────────────────────────────────────────────────────────
 * PERMISSION to repeat comes only from the app: the (server, tool) pairs it
 * declares — the server is the client the declaration is given to — and the
 * failure kinds each tool may be repeated on. Never from the model, a tool's
 * description or a server's annotations (`readOnlyHint`): nothing here reads
 * them. It is configuration, read once when the client is built — never a
 * per-call question.
 *
 * KNOWLEDGE of whether an attempt ran comes only from the record and from an
 * established service guarantee. No reply this library reads is one. A 429 is
 * not: RFC 6585 §4 defines it as rate limiting, and `Retry-After` says when to
 * ask again, not that asking is safe. AgentCore Runtime's session-busy body is
 * not either: AWS documents a retryable conflict while a session starts or
 * stops, and the body is matched by its code and words, which a server behind
 * the runtime can send after it ran the call. So every attempt that was sent
 * and did not complete is `unknown`; `none` is only a request never sent. A
 * vendor's own SDK may retry its own 429s because the vendor documents its own
 * service; a generic MCP client cannot assume that of an arbitrary server.
 *
 * Neither is read from the other: a permission never makes an effect known,
 * and an effect never grants a permission.
 *
 * ── WHAT A REPEAT IS ─────────────────────────────────────────────────────────
 * The same validated, authorized request sent again: the same body — the same
 * arguments — to the same server, in the same session, as the same identity.
 * Nothing is re-planned. A credential the library vends, or a signature, is
 * made afresh for each attempt (signatures expire), for that same identity.
 *
 * ── THE POLICIES ─────────────────────────────────────────────────────────────
 *   'compatibility' — the default, kept in 12.0: today's behaviour by name. A
 *       429 is repeated for every tool, on the ASSUMPTION that the server
 *       refused it before running it. Each such repeat records that
 *       assumption; the attempt's effect stays `unknown`, and the caller sees
 *       the error it always did. It gains none of the strict policy's
 *       guarantees: it never establishes that answers are seen or that
 *       requests are matched to their calls.
 *   'app-authorized' — opt-in, by name only: a 429 or a network failure is
 *       repeated only when the app's entry for the tool names it. What the
 *       caller sees follows footprintjs's law
 *       (`RequestReplay` · `uncertain`, `callLifetime.ts`): a received refusal
 *       or error keeps the server's error as it came, its effect still
 *       `unknown`; a call that genuinely lacked an answer somewhere — an
 *       attempt with no response, or a request accepted over HTTP whose
 *       JSON-RPC answer never came — and then fails, fails with
 *       `UnknownEffectError`, its final error the cause. That needs each
 *       request matched to its call and each answer seen; a connection that
 *       cannot give both refuses the tool call before its request is sent
 *       (`replayUnavailable.ts`), so the contract never silently weakens. It
 *       never falls back to 'compatibility', and nothing chooses it from the
 *       transport.
 *
 * Under both, the adapter the app chose retries its own refusal within the
 * budget — AgentCore's session-busy reply — as the ADAPTER's policy, on an
 * assumption it records the same way (`permission: { by: 'adapter', assumes }`),
 * never as evidence. And THE SIDE-EFFECT GUARD holds: a tool the app declares
 * as making changes is never repeated automatically unless the server is
 * declared to deduplicate by an idempotency key the call carries —
 * footprintjs's law, a retry of an effect without a key can apply it twice. A
 * key protects only when the server uses it; the library cannot check that.
 *
 * The protocol's own requests (`initialize`, `tools/list`, notifications) run
 * no tool. The declaration does not govern them, and a 429 on one is asked
 * again under both policies, as it always was. They file no record.
 */
import type { ToolRequestEffect, ToolRequestPermission, ToolRequestReason, ToolRequestReplayKind } from '../events/payloads.js';
/**
 * Which rule decides whether a tool call is sent again after a refusal or a
 * failure. `'compatibility'` is the default, kept in 12.0: it keeps its stated
 * retry assumption and gains none of the strict guarantees. `'app-authorized'`
 * applies only when written, and never falls back to `'compatibility'`.
 */
export type McpReplayPolicy = 'app-authorized' | 'compatibility';
/**
 * A failure kind the app may declare a tool repeatable on: HTTP 429
 * (`'throttle'`), or a request that failed in transport without an answer
 * (`'network'`, footprintjs's category: a dropped or refused connection, or a
 * timeout raised below the retry series). Either may have run on the server, so
 * a repeat after it leaves the call's effect `unknown`.
 */
export type McpReplayKind = ToolRequestReplayKind;
/** One tool's entry in {@link McpReplayOptions.tools}. */
export interface McpReplayTool {
    /**
     * The failure kinds this tool may be sent again on. Default: none. Under
     * `'compatibility'` a 429 is repeated without it, recorded as an assumption;
     * under `'app-authorized'` only what is named here is repeated.
     */
    readonly on?: readonly McpReplayKind[];
    /**
     * `true` — this tool makes changes. It is then never sent again
     * automatically, under either policy, unless the server is declared to
     * deduplicate (`deduplicates`) and the call carries the key.
     */
    readonly changes?: boolean;
}
/**
 * How the server deduplicates a tool call: by an idempotency key the call
 * carries in the named argument. Declare it only when the server does; a key
 * protects only when the server uses it.
 */
export interface McpReplayDeduplication {
    /**
     * The argument that carries the key — present as a non-empty string in the
     * call for a repeat to be allowed. Set it in your code (a `toolMiddleware`
     * that writes it from the call), never from what the model wrote: a key the
     * model reuses for a different operation makes the server drop that one.
     */
    readonly argument: string;
}
/**
 * The app's replay declaration for one MCP server — its client. Read once when
 * the client is built; a field it does not know is refused there, so a
 * misspelled `changes` cannot quietly switch the side-effect guard off.
 */
export interface McpReplayOptions {
    /**
     * Default `'compatibility'`, in 12.0 as in 11.x. An explicit
     * `'app-authorized'` never falls back to it.
     */
    readonly policy?: McpReplayPolicy;
    /** The tools of this server, by the name the server lists them under. */
    readonly tools?: Readonly<Record<string, McpReplayTool>>;
    /** The server deduplicates by an idempotency key the call carries. */
    readonly deduplicates?: McpReplayDeduplication;
}
interface ToolEntry {
    readonly on: ReadonlySet<McpReplayKind>;
    readonly changes: boolean;
}
/** @internal A declaration, read and checked once. */
export interface ReplayDeclaration {
    readonly policy: McpReplayPolicy;
    readonly tools: ReadonlyMap<string, ToolEntry>;
    /** The argument the server deduplicates by, when it is declared to. */
    readonly keyArgument?: string;
}
/** @internal No declaration: the compatibility policy, no tool named. */
export declare const COMPATIBILITY: ReplayDeclaration;
/**
 * @internal `options` read as a declaration — `undefined` is the compatibility
 * policy with nothing named.
 *
 * @throws TypeError naming the field, never echoing a value, for anything the
 *   rule cannot mean: an unknown field, a policy or kind it does not know, an
 *   argument name that is not one.
 */
export declare function replayDeclarationOf(options: unknown, where: string): ReplayDeclaration;
/**
 * @internal Whether the declaration needs a retry series even with the 429
 * rule off (`retryOnThrottle: false`): a tool declared repeatable on
 * `'network'`, or the `'app-authorized'` policy — its record and its "may have
 * run" rest on the series.
 */
export declare function needsSeries(declaration: ReplayDeclaration): boolean;
/**
 * @internal One request, as the permission rule needs it: the protocol's own,
 * or a `tools/call` — its tool when the body names one, and whether its
 * arguments carry the key the server deduplicates by.
 */
export type ReplayTarget = {
    readonly kind: 'protocol';
} | {
    readonly kind: 'tool';
    readonly name?: string;
    readonly keyCarried: boolean;
};
/**
 * @internal `body` — the request exactly as it will be sent — read as a
 * target. A declaration that names nothing under `'compatibility'` decides the
 * same for every request, so its bodies are never parsed.
 */
export declare function replayTargetOf(body: unknown, declaration: ReplayDeclaration): ReplayTarget;
/** @internal A failure the series met, as the permission rule reads it. */
export interface MetFailure {
    /** A refusal a rule recognised (`throttle`, `session-busy`), or a request that failed in transport. */
    readonly kind: 'throttle' | 'session-busy' | 'network';
    /**
     * What the adapter that recognised this refusal assumes in retrying it, as
     * its own policy — set on its rule. Never evidence of the attempt's effect.
     */
    readonly assumes?: 'refused-before-execution';
}
/** @internal Why the series did not ask again, by the rule. */
export type ReplayDeclined = Extract<ToolRequestReason, 'not-retryable' | 'not-permitted' | 'changes-without-key'>;
/**
 * @internal The rule's answer: ask again, with what allowed it — absent for a
 * protocol request, which has no record — or not, and why.
 */
export type ReplayDecision = {
    readonly repeat: true;
    readonly permission?: ToolRequestPermission;
} | {
    readonly repeat: false;
    readonly declined: ReplayDeclined;
};
/** @internal A thrown failure the rule can read: footprintjs's `network` category, or nothing. */
export declare function thrownFailure(error: unknown): MetFailure | undefined;
/**
 * @internal THE rule: may the series send `target` again after `failure`?
 * Asked before every repeat; the budget is asked after it.
 */
export declare function permit(declaration: ReplayDeclaration, target: ReplayTarget, failure: MetFailure): ReplayDecision;
/**
 * @internal What is known of a whole series' effect, one attempt at a time.
 * Uncertainty survives: once any attempt is `unknown`, the series is, whatever
 * later attempts show — a proven refusal does not resolve it, and a success
 * does not prove the operation happened only once. Evidence that something ran
 * (`applied`) is never erased by a later failure.
 */
export declare class SeriesKnowledge {
    private unknown;
    private applied;
    note(effect: ToolRequestEffect): void;
    get effect(): ToolRequestEffect;
}
/** @internal How `callTool` settled, as the call reads it. */
export type CallVerdict = 'completed' | 'tool-error' | 'failed';
/**
 * @internal One `tools/call` request's replay facts, shared by the series that
 * sends it, the ledger that watches its answer, and the call that waits for it
 * — the ledger hands all three the same object (`requestLedger.ts`).
 *
 * TWO LAYERS, KEPT APART. The series sees HTTP: whether an attempt got a
 * response at all, and the status of the one it delivered. A response is not
 * the MCP call's answer — a 202, or a stream, can be accepted and never carry
 * it — so the ledger watches the connection's incoming messages for the
 * JSON-RPC response to THIS request's id. And "its effect is unknown" is not
 * "it lacked an answer": a received 429 or error is an answer whose effect is
 * unknown.
 *
 * Each fact is written once, by its owner: the series (what it sent, whether an
 * attempt lacked any response, what it delivered, the policy), the ledger (the
 * logical answer), the call (how it settled).
 */
export declare class RequestReplay {
    readonly id: string | number;
    private requests;
    private appAuthorized;
    private attemptUnanswered;
    private delivered;
    private logical;
    private settled;
    private failedAsMayHaveRun;
    /**
     * @param id the request's JSON-RPC id, how its answer is found.
     * @param watched whether the connection's incoming messages are observed —
     *   without that, the logical layer is unknown and never decides anything.
     */
    constructor(id: string | number, watched: boolean);
    /** The series sent the request once more. */
    sentOne(): void;
    /** The series runs under the `'app-authorized'` policy. */
    appAuthorizedPolicy(): void;
    /**
     * The series: an attempt genuinely lacked an answer — no response arrived
     * (a lost connection, a timeout, a cut). A received refusal is never this.
     */
    noAnswer(): void;
    /** The series handed the MCP SDK a response with this status. */
    deliveredStatus(status: number): void;
    /** The ledger: the JSON-RPC response to this request's id arrived. */
    answered(): void;
    /** The call settled; `mayHaveRun` when it failed as "may have run". The first word stands. */
    settle(verdict: CallVerdict, mayHaveRun: boolean): void;
    get sent(): number;
    /**
     * Under `'app-authorized'`, a call that does not complete fails as "may have
     * run" when the call genuinely lacked an answer somewhere: an attempt got no
     * response, or the HTTP layer accepted the request (a 2xx) and the JSON-RPC
     * response never came. A chain of received refusals and errors is an answer
     * throughout: it keeps the server's error.
     */
    get uncertain(): boolean;
    /** The HTTP layer took the request (2xx), and the logical answer never arrived. */
    private get acceptedWithoutAnswer();
    get verdict(): CallVerdict | undefined;
    get mayHaveRun(): boolean;
}
export {};
