import type { IntegrationErrorCode, Judge } from "pi-typesafe"; import type { StuckGuardConfig } from "./config.js"; /** One remembered tool result. `key` identifies the exact call; `call` is the redacted view that may leave the machine. */ export interface Attempt { tool: string; key: string; /** Hash of the normalised output, so identical failures can be told from a changed error. */ outputKey: string; call: string; failed: boolean; /** Tail of the tool output, redacted, where the error usually is. */ output: string; } export interface StuckJudgment { sameStrategy: number; /** 0 identical … 2 meaningfully different. */ approachChange: number; progress: number; model: string; elapsedMs: number; } export interface StuckVerdict { stuck: boolean; source: "repeat" | "typesafe" | "error"; failures: number; reasons: string[]; /** True when the repeat that fired was a successful call printing the same output, not a failure loop. */ successRepeat?: boolean; /** True when the repeat that fired was repeated calls to the same target with changing output. */ churn?: boolean; judgment?: StuckJudgment; error?: string; errorCode?: IntegrationErrorCode; } /** Text content of a tool result, without images. */ export declare function resultText(content: ReadonlyArray<{ type: string; text?: string; }>): string; /** Non-zero exit codes count as failures even when the tool did not flag an error; context-mode reports them in the text. */ export declare function resultFailed(isError: boolean, details: unknown, content?: ReadonlyArray<{ type: string; text?: string; }>): boolean; export declare function makeAttempt(tool: string, input: Record, content: ReadonlyArray<{ type: string; text?: string; }>, failed: boolean): Attempt; /** Rolling memory of tool results for the current user prompt. */ export declare class AttemptWindow { private readonly limit; readonly attempts: Attempt[]; private sinceJudgment; constructor(limit: number); push(attempt: Attempt): void; reset(): void; markJudged(): void; failures(): number; /** How many failed attempts repeat the latest attempt's exact call with the same output. A changed error is progress, not a repeat. */ exactRepeats(): number; /** How many successful attempts repeat the latest attempt's exact call with the same normalised output. A poll that * prints the answer it already printed carries no new information: the model is re-running instead of reading. */ successRepeats(): number; /** How many attempts (regardless of outcome) target the same call key. When this count is high the output changes * each time (otherwise it would be an exact or success repeat), but the model is not making progress — it is * polling or cycling through slight variations of the same command. */ churnCount(): number; /** Latest result failed with enough failures behind it, succeeded but repeats itself, or is churning on the same * target, and the cool-down has passed. */ shouldJudge(config: StuckGuardConfig): boolean; } export declare const stuckQuestions: { same_strategy: import("pi-typesafe").NoulQuestion; approach_change: import("pi-typesafe").ScoreQuestion; progress: import("pi-typesafe").NoulQuestion; }; export declare function buildStuckRequest(attempts: readonly Attempt[], task: string | undefined): { state: { task: string; attempts: { n: number; tool: string; call: string; outcome: string; output: string; }[]; }; questions: { same_strategy: import("pi-typesafe").NoulQuestion; approach_change: import("pi-typesafe").ScoreQuestion; progress: import("pi-typesafe").NoulQuestion; }; }; export interface StuckOptions { config: StuckGuardConfig; judge?: Judge | undefined; timeoutMs: number; signal?: AbortSignal | undefined; } /** Exact repeats are decided in code; otherwise one Jev request judges the sequence. */ export declare function evaluateStuck(window: AttemptWindow, task: string | undefined, options: StuckOptions): Promise; /** Steering text for the agent. Names the pattern and asks for a change of method, not another retry. A successful * repeat is a different disease than a failure loop: the model already has the answer, so it should use it. */ export declare function stuckNudge(verdict: StuckVerdict): string; export declare function formatStuck(verdict: StuckVerdict, template?: string): string;