import type { AgentEvent } from "@skaile/workspaces/types"; /** Opaque handle for one in-flight compaction. See {@link CompactionGate.begin}. */ export type CompactionHold = symbol; /** * Coordinates the compaction-turn / user-turn race on a single driver. * * Compaction prompts the very driver a user turn would, and the runner * suppresses forwarded events for its duration. A turn dispatched into that * window therefore runs against a driver already mid-turn and has its reply * dropped on the way out — no text, no `finished`, no error, just an indefinite * "AI is thinking…" (skaile-ai/platform#3882). * * The window this gate holds is deliberately wider than the event suppression. * On the success path the orchestrator stops suppressing before it resets the * driver and injects the snapshot, so a turn released at that moment would race * the injection instead of the summary. The gate opens only once the whole * compaction call has settled. * * Mirrors {@link DriverSwapGate}: one instance per agent server, and every * method is safe to call when nothing is in flight. */ export declare class CompactionGate { /** * Every compaction currently holding the driver. * * A set rather than a boolean because holds can overlap: a driver swap * rebuilds the orchestrator, and the new instance carries its own * `_isCompacting`, so it can start a compaction while the previous * instance's call is still unwinding. Keyed by handle so the older one * settling cannot open the gate under the newer one — the same identity * check `DriverSwapGate.beginSwap` makes for swaps. */ private held; /** Resolves when the last hold is released. Null whenever the driver is free. */ private opened; private release; /** * Mark a compaction as occupying the driver. The returned handle is the only * thing that can release it. */ begin(): CompactionHold; /** * Release one hold, opening the gate once none remain. Unknown and null * handles are ignored, so a settle signal that fires without a matching * `begin()` is harmless. * * Call this from a signal the orchestrator emits unconditionally. A `begin()` * whose `settle()` can be skipped holds user turns forever, which is a worse * failure than the discarded reply this gate exists to prevent. */ settle(hold: CompactionHold | null | undefined): void; /** * Wait for the driver to be free. * * Returns `idle` when nothing was in flight, `waited` when every compaction * settled within the bound, and `timeout` when they did not. A caller that * gets `timeout` must surface it rather than dispatch: a compaction still * holding the driver past this bound is stuck, and dispatching into it * reproduces the silent loss. * * Re-checks in a loop, as `DriverSwapGate.awaitSwap` does, so a compaction * armed while this turn was already waiting is also awaited. `timeoutMs` * bounds the whole wait, not each iteration. */ awaitIdle(timeoutMs: number): Promise<"idle" | "waited" | "timeout">; } /** * How long a user turn waits for a compaction before the runner reports it as * stuck. Read per call so a test (or an operator) can set * `SKAILE_COMPACTION_GATE_TIMEOUT_MS` after this module is imported. */ export declare function compactionGateTimeoutMs(): number; /** The message a caller sends when it abandons a turn rather than race a compaction. */ export declare const COMPACTION_GATE_TIMEOUT_MESSAGE = "The session is still compacting its history and could not take this message. Send it again in a moment."; export interface GuardTurnDeps { gate: CompactionGate; /** What is waiting, for the log line: "prompt", "reply". */ what: string; log: (line: string) => void; sendEvent: (event: AgentEvent) => void; /** Defaults to {@link compactionGateTimeoutMs}. */ timeoutMs?: number; } /** * Hold a user turn until the driver is free of any compaction. * * Returns false when the caller must abandon the turn — dispatching anyway is * what skaile-ai/platform#3882 records. The error event is the first * user-visible signal this failure has ever had: before it, the turn ran and * its reply was dropped in silence. */ export declare function guardTurnAgainstCompaction(deps: GuardTurnDeps): Promise; //# sourceMappingURL=compaction-gate.d.ts.map