/**
 * FlowchartRecorder — StepGraph projection over `BoundaryRecorder`.
 *
 * Pattern: Pure projection. `attachFlowchart` wires a `BoundaryRecorder`
 *          to the executor + dispatcher; `buildStepGraph` is a fold over
 *          `boundary.getEvents()` that produces the renderer-friendly
 *          `StepGraph` shape Lens (and any other consumer) renders.
 *
 *          ZERO state machine in this file. ZERO event subscription.
 *          ZERO name-based filters. Everything that decides "what's a
 *          step" lives in BoundaryRecorder via capture-time tags
 *          (`actorArrow`, `slotKind`, `primitiveKind`, `isAgentInternal`).
 *
 * Role:    Tier 3 observability. Enabled via
 *          `runner.enable.flowchart({ onUpdate })`. The handle exposes:
 *
 *            handle.getSnapshot()  → derived StepGraph (back-compat)
 *            handle.boundary       → the underlying BoundaryRecorder
 *                                     (Lens reads it directly for richer
 *                                     queries: getSlotBoundaries(),
 *                                     getEventsByType, etc.)
 *
 * Event → StepNode mapping (the entire policy):
 *
 *   run.entry            → StepNode kind='subflow', primitiveKind='Run'
 *   subflow.entry        → StepNode kind='subflow' (skipped if isAgentInternal
 *                                                    or slotKind set —
 *                                                    those are sub-components
 *                                                    of the actor arrows)
 *   fork.branch          → StepNode kind='fork-branch'
 *   decision.branch      → StepNode kind='decision-branch'
 *   llm.start            → StepNode kind=actorArrow ('user→llm' | 'tool→llm')
 *   tool.start           → StepNode kind='llm->tool' (none for a
 *                          `notDispatched` start — a call a paused batch
 *                          never dispatched, 9.113.0; its end stashes no
 *                          result either)
 *   llm.end terminal     → StepNode kind='llm->user' (delivery marker)
 *   loop.iteration       → loop-iteration StepEdge
 *   context.injected     → attached to NEXT user→llm / tool→llm StepNode
 *
 * Result: a one-to-one correspondence between visible scrubbable steps
 * and DomainEvents. Adding a new event type adds one mapping line here
 * (or in the pure projection); no state machine, no merging.
 */
import type { CombinedRecorder } from 'footprintjs';
import type { EventDispatcher } from '../../events/dispatcher.js';
import { BoundaryRecorder, type DomainEvent } from './BoundaryRecorder.js';
/**
 * One node in the step-level flowchart. Node kind drives rendering
 * (actor icon, color). ReAct steps carry token + tool details; topology
 * nodes (subflow / fork-branch / decision-branch) mirror the footprintjs
 * composition events and exist so composition structure (Loop, Parallel,
 * Conditional, Swarm) stays visible in the graph.
 */
