/** * Per-turn token-usage accumulator for the codex app-server protocol. * * codex emits token usage via `thread/tokenUsage/updated` notifications, NOT on * `turn/completed` (whose Turn object carries no usage). A single codex turn can * produce MANY upstream completions (tool-call loops), so the notification's * `tokenUsage.last` is only the LAST completion's usage — never the whole turn. * The authoritative per-turn figure is a delta of the cumulative `total`: * * - on the first notification for a turn, derive baseline = total - last * (per field), so a resumed session needs no prior session-total knowledge; * - the turn's usage so far = latestTotal - baseline (per field); * - later notifications only advance latestTotal (total-delta is idempotent * against duplicate notifications — never sum `last`, never overwrite). * * Fail-closed: if `total` regresses or any derived field goes negative, the * usage is dropped (returns null) and the caller logs a protocol warning rather * than reporting corrupt numbers. * * Ref: codex protocol TokenUsageInfo::append_last_usage (total += last; last = * this completion) and app-server ThreadTokenUsageUpdatedNotification / * TokenUsageBreakdown (0.145 generated types). */ /** codex TokenUsageBreakdown (0.145). All numbers; cumulative on `total`. */ export interface CodexTokenBreakdown { totalTokens: number; inputTokens: number; cachedInputTokens: number; cacheWriteInputTokens: number; outputTokens: number; reasoningOutputTokens: number; } /** riff-facing four-bucket usage (mutually exclusive input buckets). */ export interface TurnTokenUsage { inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheCreateTokens: number; } /** Validate a raw notification payload's breakdown into a typed one, or null. * 0.145 fields are REQUIRED except `cacheWriteInputTokens` (added later, so a * compat default of 0 is honest for it only). Any other missing/non-numeric * field returns null — defaulting them to 0 would misreport a protocol gap as a * real 0. * * NOTE: when `total` and `last` are consumed together (the accumulator), prefer * `parseTokenUsagePair` — it additionally enforces that the back-compat * cacheWrite default is only honored when BOTH sides omit the field. A lone * breakdown parsed here cannot see its counterpart, so a `cacheWrite=0` default * here is provisional until the pair check confirms symmetry. */ export declare function parseCodexTokenBreakdown(raw: unknown): CodexTokenBreakdown | null; /** Parse the `{ total, last }` pair from one notification, enforcing the * cross-breakdown invariant the single parser can't see: the back-compat * `cacheWriteInputTokens → 0` default is honest ONLY when BOTH breakdowns omit * the field (a genuinely old codex). If exactly one side carries it, the two * disagree (version skew / corruption): silently defaulting the missing side to * 0 would misattribute real cache-create tokens into fresh input AND poison the * baseline for later completions with a plausible-looking undercount. Return * null so the caller poisons the turn instead of emitting corrupt buckets. */ export declare function parseTokenUsagePair(rawTotal: unknown, rawLast: unknown): { total: CodexTokenBreakdown; last: CodexTokenBreakdown; } | null; /** Map a cumulative-delta codex breakdown to riff's four mutually-exclusive * buckets. codex `inputTokens` INCLUDES cached-read + cache-write, so the * fresh-input bucket subtracts both. Returns null if the split is incoherent * (buckets exceed input) — caller drops usage + warns rather than emit garbage. */ export declare function toFourBucket(d: CodexTokenBreakdown): TurnTokenUsage | null; /** Accumulates per-turn usage from `thread/tokenUsage/updated` notifications for * ONE appTurnId, using the total-delta algorithm. */ export declare class TurnTokenUsageAccumulator { private baseline; private latestTotal; private protocolWarning; /** Feed a notification's `tokenUsage` = { total, last, ... }. `total` is * cumulative; `last` is the most recent completion's usage. */ update(total: CodexTokenBreakdown, last: CodexTokenBreakdown): void; /** Mark this turn's usage as unusable (sticky). Called when a notification for * the turn arrives but its breakdown is malformed: skipping it silently would * let a LATER valid notification rebuild a fresh baseline and report only the * last completion — a plausible-looking undercount. Poisoning makes result() * omit + warn instead. */ poison(reason: string): void; /** The turn's usage so far as four buckets, or null if no usage seen / a * protocol anomaly was detected / the bucket split is incoherent. When usage * is dropped for an incoherent delta or bucket split (as opposed to simply * never having seen a notification), a warning is recorded so the caller can * surface the omission rather than dropping it silently. */ result(): TurnTokenUsage | null; /** Non-null when the accumulator gave up on usage for a protocol reason. */ get warning(): string | undefined; } //# sourceMappingURL=codex-app-token-usage.d.ts.map