import { RecallPlanMode, IdentityInjectionMode, RecallTierExplain } from './types.js';

interface LastRecallBudgetSummary {
    requestedTopK?: number;
    appliedTopK: number;
    recallBudgetChars: number;
    maxMemoryTokens: number;
    qmdFetchLimit?: number;
    qmdHybridFetchLimit?: number;
    finalContextChars?: number;
    truncated?: boolean;
    includedSections?: string[];
    omittedSections?: string[];
}
interface LastRecallSnapshot {
    sessionKey: string;
    recordedAt: string;
    queryHash: string;
    queryLen: number;
    memoryIds: string[];
    namespace?: string;
    traceId?: string;
    plannerMode?: RecallPlanMode;
    requestedMode?: RecallPlanMode;
    source?: string;
    fallbackUsed?: boolean;
    sourcesUsed?: string[];
    budgetsApplied?: LastRecallBudgetSummary;
    latencyMs?: number;
    resultPaths?: string[];
    policyVersion?: string;
    identityInjectionMode?: IdentityInjectionMode | "none";
    identityInjectedChars?: number;
    identityInjectionTruncated?: boolean;
    /**
     * Collision-safe write nonce.  Random UUID set on every `record()`
     * call so the observation-mode direct-answer hook can detect stale
     * snapshots and avoid annotating a snapshot that a subsequent recall
     * already replaced (issue #518).
     */
    writeNonce?: string;
    /**
     * Optional tier-level explanation of how recall was served
     * (issue #518).  Populated by orchestrator call sites that can
     * identify a concrete tier; surfaces expose the block via
     * `engram query --explain`, the `?explain=1` HTTP flag, and the
     * `remnic_recall_explain` MCP tool.  Orthogonal to the existing
     * graph-path `recallExplain` operation.
     */
    tierExplain?: RecallTierExplain;
}
interface GraphRecallExpandedEntry {
    path: string;
    score: number;
    namespace: string;
    seed: string;
    hopDepth: number;
    decayedWeight: number;
    graphType: "entity" | "time" | "causal";
    /**
     * Issue #681 PR 3/3 — confidence of the edge that produced this entry's
     * recorded provenance (strongest edge along the chosen entry path).
     * Range `[0, 1]`. Optional so persisted snapshots from older builds
     * round-trip through `clampGraphRecallExpandedEntries` without dropping.
     */
    edgeConfidence?: number;
}
declare function clampGraphRecallExpandedEntries(entries: unknown, maxEntries?: number): GraphRecallExpandedEntry[];
interface TierMigrationCycleSummary {
    trigger: "extraction" | "maintenance" | "manual";
    scanned: number;
    migrated: number;
    promoted: number;
    demoted: number;
    limit: number;
    dryRun: boolean;
    skipped?: string;
    errorCount?: number;
}
interface TierMigrationStatusSnapshot {
    updatedAt: string;
    lastCycle: TierMigrationCycleSummary | null;
    totals: {
        cycles: number;
        scanned: number;
        migrated: number;
        promoted: number;
        demoted: number;
        errors: number;
    };
}
declare class LastRecallStore {
    private readonly statePath;
    private readonly impressionsPath;
    private state;
    constructor(memoryDir: string);
    load(): Promise<void>;
    get(sessionKey: string): LastRecallSnapshot | null;
    getMostRecent(): LastRecallSnapshot | null;
    /**
     * Persist last-recall snapshot and append an impression log entry.
     * Does not store raw query text; uses a stable hash for correlation.
     */
    record(opts: {
        sessionKey: string;
        query: string;
        memoryIds: string[];
        namespace?: string;
        traceId?: string;
        plannerMode?: RecallPlanMode;
        requestedMode?: RecallPlanMode;
        source?: string;
        fallbackUsed?: boolean;
        sourcesUsed?: string[];
        budgetsApplied?: LastRecallBudgetSummary;
        latencyMs?: number;
        resultPaths?: string[];
        policyVersion?: string;
        appendImpression?: boolean;
        identityInjection?: {
            mode: IdentityInjectionMode | "none";
            injectedChars: number;
            truncated: boolean;
        };
        /**
         * Per-tier explain annotation (issue #518).  When supplied, the
         * snapshot carries it so downstream surfaces (CLI / HTTP / MCP)
         * can render which retrieval tier served the query.
         */
        tierExplain?: RecallTierExplain;
    }): Promise<void>;
    /**
     * Attach a RecallTierExplain block to the existing snapshot for a
     * session without rewriting the entire snapshot.  Used by the
     * post-recall direct-answer annotation path (issue #518 slice 3c):
     * recallInternal records the snapshot first, then the orchestrator
     * fires the direct-answer tier in observation mode and annotates
     * the stored snapshot with whichever tier served the query.
     *
     * No-op when no snapshot exists for the given session; callers do
     * not need to guard on existence.
     */
    annotateTierExplain(sessionKey: string, tierExplain: RecallTierExplain, expected?: {
        writeNonce?: string;
        traceId?: string;
        recordedAt?: string;
    }): Promise<void>;
}
declare class TierMigrationStatusStore {
    private readonly statePath;
    private state;
    constructor(memoryDir: string);
    load(): Promise<void>;
    get(): TierMigrationStatusSnapshot;
    recordCycle(summary: TierMigrationCycleSummary): Promise<void>;
}

export { type GraphRecallExpandedEntry, type LastRecallBudgetSummary, type LastRecallSnapshot, LastRecallStore, type TierMigrationCycleSummary, type TierMigrationStatusSnapshot, TierMigrationStatusStore, clampGraphRecallExpandedEntries };