export interface StepNode {
    readonly id: string;
    readonly kind: 'user->llm' | 'llm->tool' | 'tool->llm' | 'llm->user' | 'subflow' | 'fork-branch' | 'decision-branch';
    readonly label: string;
    readonly startOffsetMs: number;
    readonly endOffsetMs?: number;
    /** LLM step: token usage of the call that bounded this step. */
    readonly tokens?: {
        readonly in: number;
        readonly out: number;
    };
    /** llm->tool / tool->llm: the tool name. */
    readonly toolName?: string;
    /** user->llm / tool->llm: the model that was invoked. */
    readonly llmModel?: string;
    /** Decomposition of the underlying subflowId (rooted under '__root__'). */
    readonly subflowPath: readonly string[];
    /** Context injections attributed to this step (LLM steps only). */
    readonly injections?: readonly ContextInjection[];
    /** 1-based ReAct iteration this step belongs to. Undefined for
     *  topology / composition nodes. */
    readonly iterationIndex?: number;
    /** Which slot the step's input updated. ReAct steps only. */
    readonly slotUpdated?: 'system-prompt' | 'messages' | 'tools';
    /** True ONLY for `subflow` StepNodes whose primitiveKind is `'Agent'`.
     *  Narrow flag for callers that distinguish ReAct agents from other
     *  composition primitives (cost / iteration / token attribution). */
    readonly isAgentBoundary?: boolean;
    /** Primitive kind from the subflow root description prefix
     *  (`'Agent'` / `'LLMCall'` / `'Sequence'` / etc.). */
    readonly primitiveKind?: string;
    /** True for `subflow` StepNodes representing any KNOWN primitive
     *  (Agent / LLMCall / Sequence / Parallel / Conditional / Loop) —
     *  drives Lens's drill-in container treatment. */
    readonly isPrimitiveBoundary?: boolean;
    /** `inputMapper` payload at the subflow's entry. Subflow nodes only. */
    readonly entryPayload?: unknown;
    /** Subflow shared state at exit. Subflow nodes only.
     *  Undefined for in-progress / paused subflows. */
    readonly exitPayload?: unknown;
    /** LLM's text content. Set on `llm->tool` (the reasoning emitted with the
     *  tool_use blocks) and on `llm->user` (the terminal answer). */
    readonly assistantText?: string;
    /** Tool input arguments the LLM produced. Set on `llm->tool` from the
     *  matching `tool.start` event payload. */
    readonly toolArgs?: unknown;
    /** Tool result returned to the LLM. Set on `tool->llm` from the
     *  preceding `tool.end` event payload. */
    readonly toolResult?: unknown;
    /** Stable per-execution key — same `runtimeStageId` Trace view uses. */
    readonly runtimeStageId?: string;
    /**
     * Slot boundary payloads composed for THIS LLM step.
     *
     * Set ONLY for `kind === 'user->llm'` and `kind === 'tool->llm'`
     * StepNodes — the moments where context flows INTO the LLM. Each
     * entry carries the slot subflow's `inputMapper` result (entryPayload)
     * and rendered slot output (exitPayload).
     *
     * Attribution: any slot subflow that fired BETWEEN the previous LLM
     * end (or run start) and THIS LLM start is attributed to this call.
     * Done at projection time over `boundary.getEvents()`; no consumer-
     * side correlation required.
     *
     * Lens uses this to make the 3 slot rows inside the LLM card
     * clickable — clicking a slot reveals its entry/exit payloads in
     * the right-pane detail panel without needing direct BoundaryRecorder
     * access.
     */
    readonly slotBoundaries?: {
        readonly systemPrompt?: SlotBoundary;
        readonly messages?: SlotBoundary;
        readonly tools?: SlotBoundary;
    };
}
/** One slot's boundary pair attributed to a specific LLM step. */
export interface SlotBoundary {
    /** runtimeStageId of the slot subflow execution. */
    readonly runtimeStageId: string;
    /** `inputMapper` payload — the data the slot was COMPOSED FROM
     *  (RAG hits, skill content, user message, tool result, etc). */
    readonly entryPayload?: unknown;
    /** Subflow shared state at exit — the rendered slot content
     *  (system prompt string, messages array, tools array). */
    readonly exitPayload?: unknown;
}
/** Consumer-facing context injection (5 axes of context engineering). */
export interface ContextInjection {
    readonly slot: 'system-prompt' | 'messages' | 'tools';
    readonly asRole?: 'system' | 'user' | 'assistant' | 'tool';
    readonly source: string;
    readonly sourceId?: string;
    readonly contentSummary?: string;
    readonly reason?: string;
    readonly sectionTag?: string;
    readonly upstreamRef?: string;
    readonly retrievalScore?: number;
    readonly rankPosition?: number;
    readonly budgetTokens?: number;
    readonly budgetFraction?: number;
}
export interface StepEdge {
    readonly id: string;
    readonly from: string;
    readonly to: string;
    readonly kind: 'next' | 'loop-iteration' | 'fork-branch' | 'decision-branch';
    readonly iteration?: number;
}
export interface StepGraph {
    readonly nodes: readonly StepNode[];
    readonly edges: readonly StepEdge[];
    readonly activeNodeId?: string;
}
export interface FlowchartOptions {
    /** Called each time the graph changes; fires synchronously on the
     *  driving event so the UI updates the moment the structure changes. */
    readonly onUpdate?: (graph: StepGraph) => void;
}
export interface FlowchartHandle {
    /** Current step graph (derived from boundary events). Safe during or
     *  after a run. */
    readonly getSnapshot: () => StepGraph;
    /** Underlying BoundaryRecorder. Use for richer queries — slot data,
     *  full event log, type-narrowed lookups. The single source of truth
     *  Lens reads. */
    readonly boundary: BoundaryRecorder;
    /** Detach from executor + dispatcher. Subsequent events ignored. */
    readonly unsubscribe: () => void;
}
/**
 * Attach a live FlowchartRecorder to a runner.
 *
 *   1. Creates a `BoundaryRecorder` (the unified domain event log) with
 *      commit tracking, so every boundary records WHERE on the commit
 *      axis it happened.
 *   2. Attaches it to the executor's FlowRecorder channel via
 *      `runnerAttach` — captures run / subflow / fork / decision / loop.
 *   3. Subscribes it to the dispatcher — captures llm.* / tool.* /
 *      context.injected.
 *   4. Wires `onUpdate` so the consumer sees a fresh derived StepGraph
 *      on every event.
 *
 * @param getCommitCount  where each boundary sits on the run's commit
 *   axis — the runner's `getCommitCount()`, sampled live. Optional only
 *   because a caller may have no runner to sample; omitting it stamps
 *   every boundary `commitIdxBefore: 0`, which reads as "all boundaries
 *   opened at once" and leaves an offline step strip with nothing to
 *   place. Nothing downstream can repair it — the commit log records
 *   what stages wrote, never when a boundary was crossed — so the
 *   runner always passes it.
 *
 * @internal Called from `RunnerBase.enable.flowchart`.
 */
export declare function attachFlowchart(runnerAttach: (recorder: CombinedRecorder) => () => void, dispatcher: EventDispatcher, options?: FlowchartOptions, getCommitCount?: () => number): FlowchartHandle;
/**
 * Project a `BoundaryRecorder`'s event stream into a `StepGraph`.
 *
 * Pure function — no side effects, no recorder mutation, deterministic.
 * Called on every snapshot request and on every `onUpdate` fire. O(N)
 * over the event stream; consumer-side memoization (e.g., React's
 * `useMemo`) is straightforward when needed.
 *
 * The mapping is local to each event type: see the mapping table in
 * the file header. State carried across the fold:
 *   - `iter`: 1-based ReAct iteration counter, incremented on each
 *     `llm.start`. ReAct nodes inherit the current value.
 *   - `pendingInjections`: context.injected events buffered between
 *     LLM calls; flushed onto the next user→llm or tool→llm StepNode.
 *   - `prevReActId`: id of the previous ReAct StepNode for `next`-edge
 *     wiring within an iteration.
 *   - `runStartTs`: wall-clock at run start, for relative offsets.
 */
export declare function buildStepGraph(boundary: BoundaryRecorder): StepGraph;
/**
 * Pure events → StepGraph fold. Same projection as `buildStepGraph`, but from a
 * flat `DomainEvent[]` rather than a live `BoundaryRecorder` — so an offline
 * `Trace` (which stores only events) can be rebuilt into a graph for `<Replay>`
 * without re-running the agent. The graph is always derived, never stored.
 */
export declare function buildStepGraphFromEvents(events: readonly DomainEvent[]): StepGraph;
