/** * Per-request token accounting, so the cost of compressing can be attributed * rather than argued about. * * WHY THIS EXISTS. The first end-to-end measurement of the proxy showed four * THOL tasks taking 36 turns against control's 35 -- effectively no turn cost -- * while costing $0.58 against $0.43. Turns barely moved and money moved a lot, * which means the difference is per-turn token spend rather than extra work. * Nothing in the rig could say which kind of token: a cache read bills at 0.1x, * a cache write at 1.25x, and a plain input token at 1.0x, so a strategy can cut * the token COUNT and raise the BILL by moving tokens between those classes. * * The benchmark models that split from recorded payloads. It cannot observe it, * because only the provider says what it actually charged. This reads the * `usage` the provider reports and writes it beside what compression did to the * same request, so the two can be joined per turn. * * OFF UNLESS ASKED FOR. It writes a file, and a proxy that writes files nobody * requested is a proxy nobody should run. `TOKEN_OPTIMIZER_PROXY_ACCOUNTING` * names the path; absent, nothing here does anything. * * FAILS OPEN, ALWAYS. This is instrumentation. An optimizer that wedges the * agent is worse than one that saves nothing, and that goes double for a * measurement it was not asked to take. */ import type { Readable } from 'node:stream'; /** The token classes a provider bills separately. */ export interface RequestUsage { input_tokens?: number; output_tokens?: number; cache_creation_input_tokens?: number; cache_read_input_tokens?: number; /** Responses input_tokens includes this subset; do not add it a second time. */ cached_input_tokens?: number; } /** * Pulls usage numbers out of a response fragment, keeping the LAST value seen * for each key. * * Last-wins is the correct rule rather than a convenience. A streaming response * reports input and cache tokens once in `message_start` and then reports * `output_tokens` again in every `message_delta`, cumulatively -- so the final * occurrence is the total and an earlier one is a partial count. */ export declare function scanUsage(text: string, into: RequestUsage): void; /** What compression did to one request, as the summary already reports it. */ export interface CompressionFacts { readonly compressed: boolean; readonly reason?: string; readonly anchorReason?: string; readonly elisions?: number; /** References actually forwarded by the Responses deduplicator. */ readonly dedupReferences?: number; readonly deferredTools?: number; readonly deferredToolChars?: number; /** * Characters of cached knowledge added to the request. * * RECORDED BECAUSE IT IS THE ONE THING HERE THAT MAKES A REQUEST BIGGER, * and it was the one fact the ledger did not carry. The proxy printed * `+1927 injected` to its log while the ledger line beside it said nothing, * so an A/B of the knowledge block read its own effect as zero and would * have reported the feature inert. A cost that only appears in a log a * measurement does not parse is a cost nobody attributes. */ readonly injectedChars?: number; readonly systemChars?: number; readonly toolsChars?: number; readonly toolCount?: number; readonly coreToolChars?: number; readonly mcpToolChars?: number; readonly topTools?: string; readonly messagesChars?: number; readonly messageCount?: number; readonly beforeBytes: number; readonly afterBytes: number; } /** One line of the ledger: what we sent, and what it was billed as. */ export interface AccountingRecord extends CompressionFacts { /** Monotonic durations. Upstream includes transport and provider processing. */ readonly timing?: { readonly transformMs: number; readonly upstreamHeadersMs?: number; readonly upstreamMs: number; }; readonly ts: string; readonly path: string; readonly status: number; /** No HTTP response was received; usage remains unknown, not zero. */ readonly transportError?: string; readonly usage: RequestUsage; } /** The ledger path, or null when accounting was not asked for. */ export declare function accountingPath(env?: NodeJS.ProcessEnv): string | null; /** * Appends one record. Swallows every failure by design -- see the file header. */ export declare function appendRecord(path: string, record: AccountingRecord): void; /** * Watches a response stream for usage numbers without touching what it carries. * * OBSERVES, NEVER INTERPOSES. Attaching a `data` listener does not consume the * stream in flowing mode, so the existing `pipe` still delivers every byte * unchanged -- which matters more here than anywhere, because an SSE stream has * to arrive as it is produced and this is a byte-faithful proxy. * * BOUNDED. The parser retains only bounded usage objects and structural state, * never the assistant's response content. */ export declare function tapUsage(stream: Readable, done: (usage: RequestUsage) => void, contentEncoding?: string): void; //# sourceMappingURL=accounting.d.ts.map