/** * RepetitionDetector — catches text-degeneration loops during streaming. * * Weaker models sometimes get stuck (typically after an unrecoverable tool * error) and stream the same sentence/paragraph forever until the output-token * cap — burning tokens and hanging the UI. The tool-loop detector in the agent * handles repeated *tool calls*; this is its sibling for repeated *text*. * * Strategy: over the recent tail of accumulated output, look for any word * n-gram that recurs an excessive number of times. This catches both a single * repeated sentence and a repeated multi-sentence block (the n-gram spans the * cycle). Cheap (bounded tail + throttled checks) and conservative — a 10-word * exact sequence recurring 5× is virtually never legitimate output. */ export interface RepetitionDetectorOptions { /** Window size in words for the repeated-unit probe. */ ngramWords?: number; /** Trip when any n-gram occurs at least this many times. */ maxRepeats?: number; /** Don't check until at least this many chars have accumulated. */ minChars?: number; /** Only examine the last N chars (bounds cost; loops live in the tail). */ tailChars?: number; /** Re-check only after this many new chars (throttle). */ checkEveryChars?: number; } export declare class RepetitionDetector { private text; private lastCheckedLen; private readonly ngramWords; private readonly maxRepeats; private readonly minChars; private readonly tailChars; private readonly checkEveryChars; constructor(opts?: RepetitionDetectorOptions); /** * Feed a streamed text chunk. Returns true the first time a degeneration * loop is detected (the caller should then stop the stream). */ feed(chunk: string): boolean; private check; }