UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

36 lines (35 loc) • 2.44 kB
import { type UsageWindow, type UsageWindowReading, type UsageWindowStore } from "../../core/usage-window-store.js"; import { type CorruptReadInfo } from "./corrupt-read-sink.js"; export interface FileUsageWindowStoreOptions { /** Disclosure sink for a ledger that is present but cannot be read as one: it fires WITH the refusal and is the * only carrier of the file's location (the refusal's message, which reaches a run's failure text, names none). * Never fires on plain absence. Swallow-guarded: a throwing sink cannot change the refusal. */ onCorruptRead?: (info: CorruptReadInfo) => void; } /** * design/164 件五 — file-backed {@link UsageWindowStore}: ONE JSON record per governed key, semantics * identical to `InMemoryUsageWindowStore` BY CONSTRUCTION (both are shells around the same pure * `chargeUsageRecord` / `readUsageRecord`; neither re-implements window arithmetic). * * Atomicity: the file backend is single-process (the `FileStorageBackend` boot lock guarantees ONE writer * per data dir) and `charge` reads-modifies-writes SYNCHRONOUSLY (no await between the read and the * atomic replace), so the update is atomic within the one event loop — the in-memory store's premise. * Cross-process governance belongs to a database backend with a real transaction. * * **Corrupt records FAIL CLOSED** — in the same direction as `FileSessionPolicyStore`'s keyed read. A * policy file is a DENY list and a usage window is a CEILING; for both, reading a damaged record as "nothing * there" would drop the very limit the operator wired — here an unlimited, silent allowance, precisely what * the operator wired this to prevent. A corrupt record therefore refuses with `usage_window.store_corrupt` * until it is repaired or removed. */ export declare class FileUsageWindowStore implements UsageWindowStore { private readonly dir; private readonly onCorruptRead; constructor(root: string, opts?: FileUsageWindowStoreOptions); /** key → a safe, INJECTIVE filename (`sanitizeScope` appends the full sha256 of the raw key, so two * distinct principals can never share a ledger file). */ private pathFor; private loadRecord; charge(key: string, tokens: number, at: number, windows: readonly UsageWindow[], costMicroUsd?: number | null): Promise<void>; read(key: string, windows: readonly UsageWindow[], now: number): Promise<readonly UsageWindowReading[]>; }