Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ function defineModel(opts: {
}
}

// Per-token costs derived from Anthropic per-million-token pricing.
// Costs in US dollars per MILLION tokens, matching Anthropic's published
// pricing verbatim. This is the unit opencode and models.dev use: opencode
// divides by 1e6 itself when it multiplies a cost by a token count, so writing
// per-token values here under-reports session cost by exactly 1,000,000x.
// Compare models.dev's own entry for the same model:
// `anthropic/claude-haiku-4-5 -> {"input": 1, "output": 5, "cache_read": 0.1,
// "cache_write": 1.25}`.
//
// There is no long-context premium to model. Anthropic's pricing page states
// that Claude 4.6 and later ship the full 1M-token context window at standard
Expand All @@ -70,18 +76,18 @@ function defineModel(opts: {
// fields for above-200K pricing; they stay unset here deliberately, because a
// tier would misreport the real price. Re-check only if Anthropic introduces
// one. Verified against the pricing docs 2026-07-26.
const haikuCost = { input: 1e-6, output: 5e-6, cacheRead: 1e-7, cacheWrite: 1.25e-6 }
const sonnetCost = { input: 3e-6, output: 15e-6, cacheRead: 3e-7, cacheWrite: 3.75e-6 }
const haikuCost = { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }
const sonnetCost = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }
// Introductory pricing through August 31, 2026. Standard pricing from September
// 1 is the same $3/M input and $15/M output as the other Sonnet models.
const sonnet5Cost = { input: 2e-6, output: 10e-6, cacheRead: 2e-7, cacheWrite: 2.5e-6 }
const sonnet5Cost = { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }
// Opus 4.5+ standard pricing is $5/M in, $25/M out (the price cut at 4.5; held
// through 4.6/4.7/4.8/5). Cache read 0.1x input, cache write 1.25x input.
const opusCost = { input: 5e-6, output: 25e-6, cacheRead: 0.5e-6, cacheWrite: 6.25e-6 }
const opusCost = { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }
// Fable 5 and Mythos 5 are the Mythos-class tier above Opus and share pricing
// ($10/M in, $50/M out). Cache read/write follow Anthropic's standard 0.1x / 1.25x
// input ratios (not separately published).
const fableCost = { input: 10e-6, output: 50e-6, cacheRead: 1e-6, cacheWrite: 12.5e-6 }
const fableCost = { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }

/**
* Convert an OpenCodeModel to the flat config schema that OpenCode's
Expand Down
17 changes: 9 additions & 8 deletions test-config-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ test("configModelsForProvider registers Sonnet 5 and Opus 5 metadata", () => {
assert.equal(sonnet.release_date, "2026-06-30")
assert.equal(sonnet.reasoning, true)
assert.deepEqual(sonnet.limit, { context: 1_000_000, output: 128_000 })
// Dollars per million tokens, the unit opencode/models.dev expect.
assert.deepEqual(sonnet.cost, {
input: 2e-6,
output: 10e-6,
cache_read: 2e-7,
cache_write: 2.5e-6,
input: 2,
output: 10,
cache_read: 0.2,
cache_write: 2.5,
})

const opus = models["claude-opus-5"] as Record<string, unknown>
Expand All @@ -101,10 +102,10 @@ test("configModelsForProvider registers Sonnet 5 and Opus 5 metadata", () => {
assert.equal(opus.reasoning, true)
assert.deepEqual(opus.limit, { context: 1_000_000, output: 128_000 })
assert.deepEqual(opus.cost, {
input: 5e-6,
output: 25e-6,
cache_read: 0.5e-6,
cache_write: 6.25e-6,
input: 5,
output: 25,
cache_read: 0.5,
cache_write: 6.25,
})

assert.ok("max" in (sonnet.variants as Record<string, unknown>))
Expand Down