import type { AgentToolResult } from "@apholdings/jensen-agent-core"; /** * Provider-independent Tool Storm Breaker. * * Detects repeated / alternating / no-progress tool calls and escalates through * bounded, user-visible stages. Progress is determined ONLY from structured * events (authoritative state change), never from model prose. */ export declare const TOOL_CALL_DUPLICATE_NO_PROGRESS = "TOOL_CALL_DUPLICATE_NO_PROGRESS"; export declare const TOOL_CALL_STORM_BLOCKED = "TOOL_CALL_STORM_BLOCKED"; export declare const TOOL_STRATEGY_PIVOT_REQUIRED = "TOOL_STRATEGY_PIVOT_REQUIRED"; export type StormStage = "fresh" | "duplicate_annotate" | "no_progress_reflect" | "storm_blocked" | "strategy_pivot_required"; export interface StormThresholds { /** Duplicate count at which we start annotating. */ annotate: number; /** Duplicate count at which we require structured reflection. */ reflect: number; /** Duplicate count at which we block the repeated call. */ block: number; /** Duplicate count at which we fail the current strategy. */ terminal: number; /** Max storm history entries retained. */ maxHistory: number; } export declare const DEFAULT_STORM_THRESHOLDS: StormThresholds; /** Structured event describing authoritative progress/state change. */ export type StormProgressSignal = { kind: "new_evidence"; evidenceHash: string; } | { kind: "file_content_hash"; path: string; hash: string; } | { kind: "diagnostics_hash"; hash: string; } | { kind: "process_state"; identity: string; state: string; } | { kind: "provider_result"; resultHash: string; } | { kind: "transaction_state"; transactionId: string; state: string; } | { kind: "user_input"; inputHash: string; } | { kind: "retry_window_elapsed"; elapsedMs: number; }; export interface StormContext { workspaceScope?: string; runScope?: string; /** Authoritative current state against which to detect progress. */ progressSignals: StormProgressSignal[]; /** Whether the tool is read-only (required for authoritative cache reuse). */ readOnly: boolean; /** Whether the policy permits reusing a prior result (default true for read-only). */ policyAllowsReuse?: boolean; } export interface StormClassifyInput extends StormContext { toolName: string; canonicalArgsHash: string; /** Optional cached prior result for reuse. */ priorResult?: { result: AgentToolResult; validityFingerprint: string; at: number; }; /** Current prior result validity fingerprint (authoritative state identity). */ currentValidityFingerprint?: string; } export type StormDecision = { stage: "fresh"; execute: true; } | { stage: "duplicate_annotate"; execute: true; reason: string; cachedResult?: AgentToolResult; duplicateCount: number; } | { stage: "no_progress_reflect"; execute: true; reason: string; duplicateCount: number; requireReflection: true; } | { stage: "storm_blocked"; execute: false; errorCode: "TOOL_CALL_STORM_BLOCKED"; reason: string; duplicateCount: number; } | { stage: "strategy_pivot_required"; execute: false; errorCode: "TOOL_STRATEGY_PIVOT_REQUIRED"; reason: string; duplicateCount: number; }; /** * Durable storm-breaker state for one run/workspace. One instance per active * agent strategy; reset at user turn boundaries. Reads only structured signals * for progress. */ export declare class StormBreaker { private now; private history; private thresholds; constructor(thresholds?: Partial, now?: () => number); /** Combine structured progress signals into an authoritative state hash. */ private stateHash; /** * Classify a call. Returns whether to execute and with what annotation. * Progress detection: if the authoritative state hash differs from the last * recorded state for this fingerprint, the call is treated as FRESH (context * changed → not a duplicate). */ classify(input: StormClassifyInput): StormDecision; /** Record a cached authoritative result for later read-only reuse. */ recordResult(input: { toolName: string; canonicalArgsHash: string; workspaceScope?: string; runScope?: string; result: AgentToolResult; validityFingerprint: string; }): void; /** Register an authoritative progress signal so subsequent calls are fresh. */ noteProgress(signals: StormProgressSignal[]): void; /** Reset per-turn state (fresh user turn). */ reset(): void; snapshot(): { historySize: number; counts: Record; }; private evictOldest; } //# sourceMappingURL=breaker.d.ts.map