/**
 * agent_bridge — warm-pool session manager (WAB.3, 0.5.95).
 *
 * Authoritative spec: `docs/tasks/T-warm-agent-chat-bridge.md` WAB.3.
 * Architecture: `docs/tasks/WAB.1-architecture.md` decisions (b) + (c) +
 * Section 2 module layout (≤350 LOC budget for this file).
 *
 * Responsibility:
 *   1. Maintain an LRU of `SessionState` objects keyed by canonical session
 *      slug — Hermes-derived caps (`max=128`, `ttl=3_600_000ms`, verified
 *      against `gateway/run.py:55-65`).
 *   2. Lazy-construct a `SessionState` on first `getOrCreate`, hydrating
 *      `history` from persisted JSONL (WAB.3 `SessionPersistence`).
 *   3. On eviction (LRU cap hit, idle TTL expire, or shutdown), notify the
 *      caller via the optional `onEvict` callback so any unfinished work
 *      (e.g. a final flush) can be performed before the entry vanishes.
 *      The state's `history` is already on disk — eviction is a memory
 *      release, not a data loss.
 *   4. `appendTurn` is the only mutation API — it APPEND-WRITES the new
 *      entries to disk FIRST, then mutates the in-memory `history`, so a
 *      persistence failure leaves the in-memory state cleanly unchanged
 *      (the caller's catch can decide to retry or escalate).
 *
 * Non-responsibility (per WAB.1 (c)):
 *   - Does NOT store an Anthropic SDK client per session. One daemon-wide
 *     client is shared.
 *   - Does NOT compute cache-control breakpoints. Those are derived from
 *     `history` positions at request-time by the agent loop (WAB.4).
 *   - Does NOT serialize concurrent appends to the same session. This is
 *     intentional: the manager is the unsynchronized data plane; the
 *     control plane (`ChatDispatcher` in `dispatcher.ts`) owns the
 *     per-session mutex+queue policy and is the sole production caller of
 *     `appendTurn` (regression-locked by `appendturn_sole_caller.test.ts`).
 *     See the `Concurrency contract:` paragraph on `appendTurn` below for
 *     the policy details.
 *
 * Imports from: lru-cache, ./session_persistence.js, ./types.js.
 * Imported by: (future) dispatcher.ts, daemon.ts.
 */
import { type SessionPersistence } from './session_persistence.js';
import { type ChatHistoryEntry, type SessionKey, type SessionState } from './types.js';
/** Max warm sessions in memory. Hermes `_AGENT_CACHE_MAX_SIZE`. */
export declare const AGENT_CACHE_MAX_SIZE = 128;
/** Idle TTL after which an untouched session is evicted. Hermes
 *  `_AGENT_CACHE_IDLE_TTL_SECS = 3600.0` → 3_600_000 ms. */
export declare const AGENT_CACHE_IDLE_TTL_MS = 3600000;
export type EvictionReason = 'lru' | 'idle' | 'shutdown';
export interface SessionManagerOptions {
    persistence: SessionPersistence;
    /** Fallback pack id stamped onto newly-created `SessionState`s when the
     *  caller does not override it. WAB.6 will replace this with a per-call
     *  override (different sessions can run different packs). */
    defaultPackId: string;
    /** Fallback resolved model id stamped onto newly-created states. */
    defaultModelAlias: string;
    /** Override cache cap (tests). Defaults to `AGENT_CACHE_MAX_SIZE`. */
    maxSessions?: number;
    /** Override idle TTL ms (tests). Defaults to `AGENT_CACHE_IDLE_TTL_MS`. */
    idleTtlMs?: number;
    /** Injected clock (tests). Defaults to `Date.now`. */
    nowMs?: () => number;
    /**
     * Fired when a session leaves the cache. Synchronous-return; the
     * implementation may kick an async flush — the SessionManager does not
     * await it (lru-cache's dispose is sync). Callers that need a barrier
     * should track outstanding flushes themselves.
     *
     * For 'lru' / 'idle' reasons: invoked from the LRU dispose hook.
     * For 'shutdown' reason: invoked from `shutdown()` for each remaining
     * entry before the cache is cleared.
     */
    onEvict?: (state: SessionState, reason: EvictionReason) => void;
}
export declare class SessionManager {
    private readonly cache;
    private readonly persistence;
    private readonly defaultPackId;
    private readonly defaultModelAlias;
    private readonly nowMs;
    private readonly onEvict;
    private shutdownInProgress;
    constructor(opts: SessionManagerOptions);
    /**
     * Look up an existing warm session, or create one (hydrating its
     * `history` from persisted JSONL). Cache-hit path is a single LRU
     * lookup + sync return inside an awaited promise — no extra I/O.
     *
     * `projectUuid` is required (sessions are project-scoped); pack id +
     * model alias use the manager-level defaults at creation time. WAB.6
     * will add per-call overrides.
     */
    getOrCreate(key: SessionKey, projectUuid: string): Promise<SessionState>;
    /**
     * Append entries from a completed turn. Persistence happens BEFORE
     * in-memory mutation so a write failure leaves the state untouched
     * (the caller can catch and decide).
     *
     * If the session was evicted between turn-start and turn-completion
     * (race against LRU cap or idle TTL), the method is a no-op — there is
     * no warm state to update, and re-creating it just to attach orphan
     * entries would corrupt the order on disk (the evicted state's flush
     * already covers it).
     *
     * Concurrency contract: this method ASSUMES the caller has serialized
     * concurrent calls for the same session. The control plane —
     * `ChatDispatcher.handleFlush` + `runTurnChain` in `dispatcher.ts` —
     * enforces this via a per-session `inFlight` map (depth 1) plus a
     * `pendingQueue` map (depth 1, coalesce up to MAX_QUEUE_COALESCE_ATTEMPTS,
     * then DROP + warn). Adding a SECOND production caller would violate
     * the contract; the `appendturn_sole_caller.test.ts` regression net
     * catches that drift.
     */
    appendTurn(key: SessionKey, entries: ChatHistoryEntry[]): Promise<void>;
    /**
     * Mark a session's turn as in-flight. Pure in-memory; intended for the
     * batch coordinator (WAB.5) to set BEFORE issuing the agent turn so
     * other inbound batches buffer.
     */
    beginTurn(key: SessionKey): void;
    /** Test/admin: returns the live entry without resetting age. */
    peek(key: SessionKey): SessionState | undefined;
    /** Live entry count — for telemetry + tests. */
    get size(): number;
    /**
     * Drain the cache: emit `onEvict(state, 'shutdown')` for each live
     * session, then clear. Idempotent. After shutdown, the manager is
     * single-use — re-using it would silently start a fresh cache; we
     * surface that as a recoverable no-op rather than throw (matches
     * `InboxTransportBridge.shutdown` semantics).
     */
    shutdown(): void;
}
//# sourceMappingURL=session_manager.d.ts.map