Skip to main content

llm-rates

Named llm-rates (not llm-prices, its name until 2026-08-21) because PyPI's similarity check rejected llm-prices as too close to the existing llmprices project — collapsed-separator collision, not an exact-name clash. llm-rates was verified free in every form (llm-rates, llmrates, llm_rates, singular llm-rate/llmrate) before adopting it; don't re-litigate the name.

One vendored model-price catalog + one internal overlay + a shared Python lookup/cost-math module, replacing four independently hand-maintained price tables that were drifting apart. Full origin story and decisions: this repo's sibling checkout plugin/docs/plans/model-catalog-consolidation.md (cross-repo — plugin is a separate git repository from libs, so this is a path reference, not a clickable link).

Why this exists

Four tables held the same vendor facts (plugin/scripts/prices/anthropic.json, plugin/skills/tokenator/scripts/pricing.json, sessions/src/sessmon/pricing.py, factory-bench/runs/model-bench/model-bench-runner.py). One of them silently returned $0.00 for any model it didn't recognise — a lookup bug, not a data bug — and under-reported real spend by over $800 in one 30-day window. This package fixes the lookup logic (never $0 for an unknown model) and gives the data one home.

Files

  • catalog.json — vendored snapshot of litellm's model_prices_and_context_window.json, filtered to the providers/models the portfolio actually uses. Vendor list price, per-single-token USD (litellm's native unit). Never hand-edit — regenerate prices via refresh.py --apply; for Anthropic-provider rows, the capability fields (max_input_tokens/max_output_tokens) are instead kept in sync with Anthropic's own live Models API via refresh_context.py --apply (litellm's snapshot is a third-party guess for those fields, not authoritative).
  • overlay.json — everything no public catalog can know: actual-billing overrides (e.g. Groq OSS models are free-tier here, not their list price), family-rate fallbacks (claude-opus → tier rate, so an unrecognised new model prices at its family's rate instead of $0), model-ID aliases (dated suffixes → canonical key), retirement/deprecation history (a retired model's row is kept, never deleted, so historical transcripts still reprice correctly), context_overrides for the rare model whose real default-served context genuinely differs from its published maximum (empty as of 2026-08-21 — see "Context-window data" below), and per-consumer portfolio pins.
  • llm_rates/lookup(model_id) -> PriceRecord + cost math (in __init__.py); catalog.json and overlay.json ship inside this directory as package data so an installed wheel carries them alongside the code. Shared by every Python consumer; the sole PowerShell consumer (tokenator.ps1) can't import Python, so it reads a generated JSON table instead — see generate_tokenator_table.py below and the plan doc's "Known constraint".
  • refresh.py — re-pulls the live litellm catalog, re-filters it to the same model set, diffs against the vendored catalog.json, and prints a report. Never applies silently — pass --apply to write. Price source only; does not touch capability fields for Anthropic-provider rows.
  • refresh_context.py — re-pulls max_input_tokens/max_tokens for every Anthropic-provider catalog.json row from Anthropic's own live Models API (client.models.retrieve()), diffs against the vendored values, and prints a report. Never applies silently — pass --apply to write. Requires the anthropic package (pip install "llm-rates[refresh]") and a resolvable Anthropic credential (ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, or an ant auth login profile) — never falls back to a guessed value if no credential resolves. Run manually; not wired into any scheduled job. lookup()/cost() never import this module or touch the network — see "Context-window data" below.
  • generate_tokenator_table.py — emits a plain JSON price table shaped for tokenator.ps1 (a models map of {input, output, context} per model id, plus flat cache_read_multiplier/cache_write_multiplier and a default row) from catalog.json + overlay.json, so that repo can hold a generated copy instead of a hand-maintained one. Deterministic — the same inputs always produce byte-identical output.

Usage

from llm_rates import lookup, cost, UnknownModelError

record = lookup("claude-sonnet-5")
record.input          # 2.0   ($/MTok)
record.output          # 10.0  ($/MTok)
record.source           # "catalog"
record.context           # 1000000 (context-window token limit, or None)

# A client-side "[1m]" resolvedModel signal (not a vendor id — see
# overlay.json's aliases) resolves to the same price and, as of 2026-08-21,
# the same context — the base id already reports the model's real
# 1,000,000-token window:
lookup("claude-sonnet-5[1m]").context   # 1000000

# One-shot cost for a turn:
usd = cost(
    "claude-opus-4-8",
    input_tokens=12_000,
    output_tokens=800,
    cache_read_tokens=50_000,
)

# An unrecognised model still resolves at its family rate:
lookup("claude-opus-4-9").source   # "overlay-family-fallback"

# A genuinely unknown vendor/model raises instead of returning $0:
try:
    lookup("some-new-vendor/mystery-model")
except UnknownModelError as e:
    ...

lookup() and cost() both accept optional catalog=/overlay= kwargs (already-loaded dicts) — useful for tests, or for a caller that wants to load once and reuse across many lookups instead of re-reading the JSON files each call.

Refreshing the catalog

