/**
 * selfExplain — the IN-CONVERSATION door over the agent's own trace.
 *
 * `.selfExplain()` on the builder mounts ONE skill plus ONE scoped tool
 * provider. Day to day the tool catalog carries only the skill's
 * activation row — the trace tools are NOT in the skill (skill `tools`
 * land in the static registry, exposed every iteration); they ride a
 * `skillScopedTools` provider gated on the skill's activation, composed
 * with whatever provider the consumer already set. When the user asks a
 * why-question the LLM activates the skill, and the NEXT iteration's
 * catalog gains the trace tools, bound to the agent's own PREVIOUS
 * COMPLETED run.
 *
 * The two pieces here:
 *
 * 1. `SelfExplainBinding` — the late-binding seam, a plain CombinedRecorder
 *    attached like any consumer recorder (zero engine changes):
 *
 *      - capture at `onRunEnd`/`onRunFailed`: the just-finished run's
 *        snapshot becomes the explainable evidence (a FAILED run is
 *        still a completed trace — "why did you fail?" works);
 *      - rotate at `onRunStart`: a FRESH ControlDepRecorder per run. The
 *        retired instance never sees the new run's events, so its live
 *        `asLookup()` survives Convention-4's runId reset — the captured
 *        control edges stay valid for the whole next turn.
 *
 *    B13 safety lives here: `Agent.run()` reassigns its executor at run
 *    START, so resolving artifacts mid-run through `getLastSnapshot()`
 *    would expose the IN-FLIGHT run. Capturing only at terminal flush
 *    means the binding can never serve anything but a completed run.
 *
 *    Keyed PER CONVERSATION (R2-11): one agent instance can serve
 *    many people (`standingAgent({ agent })`), so "the previous completed
 *    run" is asked of the ASKING run's session — the evidence of the last
 *    run that session completed, never whichever run the instance finished
 *    last. A run with no session reads the last run that had none. A tool's
 *    retained inner runs are served through the same key
 *    (`core/innerRunRecords.ts · innerRunsOfConversation`).
 *
 * 2. `buildSelfExplainSkill` — the skill in two modes:
 *
 *      - INLINE (default): the skill unlocks the trace tools — every name
 *        in `TRACE_TOOL_NAMES` (11 today) — in the main agent's own loop
 *        (same model). The count is deliberately not restated anywhere
 *        that could fall behind the pack.
 *      - DELEGATE: the skill unlocks ONE tool — `explain_run(question)` —
 *        whose execute runs a nested `traceDebugAgent` on the consumer's
 *        chosen (cheaper) provider/model and returns its evidence-cited
 *        answer. The main conversation pays for one tool call; the
 *        trace-walking loop happens at the delegate's price. Loaded via
 *        dynamic import so the builder never statically pulls Agent
 *        through this module (no core ↔ lib cycle).
 */
import { type CombinedRecorder, type RuntimeSnapshot } from 'footprintjs';
import type { Injection } from '../injection-engine/types.js';
import type { AgentOptions } from '../core/agent/types.js';
import type { Unsubscribe } from '../events/dispatcher.js';
import type { AgentfootprintEvent } from '../events/registry.js';
import type { ToolProvider } from '../tools/toolProvider.js';
import { type InnerRunLookup } from '../core/innerRunRecords.js';
import type { TraceToolpackArtifacts, TraceToolpackOptions } from './types.js';
/**
 * How much of a turn's evidence the binding keeps.
 *
 * Both default to TRUE, which is the point: the tools that read them
 * (`read_narrative`, `inspect_tool_call`) are on the catalog either way,
 * and a tool that answers "⚠ no evidence" by default is a tool that
 * teaches the model not to call it. Turn one off when the cost matters
 * more than the answer — a very long-running turn, or a run whose
 * narrative would repeat what the structured tools already say.
 */
