import type { Message } from "@prestyj/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 when the agent is STUCK: repeating the same failing
 * action, hammering the same file, or degenerating into repeated output.
 * The decision is pure arithmetic over signals useAgentLoop already
 * collects, so the trigger itself costs nothing — only the (at most one)
 * injected message costs a round-trip.
 *
 * Two independent detectors per the research:
 *  - tool-call level: signature repeats / same-file edits / failures.
 *  - text level: a streamed block repeating verbatim (high-temp / stuck
 *    token degeneration), which signature hashing alone never catches.
 */
export interface LoopBreakStats {
    /** Failed tool calls in an unbroken streak (reset by any success). */
    consecutiveFailures: number;
    /** Highest repeat count for any single tool-call signature this run. */
    maxSignatureRepeats: number;
    /** Highest number of edits to any single file this run. */
    maxSameFileEdits: number;
    /** Whether streamed assistant text degenerated into repetition. */
    textRepetitionDetected: boolean;
}
export interface LoopBreakDecision {
    shouldBreak: boolean;
    reasons: string[];
}
export declare const LOOP_BREAK_PROMPT: string;
/**
 * Stable signature for a tool call: name + canonicalized args. Key order is
 * normalized so semantically identical calls hash identically.
 */
export declare function toolCallSignature(name: string, args: unknown): string;
/**
 * 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[]): Message;
//# sourceMappingURL=loop-breaker.d.ts.map