import type { EngineName } from "./models.js"; import type { EngineLimitWindow, JinnConfig, ModelRegistry } from "./types.js"; /** * Whether an engine can actually serve a turn, beside the installed-availability * the model registry reports. * * Advisory by construction, and every part of that is deliberate: reads and * writes swallow their own errors, every record carries the moment it stops * being true, and both dispatchers walk their chain again without health when * health would have left them nothing. The worst a wrong record can do is order * a chain differently — it can never refuse a turn. */ export type EngineHealthState = "ok" | "exhausted" | "degraded"; export interface EngineHealth { state: EngineHealthState; /** ISO. The reopening the engine itself stated, verbatim: what every display * surface shows, and the moment the record is spent. */ until?: string; /** ISO. When a dispatcher may offer the engine a probing turn again, on an * `exhausted` record. Internal — a shorter belief than `until`, never a * shorter claim, so it is deliberately not displayed anywhere. */ recheckAt?: string; /** The binding quota window as telemetry names it (`5h`, `7d`), when it does. */ window?: string; reason?: string; observedAt?: string; } /** Live readings keyed by engine name. An engine with no entry is healthy. */ export type EngineHealthReading = Record; /** Every engine something has been observed about, with a record whose window * has passed reading back as `ok`. */ export declare function readEngineHealth(now?: Date): EngineHealthReading; /** The one question a dispatcher asks, and the only reader of `recheckAt`: past * the re-probe the engine is offered a turn again even though the record still * reads — and still displays — as out until its stated reset. * * `degraded` is deliberately not an answer to it: an engine that named no * reopening is a preference, never a reason to hold a turn back. A record from * before re-probes existed carries no `recheckAt` and blocks until `until`, * which is what it meant when it was written. */ export declare function isEngineExhausted(health: EngineHealthReading, engine: string, now?: Date): boolean; /** * Note that an engine could not serve a turn, given whatever it said about when * it can again. * * A stated reopening is stored verbatim and is `exhausted` until then. Silence * is `degraded`, because a failure that named no end says nothing about when to * stop believing it — but silence from an engine already out until a stated * reset is a failed re-probe, and that replaces neither the state nor the * reopening it already stated. A re-probe only ever moves the next re-probe. */ export declare function recordEngineUnavailable(engine: string, reason: string, resetsAtSeconds?: number, now?: Date, window?: string): void; /** * The same fact a failed turn would have carried, minus the failed turn: a quota * window the provider itself reports as fully spent. When several are spent the * engine is back only once the last of them reopens. */ export declare function recordExhaustedWindows(engine: string, windows: readonly EngineLimitWindow[] | undefined, now?: Date): void; /** * The first engine in `from`'s chain that can take the turn: one the caller * accepts AND whose allowance has not run out. * * A chain the health filter empties is walked again without it. Installed * availability stays the only hard gate, so a record that has gone stale can * reorder a chain but can never empty one the caller would have accepted. */ export declare function resolveHealthyFallbackEngine(config: JinnConfig, from: string, isUsable: (engine: EngineName) => boolean, health: EngineHealthReading): EngineName | null; /** * The engine a NEW session should start on, given the one it prefers. * * Only ever asked about a preference the caller did not state outright — an * engine named in the request runs, spent allowance or not. Ordering, never * refusal: when nothing left in the chain can serve either, the preference is * handed straight back and the session starts exactly where it would have. */ export declare function preferHealthySessionEngine(config: JinnConfig, preferred: EngineName, isUsable: (engine: EngineName) => boolean, health: EngineHealthReading): EngineName; /** The registry as an API consumer reads it: installed availability from the * registry, the live reading beside it. */ export declare function withEngineHealth(registry: ModelRegistry): Record; //# sourceMappingURL=engine-health.d.ts.map