Skip to content

feat: serve per-category price_details (cached, cache_creation, audio) - #5

Merged
viniciusdsmello merged 2 commits into
mainfrom
vini/open-11150-per-category-price-details
Jun 5, 2026
Merged

feat: serve per-category price_details (cached, cache_creation, audio)#5
viniciusdsmello merged 2 commits into
mainfrom
vini/open-11150-per-category-price-details

Conversation

@viniciusdsmello

Copy link
Copy Markdown
Contributor

What & why

Adds an open price_details map ({token_category: cost_per_token}) to the cost records, alongside the existing scalar prompt_cost_per_token / completion_cost_per_token. This lets the Openlayer platform's cost engine price granular token categories (cached reads, cache creation, audio) per category — the upstream half of OPEN-11148 / OPEN-11150. The platform already reads price_details as an optional field, so once this deploys, global per-category prices flow through automatically.

Canonical keys (contract)

The price_details keys are a contract matched by name to a request's usageDetails (SDK) and the platform's price map:

Canonical key LiteLLM field OpenRouter pricing
input_tokens input_cost_per_token prompt
output_tokens output_cost_per_token completion
cached_tokens cache_read_input_token_cost input_cache_read
cache_creation_tokens cache_creation_input_token_cost input_cache_write
audio_input_tokens input_cost_per_audio_token
audio_output_tokens output_cost_per_audio_token

Reasoning is intentionally omitted — it's billed at the output rate and already counted within output_tokens, so it carries no separate price (producers surface it as an informational usage-only category). Per-token categories only; non-token costs (web search per-query, file search per-call, code interpreter per-session, vector store per-GB-day) are out of scope for now.

Changes

  • entities / models (JSON column, 004 migration) / schemas / repositories / api: thread price_details through. JSON maps to JSONB on Postgres and JSON on the SQLite test env; nullable for back-compat (read as {}).
  • providers: extract per-category fields → canonical keys in both LiteLLM and OpenRouter providers.

Backward compatibility

Purely additive — the two scalars stay, price_details is nullable and defaults to {}. Consumers that ignore it are unaffected.

Verification

  • 101 tests pass.
  • Live LiteLLM extraction across 2271 models: gpt-4o → input/output/cached; gpt-4o-audio-preview → + audio_input/audio_output; o1 → input/output/cached (no reasoning price, as intended). Key coverage: cached=568, cache_creation=197, audio_input=111, audio_output=48.

🤖 Generated with Claude Code

Adds an open `price_details` map ({token_category: cost_per_token}) alongside the
scalar prompt/completion costs, so consumers (Openlayer platform cost engine) can
price granular token categories. Keys are a canonical contract matched by name to
a request's usageDetails.

Sources → canonical keys:
- LiteLLM: input_cost_per_token→input_tokens, output_cost_per_token→output_tokens,
  cache_read_input_token_cost→cached_tokens,
  cache_creation_input_token_cost→cache_creation_tokens,
  input_cost_per_audio_token→audio_input_tokens,
  output_cost_per_audio_token→audio_output_tokens.
- OpenRouter pricing: prompt/completion/input_cache_read/input_cache_write.

Reasoning is intentionally omitted: it is billed at the output rate and already
counted within output_tokens, so it carries no separate price (surfaced as an
informational usage-only category by producers).

- entities/models/schemas/repositories/api: thread price_details through; JSON
  column (JSONB on PG, JSON on the SQLite test env), nullable for back-compat,
  read as {} when null. Additive — the two scalars stay; consumers that ignore
  the field are unaffected.
- alembic 004: add nullable price_details column.

Verified: 101 tests pass; live LiteLLM extraction across 2271 models
(cached=568, cache_creation=197, audio_input=111, audio_output=48).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jun 5, 2026

Copy link
Copy Markdown
OPEN-11150 Backend: per-key cost computation

Part of OPEN-11148. Depends on OPEN-11149.

Extend model price definitions with per-category prices; compute costDetails + total by summing usageDetails[key] × price[key].

Acceptance criteria

  • Cached reads priced at their discounted rate; cache-creation tokens priced at their surcharge; reasoning tokens priced.
  • costDetails is populated per category and total cost matches provider billing within tolerance.
  • Models without per-category prices fall back gracefully to current behavior.

Review in Linear

@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
llm-cost-service Ready Ready Preview, Comment Jun 5, 2026 3:06pm

Request Review

@gustavocidornelas gustavocidornelas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good. Added just a small comment. Feel free to merge after addressing it

Also, it'd be good if you could add unit tests for _coerce_price and _build_price_details (just because the rest of the methods overall are all tested).

Comment thread service/costs/providers.py
…t tests

Address review (gustavocidornelas):
- Drop input_tokens/output_tokens from price_details — they duplicated the root
  prompt_cost_per_token/completion_cost_per_token. price_details now carries only
  the granular extras (cached, cache_creation, audio). Consumers reuse the root
  scalars for base input/output rates.
- Add unit tests for _coerce_price and _build_price_details, plus provider-level
  checks that price_details carries only extras (empty for basic models).
@viniciusdsmello
viniciusdsmello merged commit e517764 into main Jun 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants