Skip to content

Cache Savings Calculator — TypeScript source

See what prompt caching saves — uncached vs cached cost over N requests, with the write-premium break-even point.

This is the TypeScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

/**
 * Pure cache-savings math for the Cache Savings Calculator. All rates flow
 * from the model snapshot accessor (src/lib/ai/models.ts) — never hardcoded
 * here. Mirrors the cost conventions of llmCost.ts (per-1M-token USD rates).
 */
import type { AiModel } from './ai/models';

export interface CacheInput {
  /** Prompt (input) tokens per request. */
  promptTokens: number;
  /** Completion (output) tokens per request. */
  outputTokens: number;
  /** Requests that reuse the cached prompt. Values < 1 are treated as 1. */
  hits: number;
}

export interface CacheMath {
  /** hits × (prompt·in$/M + output·out$/M) / 1e6. */
  uncached: number | null;
  /** (prompt·write$/M + hits × (prompt·read$/M + output·out$/M)) / 1e6 —
   *  one cache write, `hits` cache reads, output billed every request. */
  cached: number | null;
  /** uncached − cached (negative when caching costs more). */
  savings: number | null;
  /** savings / uncached × 100; 0 when uncached is 0. */
  savingsPct: number | null;
  /** ceil(write$/M / read$/M) when read$/M > 0 — cache hits needed for
   *  cumulative READ spend to equal ONE write premium; null otherwise. */
  breakEvenHits: number | null;
}

const nulled = (): CacheMath => ({
  uncached: null,
  cached: null,
  savings: null,
  savingsPct: null,
  breakEvenHits: null,
});

/**
 * Compare uncached vs prompt-cached cost for one model. Any missing rate
 * (input, output, cacheRead, cacheWrite) makes every field null — the caller
 * renders an explanatory empty state instead of partial math.
 */
export function cacheMath(model: AiModel, input: CacheInput): CacheMath {
  const { inputPerM: ipM, outputPerM: opM, cacheReadPerM: cr, cacheWritePerM: cw } = model;
  if (ipM === null || opM === null || cr === null || cw === null) return nulled();

  const hits = Math.max(1, input.hits);
  const inT = input.promptTokens;
  const outT = input.outputTokens;

  const uncached = (hits * (inT * ipM + outT * opM)) / 1_000_000;
  const cached = (inT * cw + hits * (inT * cr + outT * opM)) / 1_000_000;
  const savings = uncached - cached;
  const savingsPct = uncached === 0 ? 0 : (savings / uncached) * 100;
  const breakEvenHits = cr > 0 ? Math.ceil(cw / cr) : null;

  return { uncached, cached, savings, savingsPct, breakEvenHits };
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →