import { Logger } from '@nestjs/common';
import { type Entry } from '../entry/entry.js';
import type { StorageProvider } from '../storage/storage-provider.js';
import type { TelescopeAiOptions } from './diagnoser.js';
import { DiagnosisCache } from './diagnosis-cache.js';
/**
 * Default grace an alert waits for an in-flight auto-mode diagnosis before
 * dispatching WITHOUT it. Kept short: the alert is the time-critical artifact, so
 * we'd rather page promptly with no AI note than hold the page waiting on a model.
 */
declare const DEFAULT_ALERT_GRACE_MS = 10000;
/** Outcome of a diagnose request: the markdown plus whether it was a cache hit. */
export interface DiagnoseResult {
    markdown: string;
    cached: boolean;
}
/**
 * Central AI-diagnosis coordinator. Owns the diagnoser, the per-family cache, and
 * the auto-mode wiring. Constructed only when the host configures `ai`; the
 * service injects nothing AI-related otherwise, so the feature is zero-cost off.
 *
 * Two entry points:
 *  - {@link diagnose}: on-demand, behind the dashboard endpoint. Cache-first
 *    (unless `force`), and a diagnoser rejection PROPAGATES so the controller can
 *    map it to a safe 5xx.
 *  - {@link onNewFamily}: auto-mode. Called from the alerter's first-seen signal.
 *    Fire-and-forget — it NEVER throws into the flush path; a failure is swallowed
 *    and logged. The in-flight promise is tracked so an alert firing for the same
 *    family can briefly await it ({@link awaitForAlert}) and attach the result.
 */
export declare class DiagnosisCoordinator {
    private readonly storage;
    private readonly logger;
    private readonly diagnoser;
    readonly mode: 'auto' | 'on-demand';
    private readonly cache;
    /** In-flight auto-mode diagnoses keyed by familyHash (so alerts can await). */
    private readonly inFlight;
    private readonly alertGraceMs;
    /** First-seen tracker backing auto-mode (independent of the alerter's). */
    private readonly newFamilyTracker;
    private readonly newFamilyWindowMs;
    private readonly now;
    constructor(options: TelescopeAiOptions, storage: StorageProvider, deps?: {
        cache?: DiagnosisCache;
        logger?: Logger;
        alertGraceMs?: number;
        now?: () => number;
    });
    /**
     * Auto-mode flush hook, wired into the Recorder's `onFlushStored` path (the
     * SAME path the new-exception alert evaluates on). For each just-stored
     * exception, do a cheap first-seen check; on a genuinely NEW family kick off a
     * fire-and-forget diagnosis. Independent of whether a `new-exception` ALERT
     * rule is configured — auto-diagnosis is its own feature. No-op in on-demand
     * mode. NEVER throws into the flush path.
     */
    observeFlush(storedEntries: Entry[]): void;
    /**
     * On-demand diagnosis for an exception entry. Serves from cache unless `force`.
     * A diagnoser rejection propagates to the caller (the endpoint turns it into a
     * safe 502). On success the result is cached by family for the next reader.
     *
     * @throws whatever the diagnoser rejects with (timeout/model error).
     */
    diagnose(entry: Entry, occurrenceCount: number, force?: boolean): Promise<DiagnoseResult>;
    /**
     * Read-only, cache-ONLY lookup for an entry's diagnosis. Returns the cached
     * markdown for the entry's family, or `null` on a miss / when the entry has no
     * family hash. NEVER builds context and NEVER calls the diagnoser — so it costs
     * nothing and can be safely fetched on every detail-page open. This is what
     * makes an auto-mode (or previously on-demand) diagnosis visible immediately:
     * the cache was populated by `observeFlush`/`onNewFamily` (auto) or a prior
     * `diagnose` (on-demand), and this just surfaces it without re-running.
     */
    peekCached(entry: Entry): string | null;
    /**
     * Auto-mode hook: a NEW exception family was just seen. Kick off diagnosis
     * fire-and-forget and cache the result. NEVER throws — this runs inside the
     * flush/alert path. If a diagnosis for this family is already in flight or
     * already cached, do nothing (at most once per family per cache window).
     *
     * Returns the tracked promise (resolving to the markdown, or `null` on
     * failure) so the alert path can await it; callers on the flush path ignore it.
     */
    onNewFamily(entry: Entry, occurrenceCount: number): Promise<string | null>;
    /**
     * Briefly await an in-flight (or cached) diagnosis for `familyHash`, for the
     * alert path to attach it. Returns the markdown if ready within the grace cap,
     * else `null` (the alert dispatches without it). Never throws.
     */
    awaitForAlert(familyHash: string, graceMs?: number): Promise<string | null>;
    /** True when running in `'auto'` mode (the alerter wires the first-seen hook). */
    get isAuto(): boolean;
    /** Run + cache one diagnosis, swallowing every failure. Clears the in-flight slot. */
    private runDiagnosis;
}
export { DEFAULT_ALERT_GRACE_MS };
//# sourceMappingURL=diagnosis-coordinator.d.ts.map