/**
 * agent_timeout_policy_v1 (0.13.57) — two-axis subagent watchdog.
 *
 * Background: 0.13.55 soft loop intercept handles conversation-level
 * repeated tool failure but does not catch lower-level wedges
 * (subprocess hang, Promise that never resolves, infinite generator).
 * Pre-0.13.57 the only outer safety on the Agent tool was the
 * post-abort grace period (TOOL_ABORT_HARD_DEADLINE_MS = 3s) — there
 * was no wall-clock deadline at all, so a quiet subagent could
 * theoretically run forever.
 *
 * 0.13.57 introduces a two-axis policy:
 *
 *   1. Idle timeout (`OWLCODA_AGENT_IDLE_TIMEOUT_MS`, default 5 min)
 *      — abort if no real progress signal arrives for this long. The
 *      reset signals are not "stdout/text from the model" alone (that
 *      would punish quiet but productive subagents that grind on tool
 *      use without narrating); they include any of: assistant text,
 *      tool_use start, tool_result end, tool progress chunk, runtime
 *      notice. So a subagent doing back-to-back read/grep on a 4000-
 *      line file keeps the watchdog awake even if the model never
 *      streams a token.
 *
 *   2. Max runtime (`OWLCODA_AGENT_MAX_RUNTIME_MS`, default 30 min)
 *      — absolute ceiling; fires regardless of progress. This is the
 *      true deadlock catcher.
 *
 * Both knobs accept `0` to disable. Default for both is on; the
 * recommended posture is "keep idle on; keep max on; only override
 * for genuinely long-running batch jobs".
 *
 * Industry reference (per 2026-05-06 survey):
 *   - Aider / Continue: per-request timeout, no idle vs max split
 *   - Codex CLI: `max_runtime_seconds` per subagent (1800s default)
 *   - Claude Code, Cursor: no built-in deadline; user-Esc only
 *   - OpenHands: Stuck Detector (semantic loop, not wall-clock)
 *
 * 0.13.57 picks idle+max with progress-signal heartbeat — closer to
 * OpenHands' philosophy ("watch productive progress, not silence")
 * but still gives operators wall-clock guardrails.
 */
/** Progress event types that reset the idle clock. */
export type AgentProgressType = 'agent_start' | 'assistant_text' | 'tool_start' | 'tool_end' | 'tool_progress' | 'notice';
export interface AgentProgressMark {
    type: AgentProgressType;
    at: number;
    detail?: string;
}
/** What the watchdog observed at the moment it fired. */
export interface AgentTimeoutFiring {
    kind: 'idle' | 'max';
    at: number;
    startTime: number;
    lastProgress: AgentProgressMark;
    idleTimeoutMs: number;
    maxRuntimeMs: number;
}
/**
 * Read an env-var-or-undefined as ms count with a default. Rules:
 *  - empty / unset / not-a-number → defaultMs
 *  - non-finite or negative → defaultMs (fail safe to default)
 *  - 0 (literal) → returned as 0 (caller treats as "disabled")
 *  - positive number → returned as integer ms
 */
export declare function parseAgentTimeoutMs(raw: string | undefined, defaultMs: number): number;
/** Resolve the active idle/max policy from env, with defaults. */
export declare function resolveAgentTimeoutPolicy(env?: NodeJS.ProcessEnv): {
    idleTimeoutMs: number;
    maxRuntimeMs: number;
};
export interface AgentWatchdogHandle {
    /** AbortSignal that fires when either timeout trips. Caller threads
     *  this into runConversationLoop so the LLM fetch and downstream
     *  tools cancel cooperatively. */
    signal: AbortSignal;
    /** Record a progress event. Idempotent in spirit; any call resets
     *  the idle clock. */
    recordProgress: (type: AgentProgressType, detail?: string) => void;
    /** Surface the firing event (null if the watchdog never tripped). */
    getFiring: () => AgentTimeoutFiring | null;
    /** Last recorded progress mark. */
    getLastProgress: () => AgentProgressMark;
    /** Stop the interval and detach external listeners. Idempotent. */
    dispose: () => void;
}
export interface AgentWatchdogOptions {
    idleTimeoutMs: number;
    maxRuntimeMs: number;
    /** Caller's external abort source (e.g. user Esc). When this fires,
     *  the watchdog also aborts. Optional. */
    externalSignal?: AbortSignal;
    /** Caller-supplied tick interval; default 500ms. Tests can pass a
     *  smaller value to make assertions cheap. */
    tickMs?: number;
    /** Time source override for tests. Defaults to Date.now. */
    now?: () => number;
    /** setInterval / clearInterval injection points for tests. */
    setIntervalImpl?: (cb: () => void, ms: number) => unknown;
    clearIntervalImpl?: (handle: unknown) => void;
}
/**
 * Build the watchdog. Caller is expected to:
 *   1. Wrap their conversation callbacks so each callback type
 *      fires `recordProgress(<type>, <detail>)` once.
 *   2. Pass `signal` into runConversationLoop's `opts.signal`.
 *   3. After the run, check `getFiring()` to format an actionable
 *      timeout message, otherwise fall through to normal completion.
 *   4. Always call `dispose()` in a `finally` block.
 */
export declare function createAgentWatchdog(opts: AgentWatchdogOptions): AgentWatchdogHandle;
/**
 * Build the operator-facing abort message when the watchdog fired.
 * Always includes the last-progress evidence so "my agent died at 5
 * minutes" can be diagnosed without re-running.
 */
export declare function formatAgentTimeoutMessage(firing: AgentTimeoutFiring): string;