python refresh.py            # pull live litellm catalog, diff, print report
python refresh.py --apply    # also overwrite catalog.json with the diff

refresh.py always pulls the live GitHub-hosted catalog URL, never the litellm pip package's bundled snapshot — that bundled copy is stale (it was missing Haiku 4.5, Opus 5, Opus 4.8, Fable 5, and Sonnet 5 entirely as of 2026-07-28; see the plan doc's "Two traps found").

Refreshing context-window data

python refresh_context.py            # pull the live Models API, diff, print report
python refresh_context.py --apply    # also overwrite catalog.json with the diff

Context-window limits (max_input_tokens) and output caps (max_output_tokens) for Anthropic-provider rows come from Anthropic's own Models API (client.models.retrieve(model_id)), not litellm's snapshot — litellm is a third-party-maintained guess for these fields, and it was wrong at least once (see "Pricing notes worth knowing" below). lookup() itself never calls this API: it's a refresh-time-only script, exactly like refresh.py, that writes into the vendored catalog.json, so lookup()/cost() stay pure and offline (they price historical transcripts and run behind a PowerShell overlay with no network access). Requires pip install "llm-rates[refresh]" (the anthropic SDK) and a credential the SDK's own resolution chain can find (ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN/ant auth login) — with none resolvable, the script fails with an actionable message and writes nothing, never a guessed value.

Generating tokenator's pricing table

python generate_tokenator_table.py            # print to stdout
python generate_tokenator_table.py --out FILE  # write to FILE

This is a read-only export — it never touches plugin's checkout. The consumer migration that adopts the generated bytes as tokenator/pricing.json is tracked separately. Before emitting anything, the generator proves (via verify_cache_multipliers()) that its flat cache multipliers (0.1x read, 2.0x write of input — tuned to Claude Code's 1h-TTL cache behaviour) match this package's real per-model cache rates for every model tokenator prices; a divergence raises instead of silently drifting.

Pricing notes worth knowing

  • claude-sonnet-5 is $2.00/$10.00 per MTok, permanently — not a time-limited introductory rate. It was announced as an introductory price through 2026-08-31, but the vendor cancelled the scheduled 2026-09-01 rise to $3.00/$15.00 (~2026-08-17). See overlay.json's notes.
  • Groq OSS models list at $0.075–$0.29/MTok but bill $0.00 on the portfolio's free-tier key — the vendor list price lives in catalog.json, the actual billed rate lives in overlay.json's actual_billing_overrides. Both are correct; they answer different questions.
  • A retired/de-listed model keeps its row. claude-opus-4-1 (retired 2026-08-05) and the Groq-delisted llama-4-scout/qwen3-32b entries stay priced at their historical rate so old transcripts still reprice correctly — deleting a row would silently re-price past usage at whatever family-fallback rate happens to apply now.
  • claude-fable-5, claude-opus-5, and claude-sonnet-5 all serve 1,000,000 tokens of context, natively — confirmed by Anthropic's own Models API. A prior overlay.json context_overrides block forced all three to 200,000 (on the mistaken theory that catalog.json's max_input_tokens=1000000 was an extended-context-beta-only ceiling); that override has been removed (corrected 2026-08-21, C8). Only claude-haiku-4-5 among current Claude models genuinely has a 200,000-token window.

Setup for consumers

pip install -e C:/data/projects/libs/llm-rates

Same convention as libs/plan-doc and libs/triad-base — see plugin/CLAUDE.md.

Status

Rollout step 1 of model-catalog-consolidation.md — the library itself, built and tested. Consumer migrations (activity_cost.py, sessmon, model-bench-runner.py, tokenator.ps1) are steps 2–5, tracked separately in the plan doc and out of scope for this package's initial PR.

Testing

pytest llm-rates/tests/ -v

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llm_rates-0.3.1.tar.gz (34.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llm_rates-0.3.1-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

Details for the file llm_rates-0.3.1.tar.gz.

File metadata

  • Download URL: llm_rates-0.3.1.tar.gz
  • Upload date:
  • Size: 34.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for llm_rates-0.3.1.tar.gz
Algorithm Hash digest
SHA256 79e2fd9e9f5795d120f8984d17e27d2ba2f0cd8ab2ed908de7921a7980a73723
MD5 3c60f489e3ae0655ec4118f1f09611f7
BLAKE2b-256 cf1cd7428af76ca7c70a5fd3267a3bafee21a798c6ec1dfb18c17db86a7d2517

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_rates-0.3.1.tar.gz:

Publisher: release-llm-rates.yml on m0j0d/libs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file llm_rates-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: llm_rates-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 26.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for llm_rates-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f2fa8f81f923c9c705c97ef85be7ea826b18f8aaf3f829bf0cbe090d58746fa5
MD5 34b970533d16ad0f845ffe54f66fa372
BLAKE2b-256 2f6be741428b086ccd6bd5166bb5e964e92237525dfa567d52ca0ebe22b8c529

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_rates-0.3.1-py3-none-any.whl:

Publisher: release-llm-rates.yml on m0j0d/libs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

This release

0.3.1 This release

2 files

0.3.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page