import { type CredentialId } from "./credential-id.js"; import { type CostClass } from "./metadata.js"; import type { Config } from "./config-types.js"; /** * A learned condition or measurement about a routing target. * * The kinds split into two halves, and the split is load-bearing: * - CONDITIONS (`not-servable`, `subscription-required`, `allowance-exhausted`, `credential-invalid`, * `rate-limited`) say "this target is currently unusable for a reason". A success disproves a * condition, so `clearFacts()` deletes them; they cool or cost-block through the sets below. * - MEASUREMENTS (`context-limit`, `max-output`, `rate-limit-rpm|rpd|tpm|tpd`) say "here is a * ceiling this deployment stated". A success does not disprove a measurement, so they are in * none of the sets below and `clearFacts()` never touches them — they expire on their own TTL. * They are display-only today (see `rate-limits.ts`); acting on them is a separate, announced * decision. */ export type FactKind = "not-servable" | "subscription-required" | "allowance-exhausted" | "credential-invalid" | "rate-limited" | "context-limit" | "max-output" | "rate-limit-rpm" | "rate-limit-rpd" | "rate-limit-tpm" | "rate-limit-tpd"; /** * The evidence scope, in lookup order. `provider` deliberately means every credential for the * provider; credential-wide evidence must use `credential` instead. */ export type FactScope = { kind: "attempt"; provider: string; credentialId: CredentialId; model: string; } | { kind: "group"; provider: string; credentialId?: CredentialId; members: string[]; } | { kind: "deployment"; provider: string; model: string; } | { kind: "credential"; provider: string; credentialId: CredentialId; } | { kind: "provider"; provider: string; } | { kind: "model"; model: string; }; export interface CooldownFactClearSelector { readonly provider: string; readonly model?: string; readonly credentialId?: CredentialId; } export interface ClearedCooldownFact { readonly kind: FactKind; readonly scope: FactScope; } export declare const SCOPE_PRECEDENCE: Array; /** * How a fact's explicit `until` was resolved against the response that produced it. Mirrors the * rung order of `resolveReset` in `server.ts` — the one place these values are minted: * * retry-after — the response's own `Retry-After` header. * reviewed-field — a reviewed `field` ResetRule read out of THIS response's body * (Google's `retryDelay`): a measurement from a place only a reviewer knew. * stated-body — the generic body parse; the response stated a reset, unprompted. * reviewed-fixed — a reviewer-asserted window; knowledge of the provider, not of this response. * * ABSENT means a legacy row or the kind's default TTL — the relay declined to record why, so the * absence must never be read as a basis by a consumer. Never written as a guess: `recordFact` * accepts it only alongside a positive finite `retryAfterMs`. */ export type FactResetBasis = "retry-after" | "reviewed-field" | "stated-body" | "reviewed-fixed"; /** * Maps each reset basis to which rung of the availability ladder it belongs on. * This is the ONE definition — `UNTIL_BASES` derives from it, and `availability.ts` * `factResetInputs` reads it instead of comparing two literals. * * rung "stated" = rung 1 (provider_stated): retry-after, stated-body — came from the * provider's own response. * rung "reviewed" = rung 2 (reviewed_rule): reviewed-field, reviewed-fixed — a reviewer's * assertion, not a provider measurement. */ declare const FACT_RESET_BASIS_RUNG: Record; export { FACT_RESET_BASIS_RUNG }; export declare const FACT_TTL_MS: Record; /** * Exported so consumers validating cleared-fact echoes (`cooldown-clear.ts`) import the set * rather than re-typing it — the `DashboardErrorCode` precedent. A hand copy that lagged this * set would reject the relay's own valid response as malformed. */ export declare const COOLING_FACT_KINDS: ReadonlySet; /** * The kinds whose `until` may answer a QUOTA row's `resetsAt` (`availability.ts` * `factResetInputs`). Exported so the availability ladder and `llm-relay candidates` share one * definition instead of each restating a kind list. * * It is COOLING minus `credential-invalid` on purpose, and the narrowing is the point: the two * kinds here say "this allowance/throughput is spent and refills at T", which is what a quota row * asks. A revoked or faulted credential's expiry says when the RELAY will next try the key — a * different question, on a different axis, and answering the quota one with it would label an * auth cooldown as a quota reset. The evicting conditions (`not-servable`, * `subscription-required`) are excluded for the same reason: removal from selection is not * replenishment. Those all still render in the Cooldowns panel, which is where they belong. */ export declare const QUOTA_RESET_FACT_KINDS: ReadonlySet; export declare const FACT_KINDS: FactKind[]; /** * Canonical persisted key for a fact, INCLUDING its kind. * * ⚠ The kind is part of the key on purpose: one scope may legitimately carry several kinds at once * (a real Groq 429 states both an RPM and a TPM ceiling), and a key of scope alone made four * rate-limit measurements overwrite each other down to one. Conditions never collide this way in * practice (a cell holds at most one condition verdict), but the measurement half made the * omission a silent data loss, so the key is now `:` throughout. * * Exported so persistence tests cannot duplicate it. */ export declare function keyOf(kind: FactKind, scope: FactScope): string; /** Scope-only key, kept for callers that key a single-slot cell by scope alone. */ export declare function keyOfScope(scope: FactScope): string; export declare function recordFact(kind: FactKind, scope: FactScope, opts?: { path?: string; now?: number; retryAfterMs?: number | null; untilBasis?: FactResetBasis; value?: number; costClasses?: readonly CostClass[]; }): void; export declare function factsFor(provider: string, credentialId: CredentialId | null, model: string | null | undefined, opts?: { path?: string; now?: number; costClass?: CostClass | undefined; }): Array<{ kind: FactKind; scope: FactScope; until: number; untilBasis?: FactResetBasis; value?: number; }>; export declare function isCostBlocked(provider: string, credentialId: CredentialId | null, model: string | null | undefined, opts?: { path?: string; now?: number; costClass?: CostClass | undefined; }): boolean; /** * True only when EVERY enabled credential slot for this provider is cost-blocked. * A deployment is admitted and passes the free-only guard when at least one enabled slot is clear. */ export declare function isCostBlockedForEverySlot(provider: string, model: string | null | undefined, cfg: Pick, opts?: { path?: string; now?: number; costClass?: CostClass | undefined; }): boolean; export declare function cooldownUntil(provider: string, credentialId: CredentialId | null, model: string | null | undefined, opts?: { path?: string; now?: number; costClass?: CostClass | undefined; }): number | null; /** A success retracts conditions covering this credential/model cell, never measurements. */ export declare function clearFacts(provider: string, credentialId: CredentialId | null, model: string | null | undefined, opts?: { path?: string; now?: number; costClass?: CostClass | undefined; }): FactKind[]; /** Operator retraction of active cooling conditions only; never success evidence or eviction. */ export declare function clearCooldownFacts(selector: CooldownFactClearSelector, opts?: { path?: string; now?: number; }): ClearedCooldownFact[]; /** Rotation retraction of active credential-invalid facts only. */ export declare function clearCredentialInvalidFacts(selector: CooldownFactClearSelector, opts?: { path?: string; now?: number; }): ClearedCooldownFact[]; /** * Retraction for a provider-stated paid-spend statement (`spend-headroom.ts`): only * `allowance-exhausted` rows whose cost filter is PAID-ONLY. * * The narrowing is the whole point. A provider stating "this key still has paid credit" disproves * exactly the paid-spend exhaustion — it says nothing about a free-tier allowance. So a row with * NO filter (covers every class) and a row filtered to `free` both survive; retracting either * would launder a paid-credit statement into evidence about the free tier, the same collapse the * "out of free credits is NOT paid" rule forbids in the other direction. */ export declare function clearPaidAllowanceFacts(selector: CooldownFactClearSelector, opts?: { path?: string; now?: number; }): ClearedCooldownFact[]; export declare function allFacts(opts?: { path?: string; now?: number; }): Array<{ kind: FactKind; scope: FactScope; at: number; until: number; untilBasis?: FactResetBasis; }>; export declare function describeScope(scope: FactScope): string; export declare function flushFacts(opts?: { path?: string; now?: number; }): void; export declare function resetFacts(): void;