fix(cost): reach higher pricing tiers on non-tiered providers - #5737
fix(cost): reach higher pricing tiers on non-tiered providers#5737arthi-arumugam-git wants to merge 1 commit into
Conversation
getThresholdValueFunction only had cases for vertex, google-ai-studio, anthropic and xai; every other provider fell through to `default: return () => 0`. getPricingTier picks the highest tier whose threshold is <= the value, so a constant 0 always selected the cheapest tier and higher tiers were unreachable. An openai gpt-5.4 request with input=300000, output=50000 was billed 300000 * $2.50/M + 50000 * $15/M = $1.50 instead of the >272K tier's 300000 * $5/M + 50000 * $22.50/M = $2.625, 43% under. 24 endpoint configs across openai, azure, openrouter, helicone and bedrock declare a second tier that nothing could reach. The default branch now tiers on the request's prompt length. openai, azure, openrouter and helicone use input + cachedInput, mirroring xai. bedrock, openrouter and helicone also resell Anthropic models, which bill cache writes as part of the prompt, so the threshold basis follows the model's author there rather than the serving provider. Models with a single tier are unaffected: their only tier has threshold 0, so any value selects it. Fixes Helicone#5690
|
@arthi-arumugam-git is attempting to deploy a commit to the Helicone Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
A note while this waits, since #5690 is still open and this is a fix for it. The three red checks here are all Vercel reporting "Authorization required to deploy", which is the fork deploy permission rather than a failing build, so there is no real CI signal on this branch yet. The change: Glad to rebase, split it, or take a different approach to the provider mapping if you would rather it lived somewhere else. |
Fixes #5690
The bug
getThresholdValueFunctioninpackages/cost/models/calculate-cost.tsonly had cases forvertex,google-ai-studio,anthropicandxai. Every other provider fell through todefault: return () => 0. SincegetPricingTierpicks the highest tier whosethresholdis<=the value it is given, a constant0always selects the cheapest tier, so any higher tier on those providers was unreachable and large-context requests were under-charged.The example from the issue,
gpt-5.4onopenaiwithinput: 300000, output: 50000:43% under.
I scanned every endpoint config in
packages/cost/models/authors/forpricing.length > 1to size it. 40 endpoints declare more than one tier; 24 of them sit on a provider the switch did not handle:bedrockis in that list too, which the issue did not mention: the threeclaude-sonnet-4*Bedrock endpoints each declare a 200000 tier that was never selected.The fix
The
defaultbranch now returns the request's prompt length instead of0.For
openai,azure,openrouterandheliconeserving OpenAI-authored models that isusage.input + (usage.cacheDetails?.cachedInput ?? 0), exactly what the issue proposed and what thexaihandler already does.bedrock,openrouterandheliconealso resell Anthropic models, and Anthropic bills cache writes as part of the prompt, which is why the existinganthropiccase addswrite5mandwrite1h. Keying the threshold basis purely off the serving provider would silently under-count the prompt for Claude on Bedrock, so the default branch checks the model'sauthorand applies the Anthropic rule wherever an Anthropic-authored model is served from. ThepromptLength/anthropicPromptLengthhelpers exist so the two rules are written once.Models with a single pricing tier are unaffected: their only tier has
threshold: 0, so any value selects it. The four existing provider cases are untouched,vertexin particular, which tierscachedInputCostoff the cached-token count alone rather than the prompt.Tests
Nine cases added to the
threshold-based pricingblock inpackages/__tests__/cost/modelCostFromRegistry.test.ts: gpt-5.4 above and below the 272K threshold onopenai, cached input counting toward that threshold, the higher tier onazure/helicone/openrouter(the OpenRouter rates carry that provider's 1.055 markup), Claude Sonnet 4 onbedrockabove the threshold only once cache writes are counted and below it otherwise, and a guard that a single-tier model (gpt-4o) still prices the same.Reverting only
packages/cost/models/calculate-cost.tsand keeping the tests:With the fix in place, the whole
packagessuite:npx tsc --noEmitreports nothing on either changed file.One note on how I ran these:
packages/package.jsonandpackages/yarn.lockare not in the repo, so theyarn install --frozen-lockfilestep in.github/workflows/packages-test.ymlhas nothing to install from. I ran the suite against a local jest/ts-jest setup with@helicone-package/*mapped topackages/*, which is what the imports resolve to anyway. Nothing from that setup is in this branch.