fix(cost_calculator): honor base_model's own provider in cost-logging metadata too

completion_cost() already resolves the correct provider for billing when
base_model points at a priced row under a different provider than the
deployment's transport (e.g. a chatgpt/ subscription deployment priced
via an openai/ or zai/ base_model, fixed in #46318). The diagnostic
model_map_information field built in litellm_logging.py never got the
same correction: it calls get_model_info() with the raw transport
provider, which _check_provider_match rejects, so model_map_value stays
None even though spend is now computed correctly. Reuses the same
_base_model_pricing_provider helper for this lookup too.

Fixes #47908 (the remaining part after #46318)
This commit is contained in:
Rupesh Poojary 2026-10-23 17:34:36 +05:30
parent f2118fc767
commit d066f502da
2 changed files with 38 additions and 1 deletions

View file

@ -51,6 +51,7 @@ from litellm.constants import (
from litellm.cost_calculator import (
RealtimeAPITokenUsageProcessor,
ResponsesWebSocketTokenUsageProcessor,
_base_model_pricing_provider,
get_usage_object,
pricing_entry_for_cost_calc,
select_model_name_for_cost_calc,
@ -6693,10 +6694,20 @@ class StandardLoggingPayloadSetup:
if model_cost_name is None:
model_cost_information = StandardLoggingModelInformation(model_map_key="", model_map_value=None)
else:
# When base_model points at a priced row under a different provider than the deployment's own
# transport (e.g. a chatgpt/ subscription deployment priced via an openai/ base_model), completion_cost
# already resolves the correct provider for billing. Without the same correction here, get_model_info
# rejects the match on provider mismatch and this diagnostic field stays None even though spend is
# computed correctly.
pricing_provider: Final = (
_base_model_pricing_provider(base_model, custom_llm_provider)
if base_model is not None and custom_pricing is not True
else None
)
try:
_model_cost_information: Final = litellm.get_model_info(
model=pricing_model_name or model_cost_name,
custom_llm_provider=custom_llm_provider,
custom_llm_provider=pricing_provider or custom_llm_provider,
api_base=api_base,
)
model_cost_information = StandardLoggingModelInformation(

View file

@ -11974,6 +11974,32 @@ def test_get_model_cost_information_custom_pricing_uses_base_model():
assert result["model_map_value"] is not None
assert result["model_map_key"] != "invoke_test_claude"
@pytest.mark.usefixtures("_vcr_outcome_gate", "drain_logging_worker", "isolate_litellm_state", "setup_and_teardown")
def test_get_model_cost_information_base_model_cross_provider():
"""Regression test for #47908: a deployment whose transport provider differs from the priced
base_model's own registered provider must still populate model_map_value, not just completion_cost's
return value, since the two used to disagree (spend computed correctly, this field stayed None)."""
litellm.register_model(
model_cost={
"custom-provider/base-model-cross-provider-test": {
"input_cost_per_token": 1.5e-07,
"output_cost_per_token": 5e-07,
"litellm_provider": "custom-provider",
"mode": "chat",
}
}
)
result = StandardLoggingPayloadSetup.get_model_cost_information(
base_model="custom-provider/base-model-cross-provider-test",
custom_pricing=False,
custom_llm_provider="openai",
init_response_obj={},
)
assert result["model_map_value"] is not None
assert result["model_map_value"]["input_cost_per_token"] == 1.5e-07
assert result["model_map_value"]["litellm_provider"] == "custom-provider"
@pytest.mark.usefixtures("_vcr_outcome_gate", "drain_logging_worker", "isolate_litellm_state", "setup_and_teardown")
def test_standard_logging_payload_uses_deployment_when_no_base_model():
"""metadata["deployment"] is used for cost-map lookup when base_model is not set."""