From 8d0dc9294d076425f0da810dedc041e2ed3e1b1e Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Thu, 2 Jul 2026 20:37:07 +0530 Subject: [PATCH] fix(logging): resolve model_map_value for proxy custom pricing (#31940) * fix(logging): resolve model_map_value for proxy custom pricing Use deployment model for standard logging cost-map lookup when the router overrides response.model to a group alias, and flush stdout when printing the payload. Co-authored-by: Cursor * fix(logging): add comment and test for deployment fallback in standard logging payload Address review: explain why the metadata["deployment"] fallback is unconditional, and add a test covering the get_standard_logging_object_payload code path. Co-authored-by: Cursor * fix(test): update model_map_key assertion for provider-prefixed keys Co-authored-by: Cursor * fix(logging): scope base_model to model param only under custom_pricing Passing model=base_model unconditionally caused _get_provider_for_cost_calc to infer and prepend a provider prefix on all non-custom-pricing calls, changing model_map_key for existing deployments. Scope it to custom_pricing=True where the fix is actually needed. Co-authored-by: Cursor --------- Co-authored-by: Cursor Co-authored-by: Mateo Wang <277851410+mateo-berri@users.noreply.github.com> --- litellm/litellm_core_utils/litellm_logging.py | 9 ++- .../test_standard_logging_payload.py | 68 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index da204855465..db7c1c7dfb4 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -4722,7 +4722,7 @@ class StandardLoggingPayloadSetup: api_base: Optional[str] = None, ) -> StandardLoggingModelInformation: model_cost_name = _select_model_name_for_cost_calc( - model=None, + model=base_model if custom_pricing else None, completion_response=init_response_obj, # type: ignore base_model=base_model, custom_pricing=custom_pricing, @@ -5268,6 +5268,11 @@ def get_standard_logging_object_payload( ## Get model cost information ## base_model = _get_base_model_from_metadata(model_call_details=kwargs) + # The router overrides completion_response.model to the model-group alias before + # this payload is built, so cost-map lookup via that alias always misses. + # Fall back to the actual deployment model set by the router in metadata. + if base_model is None: + base_model = metadata.get("deployment") custom_pricing = use_custom_pricing_for_model(litellm_params=litellm_params) raw_response_cost = kwargs.get("response_cost") response_cost: float = raw_response_cost or 0.0 @@ -5389,7 +5394,7 @@ def get_standard_logging_object_payload( def emit_standard_logging_payload(payload: StandardLoggingPayload): if os.getenv("LITELLM_PRINT_STANDARD_LOGGING_PAYLOAD"): - print(json.dumps(payload, indent=4)) # noqa: T201 + print(json.dumps(payload, indent=4), flush=True) # noqa: T201 def get_standard_logging_metadata( diff --git a/tests/logging_callback_tests/test_standard_logging_payload.py b/tests/logging_callback_tests/test_standard_logging_payload.py index 36215ca9c6b..f29b245b3be 100644 --- a/tests/logging_callback_tests/test_standard_logging_payload.py +++ b/tests/logging_callback_tests/test_standard_logging_payload.py @@ -335,6 +335,74 @@ def test_get_model_cost_information(): ) +def test_get_model_cost_information_custom_pricing_uses_base_model(): + result = StandardLoggingPayloadSetup.get_model_cost_information( + base_model="bedrock/invoke/global.anthropic.claude-opus-4-6-v1", + custom_pricing=True, + custom_llm_provider="bedrock", + init_response_obj={"model": "invoke_test_claude"}, + ) + assert result["model_map_value"] is not None + assert result["model_map_key"] != "invoke_test_claude" + + +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.""" + from datetime import datetime + + from litellm.litellm_core_utils.litellm_logging import ( + Logging, + get_standard_logging_object_payload, + ) + + logging_obj = Logging( + model="invoke_test_claude", + messages=[{"role": "user", "content": "hi"}], + stream=False, + call_type="completion", + start_time=datetime.now(), + litellm_call_id="test-deploy-fallback", + function_id="test-fn", + ) + + kwargs = { + "model": "invoke_test_claude", + "messages": [{"role": "user", "content": "hi"}], + "custom_llm_provider": "bedrock", + "litellm_params": { + "metadata": { + "deployment": "bedrock/invoke/global.anthropic.claude-opus-4-6-v1", + }, + }, + } + mock_response = { + "id": "chatcmpl-deploy-test", + "object": "chat.completion", + "model": "invoke_test_claude", + "usage": {"prompt_tokens": 5, "completion_tokens": 10, "total_tokens": 15}, + "choices": [ + { + "index": 0, + "message": {"role": "assistant", "content": "hello"}, + "finish_reason": "stop", + } + ], + } + + payload = get_standard_logging_object_payload( + kwargs=kwargs, + init_response_obj=mock_response, + start_time=datetime.now(), + end_time=datetime.now(), + logging_obj=logging_obj, + status="success", + ) + + assert payload is not None + assert payload["model_map_information"]["model_map_value"] is not None + assert payload["model_map_information"]["model_map_key"] != "invoke_test_claude" + + def test_get_hidden_params(): """Test get_hidden_params with different inputs""" # Test with None