refactor(opencode): one price mapper for catalog and config cost tiers
Follow-up to #34, applying the simplification patch Andrew posted in Slack verbatim. No merge until Andrew and Gabe have reviewed.
Context
#34 landed the tiered-pricing fix with four hand-written mappings from models.dev / config cost shapes (cache_read, cache_write) to the model's { input, output, cache }, and the config merge still set experimentalOver200K alongside the 200K tier it synthesizes from a config context_over_200k, contradicting the converter's rule that the legacy field exists only when a model has no tiers.
Changes
- One
price()mapper handles base cost, catalog tiers, the catalog'scontext_over_200k, and a configcontext_over_200k. - The merge sets
experimentalOver200Ktoundefinedwhenever it synthesizes the 200K tier, so catalog-only and config-named models follow the same rule. - Every comment is one line.
- The two config-override tests collapse into one that covers
openai/gpt-5.4(catalog tier at 272K replaced by the 200K tier) andx-ai/grok-4(catalog tier at 128K kept below it), priced throughSession.getUsageat 150K and 300K.
Testing Done
cd packages/opencode && bun test test/provider/provider.test.ts: 97 pass (one fewer test than #34 by design).bun run typecheckinpackages/opencode: clean.- Behavior is unchanged from #34 except that a config-override model now reports
experimentalOver200K: undefinednext to its tiers, whichSession.getUsagenever read in that case.
Patch by Andrew Wang, from the Slack thread on #34.
š¤ Generated with Claude Code
Summary by cubic
Uses one price() mapper to normalize catalog and config cost tiers. Previously, a config context_over_200k override populated both a synthesized 200K tier and experimentalOver200K; now it creates only the tier and clears the legacy field, while usage pricing remains unchanged.
Refactors
- Reuses
price()for base costs, catalog tiers, and long-context overrides. - Tests cover replacing the
openai/gpt-5.4catalog tier and retaining the lowerx-ai/grok-4tier. - Provider tests pass, and package typechecking is clean.