import type { Message } from "@kenkaiiii/gg-ai";
/**
 * Loop-breaker hook — the mid-loop counterpart to the ideal review.
 *
 * Where the ideal review fires when the agent is about to STOP, the
 * loop-breaker fires only on high-confidence evidence that the agent is
 * STUCK: a failure streak, the same call returning the same result repeatedly,
 * or degenerate repeated output.
 *
 * Successful edits to one file are progress, not a loop. Repeated calls are
 * counted only while consecutive and only when their result is unchanged;
 * expected polling/wait calls are excluded. This avoids interrupting healthy
 * long-running commands and iterative edits.
 */
export interface LoopBreakStats {
    /** Failed tool calls in an unbroken streak (reset by any success). */
    consecutiveFailures: number;
    /** Consecutive identical non-polling calls whose result did not change. */
    repeatedNoProgressCalls: number;
    /** Whether streamed assistant text degenerated into repetition. */
    textRepetitionDetected: boolean;
    /** Detected cyclic tool-call pattern (A/B/A/B…) with no new results. */
    cyclicPattern?: CycleDetection;
}
export interface LoopBreakDecision {
    shouldBreak: boolean;
    reasons: string[];
}
export declare const LOOP_BREAK_PROMPT: string;
/**
 * Second-stage break — injected when the agent is STILL looping after the
 * first LOOP_BREAK_PROMPT nudge. No more retries: report and hand back.
 */
export declare const LOOP_BREAK_FINAL_PROMPT: string;
/** Stable signature for a tool call: name + canonicalized args. */
export declare function toolCallSignature(name: string, args: unknown): string;
/**
 * Tracks only a currently repeating, unchanged tool outcome. Different calls,
 * changed output, and explicit polling/wait tools all prove enough movement to
 * reset the streak. One instance is used per agent run.
 */
export declare class ToolCallProgressTracker {
    private lastSignature;
    private lastResult;
    private lastWasError;
    private repeatCount;
    record(name: string, args: unknown, result: string, isError: boolean): number;
    reset(): void;
    private resetRepetition;
}
export interface CycleDetection {
    /** Cycle length k (1–5): the repeating unit is the last k distinct calls. */
    length: number;
    /** How many full consecutive repetitions of the unit were observed. */
    repeats: number;
}
/**
 * Detects the agent alternating through a short cycle of tool calls
 * (A/B/A/B… up to length 5) that produce no new results — the multi-call
 * generalization of ToolCallProgressTracker's single-call repeat streak
 * (Gemini CLI's cycle detector, hardened with an unchanged-result guard: a
 * call whose result changed between visits is progress, not a loop).
 *
 * One instance per agent run; `reset()` after a loop-break injection so the
 * second stage measures fresh evidence.
 */
export declare class CycleDetector {
    /** Bounded FIFO of recent call signatures (most recent last). */
    private history;
    /** Whether each historical call's result was unchanged from that
     *  signature's previous occurrence. Parallel to `history`. */
    private unchanged;
    /** Last observed result per signature. */
    private lastResults;
    record(name: string, args: unknown, result: string, _isError: boolean): CycleDetection | null;
    reset(): void;
    /** True when the last k*THRESHOLD calls repeat the same k-cycle and every
     *  one of them returned the same result as its previous occurrence. */
    private matchesCycle;
}
/**
 * Detects verbatim repetition at the tail of streamed text — the model
 * looping on a phrase/block. Scans candidate block lengths and checks how
 * many times the trailing block repeats consecutively. Cheap: bounded to a
 * fixed tail window.
 */
export declare function detectTextRepetition(text: string): boolean;
export declare function evaluateLoopBreak(stats: LoopBreakStats): LoopBreakDecision;
export declare function buildLoopBreakMessage(reasons: readonly string[], final?: boolean): Message;
//# sourceMappingURL=loop-breaker.d.ts.map