export interface SelfExplainInclude {
    /** The run's plain-English story → the `read_narrative` tool. Default true. */
    readonly narrative?: boolean;
    /**
     * A bounded tail of the run's typed events → tool-call timings and
     * outcomes in `inspect_tool_call`, and the Context Integrity findings
     * `find_context_errors` reads. Default true. Off means no wildcard event
     * subscription is made at all, not a subscription that is ignored — and
     * `find_context_errors` then reports the evidence channel as ABSENT
     * rather than reporting a run with no context errors.
     */
    readonly events?: boolean;
}
/** Consumer surface for `.selfExplain()` on the Agent builder. */
export interface SelfExplainOptions {
    /** Appended to the recommended skill body (ours stays; yours adds). */
    readonly instruction?: string;
    /**
     * Answer why-questions on a SEPARATE (typically cheaper) model: the
     * skill unlocks one `explain_run` tool that runs a nested
     * `traceDebugAgent` and returns its evidence-cited answer.
     */
    readonly delegate?: {
        readonly provider: AgentOptions['provider'];
        readonly model: string;
        readonly maxIterations?: number;
    };
    /** Skill id (activation key for `read_skill`). Default 'self-explain'. */
    readonly id?: string;
    /** Bounding dials forwarded to the toolpack. */
    readonly toolpack?: TraceToolpackOptions;
    /** Which optional parts of a turn's evidence to capture. Both default true. */
    readonly include?: SelfExplainInclude;
    /**
     * Cap on retained events per turn (only with `include.events`). Default
     * 2,000 — enough for a long tool-using turn, small enough that a server
     * holding one binding per agent does not grow without limit. A tail that
     * dropped events says so in `inspect_tool_call`.
     */
    readonly maxEvents?: number;
}
/** Default per-turn event cap for the self-explain binding. */
export declare const SELF_EXPLAIN_MAX_EVENTS = 2000;
/** Which conversation the agent is serving, and which run — see {@link SelfExplainSource.getServing}. */
export interface SelfExplainServing {
    /** The evidence key. `undefined` = a direct run with no session. */
    readonly conversation: string | undefined;
    /** The run in flight, or the one served last. */
    readonly runId: string;
    /** A conversation no later request can name (a hosted request with no
     *  session) — kept on its own, smaller shelf. */
    readonly oneShot?: boolean;
}
/**
 * What the binding reads a completed turn's evidence FROM.
 *
 * One object rather than three wiring calls, on purpose: the
 * `BoundaryRecorder` lesson in this codebase is that a seam needing three
 * separate connections gets two of them in some integrations, and the
 * missing third fails silently. Here the only caller is `AgentBuilder`,
 * and it hands over all of it at once.
 */
export interface SelfExplainSource {
    /** The just-finished run's snapshot — `agent.getLastSnapshot()`. */
    getSnapshot(): RuntimeSnapshot | undefined;
    /** The run's narrative entries — `agent.getLastNarrativeEntries()`. */
    getNarrative?(): readonly {
        readonly text: string;
    }[];
    /** The typed event stream — `agent.on('*', …)`. */
    on?(type: '*', listener: (event: AgentfootprintEvent) => void): Unsubscribe;
    /**
     * The records TOOLS kept of their own runs — present when the agent
     * mounts a `flowchartAsTool({ keepRecord: true })`. Unlike the other
     * three, this is NOT captured at the terminal flush: the store is a live,
     * bounded object owned by the tool, and the binding holds the lookup so
     * `inspect_tool_run` reads whatever the tool has filed. Rotating it per
     * turn would throw away the previous turn's inner runs at exactly the
     * moment the follow-up question arrives.
     */
    getInnerRuns?(): InnerRunLookup | undefined;
    /**
     * The conversation the agent is serving — or, between runs, served last —
     * and that run's id. The conversation is the KEY the evidence is kept and
     * served under: read at the terminal flush it names the conversation the
     * finished turn belongs to, read inside a turn it names the conversation
     * asking. It is the run's session; a HOSTED run with no session gets the
     * host's per-request key, which nobody can present again; only a direct run
     * with no session shares `undefined`. Absent (a bare `getSnapshot` binding)
     * every run shares one key — the single-conversation behaviour — and inner
     * runs are served unfiltered.
     */
    getServing?(): SelfExplainServing;
}
/**
 * The late-binding seam. Create one per built Agent, attach
 * `binding.recorder()` via `agent.attach()`, and point `bindTo()` at the
 * agent's `getLastSnapshot`. `artifacts` then always answers with the
 * previous COMPLETED run of the asking conversation — never the in-flight
 * one, and never another conversation's.
 */
