import type { ToolCallReport } from './agent-loop-types.js'; /** * Deterministic JSON.stringify with sorted object keys at every level. * Used by the stuck-loop detector to derive a stable identity key for * tool-call arguments: identical calls hash to identical strings * regardless of key insertion order. Tolerates circular references and * non-JSON-able values by collapsing them to a placeholder. */ export declare function stableStringify(value: unknown, seen?: WeakSet): string; /** * Stable error-type fingerprint of a dispatcher's result text. Returns * the first non-empty line trimmed and truncated to 80 chars when * isError; empty string otherwise. Used by the stuck-loop detector so * "fs_read failed with ENOENT three times" → stuck, but "fs_read * returned different bytes three times" → not stuck. */ export declare function extractErrorType(isError: boolean, text: string): string; /** True iff the last 3 entries are the same tool called with identical * args resulting in the identical outcome — the stuck-loop signal. */ export declare function isStuckLoop(reports: Array>): boolean; /** * v1.2.122 — semantic stuck-loop: 3× DIFFERENT tool names but the same * salient argument value (query / URL / path / command substring). * * Catches the failure mode `isStuckLoop` misses by design: * 1. native_web_search(query="aapl Q3 earnings call transcript") * → "0 results from duckduckgo" * 2. mcp__tavily(query="aapl Q3 earnings call transcript") * → "0 results" * 3. native_exec(command="curl … aapl Q3 earnings call transcript …") * → "404" * * Same intent, three different tool surfaces, all failing. The strict * `isStuckLoop` doesn't fire because tool NAMES differ. Without this * check the model keeps reshuffling tool roulette until max_iter. * * Heuristic: extract every string ≥ 8 chars from each call's argsKey * (a stable JSON of the call.arguments). If the SAME string appears in * all three recent calls AND all three tool names differ → return true. * * The ≥ 8 char floor filters out short enum-like values ("json", * "stop", "auto") that would false-positive across unrelated calls. */ export declare function isSemanticStuckLoop(reports: Array>): boolean; /** Pull every string at least 8 characters long out of a stable-JSON arg blob. * Doesn't try to be clever about which JSON path the string came * from — three calls passing the same long string anywhere in their * args is already strong evidence of repeated intent. */ export declare function extractSalientStrings(argsKey: string): Set; /** v1.2.122 — kill switch for the semantic stuck-loop check. Default ON; * flip 'off' if false positives become a real problem (none observed * in dogfood). */ export declare function resolveSemanticStuckLoopOn(): boolean; //# sourceMappingURL=agent-loop-stuck.d.ts.map