import { type TokenUsage } from '../../types/common/index.js'; import type { SessionId, TurnId } from '../../types/ids/index.js'; import type { TurnBudgetBinding } from '../../types/session/turn.js'; /** Version of the token-budget document. Version 1 (keyed by turn) is refused, never migrated. */ export declare const SESSION_TOKEN_BUDGET_VERSION: 2; /** * The key of one ledger: the root turn that opened it, in its root session. * * A child session's turns bind to the key of the root turn that spawned them, * a resumed paused turn reuses its key, and a new root turn opens a new * ledger with a limit of its own. */ export interface SessionTokenBudgetScope { readonly rootSessionId: SessionId; readonly rootTurnId: TurnId; } /** The turn an account is bound to. */ export interface SessionTokenBudgetTurn { sessionId: SessionId; turnId: TurnId; } export interface SessionTokenBudgetAccountSnapshot { id: string; parentId?: string; limit: number; settled: boolean; /** The one turn this account spends for; absent until bound. */ turn?: SessionTokenBudgetTurn; /** Cumulative own usage, keyed by the bound turn's id; descendants never appear here. */ usage: Record; } export interface SessionTokenBudgetRequestSnapshot { id: string; accountId: string; turnId: TurnId; /** Cumulative request usage already charged to the owning turn. */ usage?: TokenUsage; /** No reliable final receipt; only explicit reconciliation clears this marker. */ unresolved?: boolean; } /** * The token-budget document, stored at * `/budgets/.json`. Durable authority * independent of a checkpoint's cadence. */ export interface SessionTokenBudgetSnapshot { v: typeof SESSION_TOKEN_BUDGET_VERSION; kind: 'token-budget'; rootSessionId: SessionId; rootTurnId: TurnId; /** The root account's current limit; 0 is unlimited. Always equal to that account's `limit`. */ limit: number; rootAccountId: string; accounts: SessionTokenBudgetAccountSnapshot[]; requests: SessionTokenBudgetRequestSnapshot[]; /** Durable receipts make repeated completion delivery a no-op. */ completedRequests: SessionTokenBudgetRequestSnapshot[]; poisoned?: boolean; } export interface SessionTokenBudgetPersistence { save(snapshot: SessionTokenBudgetSnapshot): Promise; } export interface SessionTokenBudgetSummary { limit: number; ownTokens: number; treeTokens: number; reservedTokens: number; /** null means unlimited; unlike Infinity this survives JSON serialization. */ remainingTokens: number | null; inFlightRequests: number; unsettledChildren: number; /** This account is blocked by accounting failure or uncertain finite allowance. */ poisoned: boolean; /** Unresolved receipts in this subtree, including retained completion records. */ unresolvedRequests: number; } /** A token-budget document this release does not read: version 1, another version, or another kind. */ export declare class SessionTokenBudgetVersionError extends Error { readonly name = "SessionTokenBudgetVersionError"; } /** Validate the whole tree, then return a defensive, JSON-safe snapshot. */ export declare function validateSessionTokenBudgetSnapshot(value: unknown): SessionTokenBudgetSnapshot; /** * One conserved token authority for a root turn and every child session * turn it spawns, keyed by `(rootSessionId, rootTurnId)`. * * A child's unused reservation is unavailable to its parent and siblings. * Measured spend replaces that reservation, including overshoot debt. * Provider usage is known after a request: this enforces admission, not an * exact upper bound on the tokens an already admitted request can report. */ export declare class SessionTokenBudget { private readonly ledger; readonly accountId: string; private constructor(); static create(limit: number, scope: SessionTokenBudgetScope, persistence?: SessionTokenBudgetPersistence): SessionTokenBudget; static restore(snapshot: SessionTokenBudgetSnapshot, persistence?: SessionTokenBudgetPersistence): SessionTokenBudget; get limit(): number; /** The turn this account spends for, when bound. */ get turn(): SessionTokenBudgetTurn | undefined; get turnId(): TurnId | undefined; /** The ledger's key. */ get scope(): SessionTokenBudgetScope; /** * The checkpoint reference to this account, when the ledger is persisted. * A ledger with no persistence has nothing a later process could reopen, * so it has no binding. */ get binding(): TurnBudgetBinding | undefined; get ownUsage(): TokenUsage; get ownTokens(): number; get treeTokens(): number; /** This account's request is still awaiting its final receipt; descendants are independent. */ get hasInFlightRequest(): boolean; get remaining(): number; account(accountId: string): SessionTokenBudget; findTurn(turn: TurnId): SessionTokenBudget | undefined; /** Bind this account to the one turn it spends for. Idempotent; a binding never changes. */ bindTurn(session: SessionId, turn: TurnId): void; reserve(tokens: number): SessionTokenBudget; /** Narrow the entire subtree; already measured spend and reservations remain. */ narrow(limit: number): void; /** Reconcile a cumulative OWN turn counter; a completion is not another spend. */ recordUsage(usage: TokenUsage, turn?: TurnId | undefined): void; beginRequest(): Promise; finishRequest(requestId: string, usage: TokenUsage): Promise; /** Unknown spend cannot be converted into a refund, even after cancellation. */ failRequest(requestId: string, usage?: TokenUsage): Promise; /** * Explicit host recovery after obtaining the provider's final usage receipt. * Ordinary completion never clears uncertainty. Reconciliation resolves this * request after its receipt is persisted; other uncertain requests continue * to constrain their shared finite allowances. Usage and settlement are retained. */ reconcileRequest(requestId: string, usage: TokenUsage): Promise; settle(ownTotalTokens?: number): void; summary(): SessionTokenBudgetSummary; snapshot(): SessionTokenBudgetSnapshot; flush(): Promise; private uncertainRequests; private admissionBlocked; private get node(); private requireAccount; private requireOwnUsage; private hasReceipt; private recordRequestUsage; private children; private descendants; private hasRequest; private totals; private free; private requireRequest; private checkAggregateReplacement; private persist; } //# sourceMappingURL=ledger.d.ts.map