export declare class SelfExplainBinding {
    private readonly include;
    private readonly maxEvents;
    private source;
    private ctrl;
    private tail;
    /** Evidence and run ids per conversation (see
     *  {@link SelfExplainSource.getServing}), on two shelves: one for
     *  conversations a caller can come back to ({@link MAX_CONVERSATIONS}), one
     *  for one-shot ones ({@link MAX_ONE_SHOT_CONVERSATIONS}). Insertion order is
     *  recency order. Run ids are recorded at run START, so a run that PAUSED or
     *  FAILED (neither reaches the terminal capture) still owns the records its
     *  tools filed (recheck RS4). */
    private readonly lasting;
    private readonly oneShot;
    constructor(include?: SelfExplainInclude, maxEvents?: number);
    private get wantsNarrative();
    private get wantsEvents();
    /**
     * Point the binding at the agent it explains.
     *
     * Accepts the bare `getSnapshot` function it has always accepted (the
     * evidence a completed run leaves behind on its own), or the full
     * source, which adds the two parts a snapshot does NOT carry: the
     * narrative, and the typed event stream.
     */
    bindTo(source: SelfExplainSource | (() => RuntimeSnapshot | undefined)): void;
    /**
     * Evidence of the previous completed run OF THE ASKING CONVERSATION, or
     * undefined when that conversation has completed none (or its evidence was
     * dropped past the bound). Never another conversation's.
     */
    get artifacts(): TraceToolpackArtifacts | undefined;
    /**
     * Does the binding serve the run a tool call is in? Only the agent's OWN run
     * — the one its instance is serving — reads its evidence. A call from the
     * agent mounted as a composition member carries that composition's run id
     * (`ctx.runId`), which is never the instance's: the instance's evidence is
     * another caller's, so it is not served there.
     */
    servesRun(runId: string | undefined): boolean;
    /** The conversation (and run) in flight, or served last. */
    private serving;
    /** Which shelf a conversation lives on. */
    private shelfOf;
    /** Remember that the serving run belongs to its conversation (bounded both ways). */
    private recordRun;
    /** File the serving conversation's evidence as its most recent, within the bound. */
    private file;
    /** The recorder to attach — forwards flow events to the per-run ctrl. */
    recorder(): CombinedRecorder;
}
/** The default skill id — the activation key the LLM passes to read_skill. */
export declare const SELF_EXPLAIN_SKILL_ID = "self-explain";
/**
 * The skill `.selfExplain()` mounts — methodology body ONLY. The trace
 * tools deliberately do NOT ride the skill: skill `tools` land in the
 * static registry (exposed every iteration); catalog gating is the
 * ToolProvider's job — see {@link buildSelfExplainToolProvider}.
 */
export declare function buildSelfExplainSkill(options: SelfExplainOptions): Injection;
/**
 * The gated tool delivery — `skillScopedTools` (the shipped primitive)
 * scoped to the skill's id, composed with the consumer's own provider
 * when they set one. The iteration after activation, `ctx.activeSkillId`
 * matches and the catalog gains the trace tools (inline) or the single
 * `explain_run` tool (delegate).
 *
 * INLINE MODE LOADS THE PACK LAZILY (9.94.0). The toolpack module is the
 * largest single module on the library's default graph, and until this
 * release every consumer who imported `Agent` carried it — `.selfExplain()`
 * or not — because this function reached it statically. Now the pack is
 * `import()`ed the first time the self-explain skill is ACTIVE on an
 * iteration, and never before: not at `build()`, not on a turn where the
 * model never opened the skill, not at all for an agent that did not enable
 * `.selfExplain()`. A bundler splits it into its own chunk; Node loads it
 * through the same `require` it always did, one microtask later.
 *
 * What the consumer sees: `list(ctx)` still answers `[]` synchronously when
 * the skill is not active (the sync fast path the tools slot skips the await
 * for), and a Promise of the same eleven tools when it is — the shape
 * `ToolProvider.list` has always allowed, and the one the composed provider
 * below already used. The provider id is unchanged, so `.watch()` output and
 * the `skill-scoped:` refusal in the builder read exactly as before.
 */
export declare function buildSelfExplainToolProvider(binding: SelfExplainBinding, options: SelfExplainOptions, existing?: ToolProvider): ToolProvider;
//# sourceMappingURL=selfExplain.d.ts.map