[BE] fix: register xai as a canonical provider so xAI/Grok model prices load#7433
Merged
andrescrz merged 2 commits intoJul 13, 2026
Merged
Conversation
…es load Following the pattern of comet-ml#7262 (azure) and comet-ml#7432 (perplexity) — `xai` is not currently in PROVIDERS_MAPPING, so all 40 entries in model_prices_and_context_window.json tagged with litellm_provider: "xai" silently drop at load time. Every one publishes non-zero input+output rates: the grok-2 / grok-3 / grok-4 / grok-4-fast / grok-code families. 29 of the 40 also publish cache_read_input_token_cost. xAI's cost calc in LiteLLM (litellm/llms/xai/cost_calculator.py) delegates to generic_cost_per_token, which is the same helper OpenAI uses — so xai's usage payload follows OpenAI's shape (prompt_tokens_details.cached_tokens flattened into original_usage.*). That means xai routes cleanly through the existing textGenerationWithCacheCostOpenAI calculator: no new cache calc needed, just a PROVIDERS_CACHE_COST_CALCULATOR entry mirroring the azure one. Parameterized test uses xai/grok-2 (no cache rates -> textGenerationCost) and xai/grok-3 (input 3e-6, output 1.5e-5, cache_read 7.5e-7 -> textGenerationWithCacheCostOpenAI). Both branches exercised in regressions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
Anuj7411
added a commit
to Anuj7411/opik
that referenced
this pull request
Jul 11, 2026
…ting misses Addressing baz-reviewer's High-severity finding on comet-ml#7432. Registering `perplexity` as a canonical provider (this PR's original scope) fixes direct callers, but BudgetGuard also invokes CostService.calculateCost via LlmProviderFactoryImpl.getResolvedModelInfo(), which enumerates `perplexity/*`, `xai/*`, and `deepseek/*` under OpenRouter and therefore returns `provider="openrouter"`. Without an openrouter row for these models the lookup lands on DEFAULT_COST and Perplexity-hosted evaluations charge $0. Add a final fallback in `findModelPrice`: when every primary lookup has missed and the original model name carries a provider prefix that maps to a canonical provider we know pricing for (e.g. `perplexity/sonar` maps prefix `perplexity` -> canonical `perplexity`), retry the lookup under that prefix's canonical provider. Only kicks in as a fallback so no existing lookup semantics change for callers that already pass a matching provider directly, and only when the prefix appears in PROVIDERS_MAPPING so unmapped prefixes cannot leak through. The same fallback covers the parallel deepseek and xai cases (comet-ml#7434, comet-ml#7433) — those models are also enumerated under OpenRouter and would otherwise silently drop to $0 through the aggregator-routed BudgetGuard path. Parameterized test uses perplexity/sonar and perplexity/sonar-pro through both `openrouter` and `custom-llm` providers; each returns the same cost as the direct perplexity lookup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
andrescrz
approved these changes
Jul 13, 2026
andrescrz
left a comment
Member
There was a problem hiding this comment.
Hi @Anuj7411
Thanks for the contribution! I reviewed the PR and everything looks good from my side. I've approved it, and all CI checks have passed successfully.
We'll merge it shortly, and the change will be included in the next Opik release.
Thanks again for contributing to Opik!
Anuj7411
added a commit
to Anuj7411/opik
that referenced
this pull request
Jul 13, 2026
… prices load Following the pattern of comet-ml#7262 (azure), comet-ml#7432 (perplexity) and comet-ml#7433 (xai) — `deepseek` is not currently in PROVIDERS_MAPPING, so all 12 entries in model_prices_and_context_window.json tagged with litellm_provider: "deepseek" silently drop at load time. Every one publishes non-zero input+output rates: deepseek-chat, deepseek-reasoner, deepseek-v4-flash, deepseek-v4-pro, plus the deepseek/deepseek-coder, deepseek/deepseek-r1, deepseek/deepseek-v3, deepseek/deepseek-v3.2 variants. 9 of the 12 also publish cache_read_input_token_cost. DeepSeek's cost calc in LiteLLM (litellm/llms/deepseek/cost_calculator.py) is a one-liner that delegates directly to generic_cost_per_token — the same helper OpenAI/xAI use — so DeepSeek's usage payload follows OpenAI's shape (prompt_tokens_details.cached_tokens flattened under original_usage.*). Route it through the existing textGenerationWithCacheCostOpenAI calculator; no new cache-calc method needed. Parameterized test uses deepseek/deepseek-coder (no cache -> textGenerationCost) and deepseek/deepseek-chat (input 2.8e-7, output 4.2e-7, cache_read 2.8e-8 -> textGenerationWithCacheCostOpenAI). Both branches exercised in regressions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Anuj7411
added a commit
to Anuj7411/opik
that referenced
this pull request
Jul 13, 2026
…ting misses Addressing baz-reviewer's High-severity finding on comet-ml#7432. Registering `perplexity` as a canonical provider (this PR's original scope) fixes direct callers, but BudgetGuard also invokes CostService.calculateCost via LlmProviderFactoryImpl.getResolvedModelInfo(), which enumerates `perplexity/*`, `xai/*`, and `deepseek/*` under OpenRouter and therefore returns `provider="openrouter"`. Without an openrouter row for these models the lookup lands on DEFAULT_COST and Perplexity-hosted evaluations charge $0. Add a final fallback in `findModelPrice`: when every primary lookup has missed and the original model name carries a provider prefix that maps to a canonical provider we know pricing for (e.g. `perplexity/sonar` maps prefix `perplexity` -> canonical `perplexity`), retry the lookup under that prefix's canonical provider. Only kicks in as a fallback so no existing lookup semantics change for callers that already pass a matching provider directly, and only when the prefix appears in PROVIDERS_MAPPING so unmapped prefixes cannot leak through. The same fallback covers the parallel deepseek and xai cases (comet-ml#7434, comet-ml#7433) — those models are also enumerated under OpenRouter and would otherwise silently drop to $0 through the aggregator-routed BudgetGuard path. Parameterized test uses perplexity/sonar and perplexity/sonar-pro through both `openrouter` and `custom-llm` providers; each returns the same cost as the direct perplexity lookup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
andrescrz
pushed a commit
that referenced
this pull request
Jul 13, 2026
… prices load (#7434) Following the pattern of #7262 (azure), #7432 (perplexity) and #7433 (xai) — `deepseek` is not currently in PROVIDERS_MAPPING, so all 12 entries in model_prices_and_context_window.json tagged with litellm_provider: "deepseek" silently drop at load time. Every one publishes non-zero input+output rates: deepseek-chat, deepseek-reasoner, deepseek-v4-flash, deepseek-v4-pro, plus the deepseek/deepseek-coder, deepseek/deepseek-r1, deepseek/deepseek-v3, deepseek/deepseek-v3.2 variants. 9 of the 12 also publish cache_read_input_token_cost. DeepSeek's cost calc in LiteLLM (litellm/llms/deepseek/cost_calculator.py) is a one-liner that delegates directly to generic_cost_per_token — the same helper OpenAI/xAI use — so DeepSeek's usage payload follows OpenAI's shape (prompt_tokens_details.cached_tokens flattened under original_usage.*). Route it through the existing textGenerationWithCacheCostOpenAI calculator; no new cache-calc method needed. Parameterized test uses deepseek/deepseek-coder (no cache -> textGenerationCost) and deepseek/deepseek-chat (input 2.8e-7, output 4.2e-7, cache_read 2.8e-8 -> textGenerationWithCacheCostOpenAI). Both branches exercised in regressions. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Details
Following the pattern of #7262 (which registered
azure) and #7432 (perplexity) —xaiis not currently inPROVIDERS_MAPPING, so all 40 entries inmodel_prices_and_context_window.jsontagged withlitellm_provider: "xai"silently drop at load time. Every one publishes non-zero input+output rates: the fullgrok-2/grok-3/grok-4/grok-4-fast/grok-codefamilies.29 of the 40 also publish
cache_read_input_token_cost. xAI's cost calculator in LiteLLM (litellm/llms/xai/cost_calculator.py) delegates togeneric_cost_per_token, which is the same helper OpenAI uses — so xai's usage payload follows OpenAI's shape (prompt_tokens_details.cached_tokensflattened intooriginal_usage.*). That means xai routes cleanly through the existingSpanCostCalculator::textGenerationWithCacheCostOpenAIcalculator; no new cache-calc method needed, just a mirror of theazureentry inPROVIDERS_CACHE_COST_CALCULATOR.Change checklist
Issues
AI-WATERMARK
AI-WATERMARK: yes
litellm/llms/xai/cost_calculator.pyto confirm xai delegates togeneric_cost_per_tokenand therefore shares the OpenAI usage shape, drafted the two-line plumbing change following the [BE] fix: register azure as a canonical provider so Azure model prices load #7262 pattern, and wrote the parameterized branch-coverage testmodel_prices_and_context_window.jsonTesting
Local verification on JDK 25 + Maven 3.9.9:
Result: 102/102 green (2 new parameterized cases under
calculateCostHandlesXaiModels, matching the style established in #7262 for Azure).Scenarios covered:
xai/grok-2(input2e-6, output1e-5, no cache rates configured). Withprompt_tokens=1000, completion_tokens=200, expected0.004(1000 * 2e-6 + 200 * 1e-5). Exercises the path where xai is registered butresolveCalculatorfalls through past the cache check totextGenerationCost.xai/grok-3(input3e-6, output1.5e-5,cache_read 7.5e-7). Withoriginal_usage.prompt_tokens=1000, original_usage.completion_tokens=200, original_usage.prompt_tokens_details.cached_tokens=300, expected0.005325(non-cached input700 * 3e-6 + 200 * 1.5e-5 + 300 * 7.5e-7). Exercises the newPROVIDERS_CACHE_COST_CALCULATORentry.Documentation
No docs change. Behavior change is invisible to end users beyond accurate (non-zero) cost numbers for xAI/Grok traces on 40 previously-dropped models.