Skip to content

fix(opencode): price long-context steps at the catalog tier, including config-named models - #34

Merged
goleary merged 6 commits into
devfrom
merge-tier-cost
Sep 2, 2026
Merged

goleary merged 6 commits into
devfrom
merge-tier-cost

Conversation

@goleary

@goleary goleary commented Sep 2, 2026 •

Copy link
Copy Markdown

Steps that run above a model's long-context threshold are now priced at the provider's tier instead of the base rate, so the cost recorded on each assistant message matches what OpenRouter actually bills. The threshold is per model: OpenRouter's pricing.overrides starts at 272K for openai/gpt-5.6-terra and openai/gpt-5.4, at 200K for google/gemini-3.1-pro-preview, and anthropic/claude-sonnet-5 has none.

Context

Replo's sandbox config declares every selectable model under provider.openrouter.models (most entries are just { options: {} }). When a config entry names a model that also exists in the models.dev catalog, the merge in provider.ts rebuilds cost from input, output and cache only — tiers and experimentalOver200K never make it onto the merged model, even though the catalog carried them and session.ts would have used them.

Found while comparing GPT-5.6 Terra to Sonnet on the agent-models dashboard: our recorded Terra cost fit flat base pricing to six decimals across 2,229 steps, while OpenRouter's analytics API billed the >200K tier. Recomputing our steps with the tier landed within 5% of the invoice; flat was 18% short. Pairs with replohq/andytown#26545, which pins a 200K compaction ceiling so Terra stops reaching the tier in the first place; this change keeps the cost honest for any model that still does.

Changes

  • The config merge carries tiers from the catalog model, so a config entry that only names a model prices its long-context steps at the catalog tier.
  • When a config entry supplies its own context_over_200k, that price has to win everywhere above 200K, but Session.getUsage consults tiers before experimentalOver200K. The merge keeps catalog tiers below 200K and carries the configured price as a 200K context tier above them, the same shape the v1 config migration uses. The override maps through the existing cost() converter.
  • models.dev spells a model's single long-context tier as context_over_200k even when its tiers put the threshold at 272K, and Session.getUsage falls back to that field below the tier size, so a 250K step on gpt-5.x was priced at the tier rate while OpenRouter bills it at base. The catalog converter now sets experimentalOver200K only when the model has no tiers, which keeps catalog-only and config-named models in agreement. Upstream tracks this as Local cost estimate uses the 200k price below a model's real context threshold anomalyco/opencode#44224.

Testing Done

  • Three new it.instance cases in test/provider/provider.test.ts, each priced through Session.getUsage: a config entry that only names openrouter/openai/gpt-5.4 keeps the fixture's 272K tier, drops the legacy field, and prices 250K tokens at base and 300K at the tier; a config entry with its own context_over_200k replaces the catalog's 272K tier with a 200K tier and prices 300K at the configured rate; a config override on x-ai/grok-4 keeps the fixture's 128K tier and prices 100K, 150K and 300K at base, 128K-tier and configured rates. Each fails without its source change.
  • Full provider test file: 98 pass. bun run typecheck clean.

No release is cut here; this lands in the next v1.17.14-N tag per RELEASING.md, and the andytown Dockerfile and sandbox-upgrader pins move separately.


Devin Review

Summary by cubic

Model cost merging now follows each provider’s context-tier thresholds instead of pricing config-named models at the base rate or applying long-context pricing too early. A configured context_over_200k price becomes the 200K tier while preserving catalog tiers below it.

  • Catalog context_over_200k is used only when the model has no explicit context tiers.
  • Provider tests cover pricing at 100K, 150K, 250K, and 300K context; bun run typecheck passes.

Written for commit 34663af. Summary will update on new commits.

Review in cubic

A config entry that names a catalog model rebuilt cost from input, output
and cache only, dropping the catalog's tiers and experimentalOver200K, so
every step above 200K context was priced at the base rate. Carry both
through, and map a config context_over_200k when one is given.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

The following comment was made by an LLM, it may be inaccurate:

devin-ai-integration[bot]

This comment was marked as resolved.

cubic-dev-ai[bot]

This comment was marked as resolved.

…k itself

Session.getUsage consults cost.tiers before experimentalOver200K, so a
config entry that supplied its own context_over_200k would still be
priced at the catalog tier above that tier's size. When config prices
the long-context range itself, the merged model now carries no catalog
context tiers, and the override test asserts the price through
Session.getUsage at 300K tokens.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@goleary

goleary commented Sep 2, 2026

Copy link
Copy Markdown
Author

/devin review

@devin-ai-integration

Copy link
Copy Markdown

Starting Devin Review.

Devin Review

…g cost converter

The config cost shape is a structural subset of the models.dev cost, so
the existing cost() helper builds experimentalOver200K instead of a
second hand-copied mapping.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@goleary

goleary commented Sep 2, 2026

Copy link
Copy Markdown
Author

/devin review

@devin-ai-integration

Copy link
Copy Markdown

Starting Devin Review.

Devin Review

devin-ai-integration[bot]

This comment was marked as resolved.

… price

Dropping every catalog tier lost sub-200K tiers such as grok-4's 128K
tier, while keeping them would let them outrank the configured price
above 200K because Session.getUsage consults tiers first. The config
context_over_200k is now carried as a 200K context tier above the
catalog tiers below it, mirroring the v1 config migration. Covered at
100K, 150K and 300K tokens against the fixture's x-ai/grok-4.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@goleary

goleary commented Sep 2, 2026

Copy link
Copy Markdown
Author

/devin review

@devin-ai-integration

Copy link
Copy Markdown

Starting Devin Review.

Devin Review

…er-200k field

models.dev spells a model's single long-context tier as context_over_200k
even when its tiers place the threshold elsewhere: OpenRouter's override
for openai/gpt-5.4 and gpt-5.6-terra starts at 272K, Gemini 3.1 Pro at
200K. Session.getUsage consults tiers first but falls back to
experimentalOver200K below the tier size, so a 250K-token step on gpt-5.x
was priced at the tier rate while OpenRouter bills it at base. The
catalog converter now sets experimentalOver200K only when the model has
no tiers, which makes catalog-only and config-named models agree. Tracks
the same defect as anomalyco#44224.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@goleary

goleary commented Sep 2, 2026

Copy link
Copy Markdown
Author

/devin review

@devin-ai-integration

Copy link
Copy Markdown

Starting Devin Review.

Devin Review

@goleary goleary changed the title fix(opencode): keep over-200k cost tiers through the config model merge fix(opencode): price long-context steps at the catalog tier, including config-named models Sep 2, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@goleary

goleary commented Sep 2, 2026

Copy link
Copy Markdown
Author

/devin review

@devin-ai-integration

Copy link
Copy Markdown

Starting Devin Review.

Devin Review

@goleary
goleary merged commit d19fb91 into dev Sep 2, 2026
13 of 14 checks passed
goleary added a commit that referenced this pull request Sep 2, 2026
#35)

Andrew's simplification of #34: a single price() maps models.dev and config cost shapes to {input, output, cache}, the merge no longer sets experimentalOver200K alongside a config-derived 200K tier, and the two override tests collapse into one covering gpt-5.4 and grok-4.

Co-Authored-By: Andrew Wang <andrew@replo.app>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant