Repository navigation
fix(core): price Copilot long-context tiers and cache writes - #59803
golfromeo-fr wants to merge 3 commits into
Conversation
Copilot's /models payload exposes per-request price tiers (default plus long_context with its own prices and max_prompt_tokens) and a cache_write_price, but the model builder read only the default tier and hardcoded cache writes to zero, and both usage adapters dropped cache_write_tokens entirely. Long sessions on tiered models like Claude Haiku 5.5 were undercounted ~6x. The builder now emits the cache write price and a context-tier cost entry bounded by the default tier's max_prompt_tokens, which SessionUsage.calculateCost already applies per request. Both Copilot adapters map cache_write_tokens (or Anthropic-style cache_created_input_tokens) into cacheWrite and keep the non-cached input consistent with the total.
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
There was a problem hiding this comment.
This looks good to merge. I ran the #52089 reproduction (a local mock of Copilot's /models and /responses) on the base and with this change:
- Prices: cache writes go from $0 to $5/M, and a long-context tier is added above
default.max_prompt_tokens. - Usage: the Responses generate and stream paths now report
cacheWrite: 8270andnoCache: 3, where the base reported nocacheWriteandnoCache: 8273.
The tier boundary matches how SessionUsage.calculateCost picks tiers (input plus cache reads plus cache writes, strictly above the boundary). The Copilot and session-usage tests pass. I couldn't run the package type check in this environment.
Public API is unchanged: only the internal parsing of Copilot's /models and usage responses changes.
One small point is inline: the new session-usage.test.ts cases exercise unchanged code and can be dropped.
| }) | ||
| }) | ||
|
|
||
| // GitHub Copilot's Claude Haiku 5.5 rate card: a per-request tier above 100K prompt tokens at 5x. |
There was a problem hiding this comment.
These four cases test SessionUsage.calculateCost, which this PR doesn't change, and they pass on the base too. The new coverage is the tier and cache-write prices from CopilotModels, which models.test.ts already checks. Could you drop these so the change stays focused?
There was a problem hiding this comment.
Done in 238a59b — dropped the session-usage.test.ts cases. The changed code stays covered by the builder and adapter tests.
Review feedback on anomalyco#59803: the tier and cache-write pricing behavior they pinned lives in SessionUsage.calculateCost, which this PR does not change, and the changed code is already covered by the builder and adapter tests.
There was a problem hiding this comment.
The new commit removes the session-usage.test.ts cases I flagged, which addresses my earlier comment. It changes nothing else. I re-ran the Copilot tests and the #52089 and #51845 reproductions at this head: cache-write prices, the long-context tier and the cacheWrite/noCache mapping are all correct. No new concerns. The public API is unchanged.
There was a problem hiding this comment.
The new commit only merges dev. I checked that the PR's own changes are the same as before and that the merged dev commits don't touch the Copilot provider or the cost calculation. I re-ran the Copilot tests and the #52089 and #51845 reproductions at this head, and all are still fixed. My earlier test comment was addressed in the previous push. No new concerns, and the public API is unchanged.
Issue for this PR
Closes #52089
Closes #59671
Type of change
What does this PR do?
GitHub Copilot costs were undercounted badly on long sessions. In my case (#59671): a 3h session on Copilot / Claude Haiku 5.5, 348 requests, ~344K average context, OpenCode showed $1.56 when the real bill is roughly $9.34 (between $2.03 and $10.15, since Copilot picks the price tier per request by prompt size).
Two causes, both in the Copilot provider code:
/modelspayload ships two price tiers (defaultandlong_context, the latter starting abovedefault.max_prompt_tokens). The builder only read the default tier.cache_write_priceis in the payload, unread), and both usage adapters droppedcache_write_tokens, so cache writes weren't counted at all.Pricing that session's totals at the ≤100K rates with free writes gives $1.5557 — cent-exact with the displayed $1.56, which is how I know exactly which rates the old code applied.
The builder now emits the write price and a context-tier cost entry, which
SessionUsage.calculateCostalready applies per request, so no calculator change was needed. The adapters mapcache_write_tokensintocacheWrite. While there I replaced their hand-rollednoCachearithmetic withProviderShared.subtractTokens/sumTokenslike the shared protocols use: three of the four paths leftnoCacheundefined on responses without cache details, which downstream prices the entire prompt at $0, and none of them clamped against broken breakdowns.Deliberately not addressed: Copilot's own reported billed amount (#35765) and the richer
pricingshape from #59460.How did you verify your code works?
New unit tests against the Copilot rate card for Claude Haiku 5.5: long-context tier applies above 100K prompt tokens, default tier at exactly 100K, cache writes priced, reasoning billed as output, a malformed
long_contextobject no longer drops the model from the catalog, cache-write mapping in all four adapter paths, plus regressions for the $0-prompt and negative-noCachecases. The adapter regressions fail on the parent commit and pass with this change.bun run checkpasses, and thepackages/coresuite has the same 4 failures as a cleandevcheckout (all environment-related).Visual
Screenshots / recordings
Not a UI change, so none attached.
Checklist
Added by the opencode bot (AI-generated).
Fixes #51845
Related: #35765, #53521