import type { ModelPricing } from './types.js'; /** * Model and pricing catalogue (USD per million tokens). * * Source: official Claude API documentation. Prices change: check * `PRICING_LAST_REVIEWED` and update this file before making budget decisions. * Amazon Bedrock and Vertex AI pricing is set by each partner and is NOT the * pricing in this table. */ /** * When each provider's prices were last checked against that provider's own * published table. * * One date for the whole catalogue was the wrong shape, and it cost a real * error. Seven providers publish independently and are checked independently; * a single date forces a partial review to either overstate itself by moving * the date for everyone, or throw itself away by leaving it. What happened is * the second: this constant was written on 2026-08-04 already reading * 2026-06-24, and never moved again. * * Meanwhile Anthropic cancelled the increase that was going to take Sonnet 5 * from its 2/10 introductory price to 3/15 on 2026-09-01, and made 2/10 * standard. The catalogue still carried the promotion with its end date, so on * 2026-09-01 every Sonnet 5 figure this tool printed would have risen 50% with * no code change and no way for a reader to tell. A price nobody charges is * the one error this product cannot make, and it was four days out on a timer. * * So: a date per provider, checked against that provider's own page, and the * catalogue's headline date derived as the oldest of them rather than typed. */ export declare const PROVIDER_REVIEWED: Readonly>; /** * The catalogue's age is its oldest provider's, because a reader asking how * old this table is wants the answer for the worst part of it, not the best. */ export declare const PRICING_LAST_REVIEWED: string; /** Cost multipliers relative to the input price. */ /** * The defaults, which are Anthropic's numbers. * * Still exported and still correct for every Anthropic model, but no longer the * whole story: a model can override any of these through `multipliers`, and * anything computing a cost should go through `multipliersFor` rather than * reading these directly. A cache read is ~10% of input on Anthropic and ~50% * on OpenAI, and using one number for both invents a saving. */ export declare const COST_MULTIPLIERS: { /** Cache write with a 5-minute TTL. */ readonly cacheWrite5m: 1.25; /** Cache write with a 1-hour TTL. */ readonly cacheWrite1h: 2; /** Cache read: ~10% of the input price. */ readonly cacheRead: 0.1; /** Batch API: 50% discount on input and output. */ readonly batch: 0.5; }; export declare function multipliersFor(model: ModelPricing): { cacheWrite5m: number; cacheWrite1h: number; cacheRead: number; batch: number | null; }; export declare const MODELS: ModelPricing[]; export declare const DEFAULT_MODEL = "claude-opus-5"; /** * A set of prices to work from. * * Prices change on someone else's schedule, and until 1.0 correcting one meant * upgrading the library — which is backwards: a stale price is a wrong number in * a budget decision, and nobody should have to take a dependency bump to fix it. * * So the catalogue is a **value**, not module state. The bundled one below is the * default, and `applyPricingOverlay` returns a *new* catalogue with local * corrections layered on. Nothing mutates: a caller who overlays prices does not * change what any other caller sees, and two catalogues can exist in one process * — which is what makes it testable and what stops one consumer's local prices * leaking into another's report. */ export interface PricingCatalogue { models: ModelPricing[]; byId: Map; /** The date the prices in this catalogue were last checked. */ lastReviewed: string; /** Ids whose bundled prices an overlay replaced. Empty for the bundled set. */ overriddenModels: string[]; /** Ids an overlay introduced that the bundled catalogue does not have. */ addedModels: string[]; } /** * The one index every catalogue is looked up through. * * Exported, and the only builder, because there used to be two: this one * learned about `aliases` in 1.77.0 and the overlay's did not, so a dated * model id priced fine until somebody passed `--pricing-live` and then * eight calls quietly left the totals. Two builders means one of them is * always the one nobody updated. * * Aliases are written first and ids last, so a real id always wins over a * declared alias that collides with it. */ export declare function indexModels(models: ModelPricing[]): Map; /** The prices compiled into this release. */ export declare const BUNDLED_CATALOGUE: PricingCatalogue; /** * Whether this model may be offered to a reader as something to move to. * * One home for a two-part rule that used to be written in four places as one * part. `recommendable: false` — a private programme, a waitlist — was honoured * at every one of them. `retired` is the stronger statement: the provider * answered a real request for the id with an error, so a switch to it is not a * worse recommendation, it is one that cannot be carried out at all. * * Written as a function rather than as a second `&&` at four call sites, * because the fifth call site is always the one that gets written with only the * first half. `pricing.test.js` fails a source file that filters on * `recommendable` without coming through here, and that guard was proved by * planting exactly that filter. * * Pricing is a separate question and stays answered: a retired model keeps its * price, because a log full of its calls records money that was really spent. */ export declare function isOffered(model: ModelPricing): boolean; /** Looks a model up in a specific catalogue. */ export declare function modelFrom(catalogue: PricingCatalogue, id: string): ModelPricing; /** * Cheapest model of a tier within a catalogue. * * Compared on the **effective** price, so a model in a promotional window is * ranked at what it actually costs today rather than at its list price. */ export declare function cheapestOfTierIn(catalogue: PricingCatalogue, tier: ModelPricing['tier'], on?: Date, /** * Restrict to one provider. Omit to search the whole catalogue, which is what * this did before other providers existed — kept as the default so the * signature stays additive, though the advisory always passes one: switching * vendor is a migration, not a cheaper model. */ provider?: string): ModelPricing; export declare function getModel(id: string): ModelPricing; export declare function listModels(): ModelPricing[]; /** Effective price on a given date, applying any live promotion. */ /** * Memoised per model, because this runs once per record when a usage log is * priced: a 200k-line profile called it 200k times, and the `new Date(...)` * parse of the promo's end date alone was 0.7 of the 2.4 seconds the whole * profile took — measured with --cpu-prof, not guessed. The cache keys on * the model object (a WeakMap, so an overlay's models are collected with * the overlay) and stores the parsed end-of-promo instant plus the two * possible answers; `on` still decides which answer applies on every call, * so behaviour is unchanged to the millisecond. */ interface Rates { inputPerMTok: number; outputPerMTok: number; promoApplied: boolean; tier: { applied: string | null; decided: boolean; because: string; } | null; } /** * What one call is billed at, and what decided it. * * `tier` is the field this grew for, and it carries three states rather than * two. A model with no tiers gets `null`. A model whose condition could be * evaluated gets the tier that applied, or the base rate with `applied: null` * and `decided: true`. A model whose condition could **not** be evaluated — * a size tier priced without a token count — gets `decided: false`, the * **dearer** of the candidate rates, and `because` naming what would settle it. * * The dearer one is not a shrug. A cost figure that is a ceiling can prove * "under budget" and can never surprise a bill; a floor chosen for looking * better is the flattering direction this product spends its time refusing. * The reader still has to be told, which is what `decided: false` is for, and * `pricing.test.js` fails a tiered model whose report drops it. */ export declare function effectivePricing(model: ModelPricing, on?: Date, context?: { inputTokens?: number; }): Rates; /** * The date the prices behind one report were reviewed. * * ## The sentence this exists to make true * * `PRICING_LAST_REVIEWED` is the **oldest** provider's date, which is the right * answer to *how old is this table* and the wrong answer to *how old are the * prices in front of me*. Every surface that warns about staleness was using * it, and the warning says, in these words, that the table behind **every * dollar here** was last reviewed on that date. * * On 2026-08-31 that sentence was false on a report of Claude and OpenAI * calls. It named 2026-06-24 — the date belonging to two models that appear in * no such report and whose providers stopped listing them — while the prices * actually used had been read four days and zero days earlier. A warning that * fires on every run is one people stop reading, and a provenance that does * not hold is the one thing this tool exists not to print. * * `trazum models` had already worked this out and prints the dates per * provider, with the reason in a comment. The fix reached one surface and not * the three that qualify a figure. * * ## What it returns, and the direction it errs in * * The oldest review date among the providers that actually priced these * models. Where that cannot be established it returns the catalogue's own * `lastReviewed`, which is the **conservative** direction: reporting a fresher * date for a report containing a price of unknown provenance would be claiming * provenance this table does not have. * * It cannot be established in three cases, all of which fall back: * * - **An overlay is in effect.** `--pricing` and `--pricing-live` replace * prices with numbers whose provenance is the overlay's own date, and * `PROVIDER_REVIEWED` describes the bundled table rather than theirs. * - **A model the catalogue does not carry**, or one carrying no provider: a * price with no page behind it. * - **A provider with no recorded review date.** * * The fallback is inside this function rather than at each call site on * purpose. `isOffered` records why: the fifth call site is always the one * written with only the first half of a two-part rule. */ export declare function reviewedForModels(models: Iterable, catalogue: PricingCatalogue): string; /** Cheapest model of each capability tier, for recommendations. */ export declare function cheapestOfTier(tier: ModelPricing['tier']): ModelPricing; /** * Whole days between a `YYYY-MM-DD` review date and now, or `null`. * * Every dollar figure Trazum prints descends from a price list, and the list * carries the date it was checked. Printing only that date makes the reader do * arithmetic against today to learn the one thing they wanted to know — whether * to trust it — and a reader who is not already suspicious will not bother. * * `now` is a parameter for the reason `computeSavings` takes a `Date`: a function * that reads the clock can only be asserted for shape. * * Compared at UTC midnight on both sides, so the answer does not change by one * depending on what time of day the command runs. `null` for anything that is not * a date — an overlay supplies this string, and a wrong one should read as * unknown rather than as a confident number computed from `NaN`. */ /** * The age at which this product stops treating its own price table as current. * * Three surfaces warn a reader that the figures above may be off — `profile`, * the MCP report, the browser's bill — and each of them had typed `45` into * its own comparison, with four locale sentences stating it again in prose. * Seven copies of one claim, and nothing that would notice when they * disagreed; the sentence a reader sees names the number, so a drift between * them would have been a surface telling the reader one threshold and applying * another. * * The value is what those surfaces already published, not a new judgement. */ export declare const STALE_PRICING_DAYS = 45; export declare function reviewAgeDays(lastReviewed: string, now: Date): number | null; export {}; //# sourceMappingURL=pricing.d.ts.map