/** * What the provider billed, beside what Trazum computed. * * The one figure nobody else gives you. Every other door here answers *what * did this usage cost at these rates*; the provider answers *what did we * charge you*, and the two are different questions that produce different * numbers. The gap between them is the interesting part, and until this file * there was nowhere to look at it. * * ## Why the two are never added * * `docs/commands.md` already states the rule for LiteLLM's `total_cost`: a * provider-billed figure is printed **beside** Trazum's and never merged into * it, because two price tables summed into one number is how a report becomes * quietly wrong. This file is that rule with arithmetic attached. Nothing here * corrects one figure with the other, and nothing here decides which is right: * they are two measurements of the same window, and the reader is the one * entitled to say which they trust. * * ## The unit, which is the trap * * `amount` is **a decimal string in the currency's lowest unit**: `"123.45"` * in USD is $1.2345, not $123.45. A reader of this API who takes the field for * dollars overstates a bill by a hundred times, and the figure looks entirely * plausible on a large organisation. It is divided by a hundred here, once, at * the end, and a test asserts the factor against the schema's own example. * * `currency` is documented as always `USD` today. It is still checked: a * converter that assumed it would be silently wrong the day it changes, and * summing two currencies into one total is the same failure as summing two * price tables. Anything but USD is refused rather than converted, because a * conversion needs a rate and inventing one is the sin this product is built * against. * * ## What the decomposition is for * * A difference nobody can attribute is a number that starts an argument. This * report can attribute most of one, when it is fetched with * `group_by[]=description`: * * - **`cost_type` other than `tokens`** — web search, code execution, session * usage. Trazum prices tokens and nothing else, so every cent of these is * billed money it never claimed to cover. Named rather than blamed. * - **`service_tier: "batch"`** — billed at a discount `from-anthropic` * deliberately leaves out rather than misprice at a catalogue rate. * * What is left after both is the **remainder**, and it is the only figure here * worth arguing about: the same standard-tier tokens, priced two ways, or * usage the log never saw. A tool that folded the remainder into one of the * explanations would be hiding the only thing it was built to show. * * Without `group_by[]=description` none of that decomposition exists — * `cost_type`, `service_tier` and `model` are all `null` — and the reading * says so rather than reporting a remainder that is really the whole * difference wearing a smaller name. */ /** * What a provider charged, in the terms `reconcile` needs and no more. * * Two providers' reports read into it, and the difference between them is * confined to the files that read them: what the money was for, whether * batch can be told apart, which window, which currency. */ export interface BilledReading { /** Everything billed in the window, in dollars. */ usd: number; /** Billed for something no token rate covers: web search, code execution. */ notTokensUsd: number; /** Billed at the batch tier, which a catalogue rate is not the rate for. */ batchUsd: number; /** * Whether this report can name a batch charge at all. * * Anthropic's can, once grouped by description. OpenAI's never does, so a * batch discount there sits inside the remainder and the reader is told. */ batchSeparable: boolean; /** * Whether the report was fetched with the grouping that names each row. * * Without it nothing on a row says what the money was for, so neither * figure above can be separated from the total and a reconciliation can * only report a difference it cannot attribute. */ described: boolean; /** The window the buckets actually cover, or `null` when there are none. */ window: { fromMs: number; toMs: number; } | null; /** Currencies seen that were not USD. Summing across them is refused. */ otherCurrencies: string[]; } /** What Anthropic charged, read from its own report. */ export interface AnthropicCostReading extends BilledReading { buckets: number; rows: number; /** Rows whose `amount` was not a number. Counted, never read as zero. */ unreadableAmount: number; /** `has_more`: one page of several, so the billed figure is understated. */ truncated: boolean; /** The input was not the JSON this endpoint returns. */ unparseable: boolean; } /** Two measurements of one window, and what separates them. */ export interface Reconciliation { computedUsd: number; billedUsd: number; /** Billed minus computed. Positive means the provider charged more. */ differenceUsd: number; /** The part of the difference the report itself accounts for. */ notTokensUsd: number; batchUsd: number; /** * What neither figure explains: the same standard-tier tokens priced two * ways, or usage the log never saw. The only number here worth arguing * about, and never folded into the two above. */ remainderUsd: number; /** `false` when the report was not grouped in a way that names its rows. */ attributable: boolean; /** `false` when this provider's report cannot name a batch charge at all. */ batchSeparable: boolean; /** Why the two are not comparable, when they are not. */ refusal: { reason: 'no-billed-window'; } | { reason: 'window-not-covered'; computed: { fromMs: number; toMs: number; }; billed: { fromMs: number; toMs: number; }; } | { reason: 'other-currency'; currencies: string[]; } | null; } /** * Read a cost report. Pure, like every measuring function here, and for the * same reason `anthropic-usage.ts` gives: the credential that fetches this is * an admin credential, and this project holds none. */ export declare function anthropicCostReport(text: string): AnthropicCostReading; /** * Set what Trazum computed beside what the provider billed. * * @param computed what Trazum priced, and the window it priced. * * **The windows must line up or this refuses.** A receipt for September set * against a bill for August is a wrong number under a right title, which is * the failure this whole product is arranged against. The billed window has * to contain the computed one — daily buckets are wider than a receipt's span * by construction, so containment rather than equality is the honest test — * and a report that starts after the first call it is being compared with is * missing money nobody would see was missing. */ export declare function reconcile(computed: { usd: number; fromMs: number; toMs: number; }, billed: BilledReading): Reconciliation; /** * Whether this text is a cost report rather than some other JSON. * * `amount` with `currency` beside it, in a document with buckets: the usage * report has neither, and a Messages response has no buckets. */ export declare function looksLikeAnthropicCost(text: string, prefixBytes?: number): boolean; //# sourceMappingURL=anthropic-cost.d.ts.map