Cache Savings Calculator — Go source
See what prompt caching saves — uncached vs cached cost over N requests, with the write-premium break-even point.
This is the Go implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Package cachingsavings is the Go twin of CosmoDev's src/lib/cacheSavings.ts
// (dual source: the web lib is TypeScript, the CLI lib is Go — kept in
// lock-step). All rates flow from the model snapshot accessor
// (cosmodev/aimodels) — never hardcoded here — mirroring the cost conventions
// of the llmcost twin (per-1M-token USD rates). Pure + deterministic, never
// panics: any missing rate nulls every field, mirroring the TS lib's nulled()
// empty state. The table-driven tests in cache-savings-calculator_test.go
// share vectors with src/lib/cacheSavings.test.ts so the two implementations
// are held to the same contract.
package cachingsavings
import (
"math"
"cosmodev/aimodels"
)
// CacheInput describes one cached workload. It mirrors the CacheInput
// interface in src/lib/cacheSavings.ts.
type CacheInput struct {
PromptTokens int // prompt (input) tokens per request
OutputTokens int // completion (output) tokens per request
Hits int // requests that reuse the cached prompt; values < 1 are treated as 1
}
// CacheMathResult is the uncached-vs-cached comparison for one model. Pointer
// fields are nil when the TS lib yields null: an unpriced model nulls every
// field, and BreakEvenHits alone is nil when the cache-read rate is 0. It
// mirrors the CacheMath interface in src/lib/cacheSavings.ts.
type CacheMathResult struct {
Uncached *float64 // hits × (prompt·in$/M + output·out$/M) / 1e6
Cached *float64 // (prompt·write$/M + hits × (prompt·read$/M + output·out$/M)) / 1e6 — one cache write, `hits` cache reads, output billed every request
Savings *float64 // uncached − cached (negative when caching costs more)
SavingsPct *float64 // savings / uncached × 100; 0 when uncached is 0
BreakEvenHits *int // ceil(write$/M / read$/M) when read$/M > 0 — cache hits needed for cumulative READ spend to equal ONE write premium; nil otherwise
}
// CacheMath compares uncached vs prompt-cached cost for one model. Any
// missing rate (input, output, cacheRead, cacheWrite) makes every field nil —
// the caller renders an explanatory empty state instead of partial math. It
// is the Go twin of cacheMath() in src/lib/cacheSavings.ts and must agree
// with it on every shared vector.
func CacheMath(m *aimodels.Model, input CacheInput) CacheMathResult {
if m == nil || m.InputPerM == nil || m.OutputPerM == nil ||
m.CacheReadPerM == nil || m.CacheWritePerM == nil {
return CacheMathResult{}
}
ipM, opM := *m.InputPerM, *m.OutputPerM
cr, cw := *m.CacheReadPerM, *m.CacheWritePerM
hits := max(1, input.Hits)
inT := float64(input.PromptTokens)
outT := float64(input.OutputTokens)
uncached := (float64(hits) * (inT*ipM + outT*opM)) / 1e6
cached := (inT*cw + float64(hits)*(inT*cr+outT*opM)) / 1e6
savings := uncached - cached
savingsPct := 0.0
if uncached != 0 {
savingsPct = savings / uncached * 100
}
var breakEven *int
if cr > 0 {
n := int(math.Ceil(cw / cr))
breakEven = &n
}
return CacheMathResult{
Uncached: &uncached,
Cached: &cached,
Savings: &savings,
SavingsPct: &savingsPct,
BreakEvenHits: breakEven,
}
}
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 →