Skip to content

Fix model pricing by selecting best provider and deriving cache prices - #12

Merged
GoJam11 merged 1 commit into
mainfrom
claude/model-pricing-cache-logic-otw8dk
Jul 31, 2026
Merged

Fix model pricing by selecting best provider and deriving cache prices#12
GoJam11 merged 1 commit into
mainfrom
claude/model-pricing-cache-logic-otw8dk

Conversation

@GoJam11

@GoJam11 GoJam11 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

This PR fixes a critical issue where model pricing data was being incorrectly overwritten by secondary resellers, resulting in missing cache pricing information. The fix implements intelligent provider selection, cache price backfilling, and fallback pricing derivation across the entire pricing pipeline.

Root Cause

The models.dev API exposes the same model ID (e.g., claude-opus-4-6) across 170+ providers. The previous implementation simply overwrote pricing with each provider encountered, meaning the final pricing came from whichever provider was last in the iteration order. This frequently resulted in secondary resellers' incomplete pricing (missing cache_read/cache_write fields) overwriting official provider data, causing cache operations to be billed at $0.

Key Changes

Model Catalog (src/model-catalog.ts)

  • New buildCatalogMapsFromModelsDev() function: Replaces simple overwriting with intelligent provider selection
    • Ranks providers by trustworthiness (official/first-party providers prioritized)
    • Scores candidates based on pricing completeness and cache field availability
    • Selects the best candidate per model ID
    • Backfills missing cache_read/cache_write from other providers with identical base pricing
    • Validates all numeric fields (rejects negative values, non-numbers, missing required fields)

Pricing Calculation (src/pricing.ts)

  • New resolveEffectiveCachePricing() function: Derives cache prices when upstream data is incomplete
    • Anthropic: cache_read = 0.1× input, 5m cache_write = 1.25× input, 1h cache_write = 2× input
    • OpenAI: cached_input = 0.1× input, no separate cache write fee
    • Marks derived prices with cache_pricing_derived flag for transparency
  • TTL-aware cache write billing: Splits cache_creation_input_tokens into 5m and 1h buckets using new ephemeral_5m_input_tokens/ephemeral_1h_input_tokens fields
  • Enhanced CostBreakdown: Adds cache_write_5m_tokens, cache_write_1h_tokens, and actual billing prices (cache_read_price, cache_write_5m_price, cache_write_1h_price)

Database (src/catalog-db.ts)

  • Fixed onConflictDoUpdate to reference excluded.* (new values) instead of existing columns, ensuring refresh updates actually persist

Console Frontend

  • Models page: Added cache pricing columns with improved formatting (preserves significant digits for sub-$1 prices)
  • Cost breakdown display: Shows actual billing prices (with "(推导)" suffix for derived prices), splits 1h cache writes into separate formula rows
  • Usage aggregation: Tracks ephemeral_5m/1h fields for consistent cost reporting

Impact

For a typical high-cache-hit request with claude-opus-4-6:

  • Before: $0.000385 (only input/output tokens billed, cache tokens at $0)
  • After: $0.033009 (correct billing: input $0.000010 + output $0.000375 + cache_read $0.027387 + cache_write $0.005237)

Affected ~1,606 of 2,652 models that were falling back to incomplete secondary reseller pricing.

Testing

Added comprehensive test suite (test/model-catalog-pricing.test.ts) covering:

  • First-party provider preference over resellers
  • Cache price backfilling from same-price providers
  • Rejection of mismatched base prices
  • Free/placeholder entry handling
  • Malformed data validation
  • Context window fallback behavior

https://claude.ai/code/session_011a12zJk3jbzU6orYUtiD4X

models.dev 的同一个裸模型 ID 挂在 176 个 provider 下,原解析直接
pricingMap.set(modelId, cost) 一路覆盖,最后遍历到谁用谁:2652 个有价模型里
1606 个落到了没有 cache_read/cache_write 字段的二级经销商条目上,缓存 token
全部按 0 单价计费。一条 cache_read=54773 的请求只收 $0.000385。

- model-catalog: 新增 buildCatalogMapsFromModelsDev(),同模型多 provider 改为
  按「官方 provider 优先 → 有真实价格优先 → 缓存字段完整优先」择优,并从基础
  价格一致的条目回填缺失的缓存单价;对 cost/limit 做数值校验
- catalog-db: onConflictDoUpdate 的 set 引用的是已存在行的列(等于把旧值写回
  自己),冲突时整行不更新,坏价格会被永久缓存;改为引用 excluded.*
- pricing: 上游缺缓存单价时按官方比例从 input 推导兜底(读 0.1x / 写 1.25x /
  1h 写 2x),并用 ephemeral_5m/1h 把缓存写入按 TTL 分档计费;CostBreakdown
  暴露实际计费单价与 TTL 分档 token 数
- console-store: 用量聚合与时间序列补上 ephemeral_5m/1h 字段
- console: Models 页新增缓存读/写价格列,成本公式改用实际计费单价并拆分 5m/1h

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011a12zJk3jbzU6orYUtiD4X
@GoJam11
GoJam11 merged commit 2739ac6 into main Jul 31, 2026
1 check 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