/**
 * Loop — iteration composition: runs a body runner repeatedly until exit.
 *
 * Pattern: Builder (GoF) + Adapter over footprintjs's `loopTo` + `$break`.
 * Role:    core-flow/ layer. Enables Reflection, Self-Refine, Debate,
 *          Reflexion, Constitutional AI, and any pattern needing
 *          iterative refinement of a composition output.
 * Emits:   agentfootprint.composition.enter / exit +
 *          composition.iteration_start / iteration_exit
 *          (via compositionRecorder).
 *
 * Budget guard is MANDATORY. You must set at least one of:
 *   - maxIterations (default 10 if only .body() is set)
 *   - maxWallclockMs
 * Hard ceiling of 500 iterations prevents runaway loops even if a guard
 * misfires; exceeding it throws.
 */
import { type FlowchartCheckpoint, type StructureRecorder } from 'footprintjs';
import type { RunOptions } from '../core/runner.js';
import type { GroupMetadata, GroupTranslator } from '../core/translator.js';
import type { RunnerPauseOutcome } from '../core/pause.js';
import type { Runner } from '../core/runner.js';
import { RunnerBase } from '../core/RunnerBase.js';
import type { MemoryIdentity } from '../memory/identity/types.js';
export interface LoopOptions {
    readonly name?: string;
    readonly id?: string;
    /**
     * Optional build-time recorders passed through to footprintjs's
     * `flowChart()` factory. Each recorder observes per-node build
     * events (`onStageAdded` / `onSubflowMounted` / etc.) for this
     * composition's internal chart (Seed + IterationStart + body mount +
     * Guard). When omitted, no build-time observation is wired up.
     */
    readonly structureRecorders?: readonly StructureRecorder[];
    /**
     * Optional per-COMPOSITION translator (UI-agnostic). See
     * `core/translator.ts`. When attached, `runner.getUIGroup()` invokes
     * it with the Loop's `GroupMetadata` (kind `'Loop'`, id, name, body
     * as the single member, plus iteration budgets in `extra`).
     * Returns `undefined` when omitted.
     */
    readonly groupTranslator?: GroupTranslator;
}
export interface LoopInput {
    readonly message: string;
    /**
     * WHO this run is for — the same tuple as `AgentInput.identity`. Every
     * member runs for it: its memory, its tools' `ctx.identity`. Omitted, every
     * member runs under this run's own conversation (`{ conversationId: runId }`),
     * never a namespace another run shares (`core/memberRun.ts`).
     */
    readonly identity?: MemoryIdentity;
}
export type LoopOutput = string;
type BodyChild = Runner<{
    message: string;
}, string>;
/**
 * Predicate evaluated AFTER each body iteration. Return true to exit the loop.
 *
 * `latestOutput` is the body's STRING output — by design (B15): the whole
 * core-flow layer composes `Runner<{ message: string }, string>`, and the
 * Loop chart's outputMapper coerces any non-string body output to `''`.
 * For structured exit conditions today, have the body emit JSON (e.g. an
 * Agent with `.outputSchema(...)`) and parse inside the guard:
 *
 * ```ts
 * .until(({ latestOutput }) => {
 *   try { return (JSON.parse(latestOutput) as { done: boolean }).done; }
 *   catch { return false; } // not JSON (yet) — keep looping
 * })
 * ```
 *
 * A typed guard (`Loop<T>` with a structured body output) would require
 * genericizing the Runner output contract shared by Sequence / Parallel /
 * Conditional — tracked as a future enhancement, not in core today.
 */
export type UntilGuard = (ctx: {
    readonly iteration: number;
    readonly latestOutput: string;
    readonly startMs: number;
}) => boolean;
export declare class Loop extends RunnerBase<LoopInput, LoopOutput> {
    readonly name: string;
    readonly id: string;
    private readonly body;
    private readonly maxIterations;
    private readonly maxWallclockMs;
    private readonly until;
    private readonly opts;
    /** Per-method translator override on `.repeat()`, when set. Applies
     *  to the body member's `uiGroup`. */
    private readonly bodyTranslator;
    private currentRunContext;
    constructor(opts: LoopOptions, body: BodyChild, config: {
        maxIterations: number;
        maxWallclockMs?: number;
        until?: UntilGuard;
        bodyTranslator?: GroupTranslator;
    });
    static create(opts?: LoopOptions): LoopBuilder;
    protected getGroupTranslator(): GroupTranslator | undefined;
    /** Loop has a single body member + iteration budgets in `extra`.
     *  Per-method override (L1c) takes precedence over the body
     *  runner's own translator. */
    protected buildUIGroupMetadata(): GroupMetadata;
    run(input: LoopInput | string, options?: RunOptions): Promise<LoopOutput | RunnerPauseOutcome>;
    resume(checkpoint: FlowchartCheckpoint, input?: unknown, options?: RunOptions): Promise<LoopOutput | RunnerPauseOutcome>;
    private createExecutor;
    private finalizeResult;
    private buildChart;
}
/**
 * Fluent builder. Reads as natural English:
 *   Loop.create().repeat(runner).times(10).forAtMost(30_000).until(fn).build()
 *   →  "Loop: repeat runner, up to 10 times, for at most 30 seconds, until fn."
 *
 * Enforces a body runner is supplied before .build(). Default budget is
 * 10 iterations (hard ceiling 500). Any of .times / .forAtMost / .until
 * can fire to exit the loop.
 */
/**
 * Options bag accepted by `LoopBuilder.repeat()` for per-method overrides.
 */
export interface LoopRepeatOptions {
    /** Per-method translator override for the body runner — overrides
     *  the runner's own constructor-level translator for THIS loop only. */
    readonly groupTranslator?: GroupTranslator;
}
export declare class LoopBuilder {
    private readonly opts;
    private _body;
    private _bodyTranslator;
    private _maxIterations;
    private _maxWallclockMs;
    private _until;
    constructor(opts: LoopOptions);
    /**
     * The runner that executes each iteration. Required.
     * Each iteration's output string becomes the next iteration's input `{ message }`.
     *
     * Optional second arg `opts.groupTranslator` overrides the body
     * runner's own translator for THIS loop only — only its
     * `member.uiGroup` flips to the override's output.
     */
    repeat(runner: BodyChild, opts?: LoopRepeatOptions): this;
    /**
     * Maximum iteration count. Default 10 if only `.repeat()` is called.
     * Hard ceiling 500 — larger values are clamped.
     */
    times(n: number): this;
    /**
     * Wall-clock time budget in milliseconds. The loop exits at the next
     * guard check after this elapses.
     */
    forAtMost(ms: number): this;
    /**
     * Exit predicate evaluated after each iteration. Return `true` to exit.
     * Receives `{ iteration, latestOutput, startMs }`.
     *
     * `latestOutput` is the body's string output. For structured exit
     * conditions, emit JSON from the body and parse it inside the guard —
     * see the `UntilGuard` JSDoc for the pattern and the design rationale.
     */
    until(guard: UntilGuard): this;
    build(): Loop;
}
export {};
