fix(logging): backfill streaming hidden response cost - #26606
Conversation
Made-with: Cursor
Backfill calculated streaming response cost into logging payload copies so OTEL spans expose hidden_params.response_cost without mutating the response object. Made-with: Cursor
Apply the repo-pinned Black 24.10.0 formatting expected by CI. Made-with: Cursor
Allow standard logging hidden params to carry numeric response_cost values, matching LiteLLM's calculated cost payloads. Made-with: Cursor
Greptile SummaryThis PR fixes a gap where streaming responses did not expose the calculated Confidence Score: 5/5Safe to merge — targeted backfill with no mutation of existing objects and no breaking changes. No P0 or P1 issues found. Both backfill paths are correctly guarded (only fills when No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/litellm_logging.py | Two targeted changes: _merge_hidden_params_from_response_into_metadata now uses .copy() and backfills response_cost; get_standard_logging_object_payload moves clean_hidden_params setup after saved_cache_cost and conditionally backfills response_cost. Both call sites confirm cost is set before the merge runs. |
| litellm/types/utils.py | Corrects StandardLoggingHiddenParams.response_cost type from Optional[str] to Optional[Union[str, float]] to accommodate the float cost values now being stored there. |
| tests/test_litellm/litellm_core_utils/test_litellm_logging.py | Adds four new unit tests covering: backfill when cost is null, no-overwrite when cost is already set, non-mutation of the original response object, and end-to-end standard logging payload backfill. No network calls; all tests are mock-based. |
Sequence Diagram
sequenceDiagram
participant SC as Streaming Chunk Handler
participant Log as Logging.success_handler
participant Merge as _merge_hidden_params_from_response_into_metadata
participant Build as _build_standard_logging_payload
participant SLP as get_standard_logging_object_payload
SC->>Log: Stream complete
Log->>Log: _response_cost_calculator(complete_streaming_response)
Log->>Merge: _merge_hidden_params_from_response_into_metadata(response)
Merge->>Merge: hidden_params = response._hidden_params.copy()
Merge->>Merge: if hidden_params[response_cost] is None and model_call_details[response_cost] is not None backfill cost
Merge->>Log: metadata[hidden_params][response_cost] = cost
Log->>Build: _build_standard_logging_payload(response, ...)
Build->>SLP: get_standard_logging_object_payload(kwargs, response, ...)
SLP->>SLP: hidden_params = response._hidden_params
SLP->>SLP: clean_hidden_params = get_hidden_params(hidden_params)
SLP->>SLP: if clean_hidden_params[response_cost] is None and raw_response_cost is not None backfill cost
SLP->>Log: StandardLoggingPayload with hidden_params.response_cost = cost
Reviews (2): Last reviewed commit: "refactor(logging): simplify hidden respo..." | Re-trigger Greptile
Clean up metadata initialization and reuse the raw response cost when deciding whether to backfill hidden params. Made-with: Cursor
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
* fix(logging): backfill streaming hidden response cost Made-with: Cursor * fix(logging): avoid mutating streaming hidden params Backfill calculated streaming response cost into logging payload copies so OTEL spans expose hidden_params.response_cost without mutating the response object. Made-with: Cursor * fix black formatting Apply the repo-pinned Black 24.10.0 formatting expected by CI. Made-with: Cursor * fix(types): allow numeric hidden response cost Allow standard logging hidden params to carry numeric response_cost values, matching LiteLLM's calculated cost payloads. Made-with: Cursor * refactor(logging): simplify hidden response cost backfill Clean up metadata initialization and reuse the raw response cost when deciding whether to backfill hidden params. Made-with: Cursor
* fix(logging): backfill streaming hidden response cost Made-with: Cursor * fix(logging): avoid mutating streaming hidden params Backfill calculated streaming response cost into logging payload copies so OTEL spans expose hidden_params.response_cost without mutating the response object. Made-with: Cursor * fix black formatting Apply the repo-pinned Black 24.10.0 formatting expected by CI. Made-with: Cursor * fix(types): allow numeric hidden response cost Allow standard logging hidden params to carry numeric response_cost values, matching LiteLLM's calculated cost payloads. Made-with: Cursor * refactor(logging): simplify hidden response cost backfill Clean up metadata initialization and reuse the raw response cost when deciding whether to backfill hidden params. Made-with: Cursor
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/test_litellm/directory, Adding at least 1 test is a hard requirement - see detailsmake test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
CI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Screenshots / Proof of Fix
Validated with LiteLLM proxy configured with
callbacks: ["otel"]and Jaeger as the OTLP backend.After the fix:
Non-streaming request:
llm.is_streaming:Falsegen_ai.cost.total_cost:4.6499999999999995e-06hidden_params.response_cost:4.6499999999999995e-06Streaming request:
llm.is_streaming:Truegen_ai.cost.total_cost:3.9e-06hidden_params.response_cost:3.9e-06The streaming value is now present on the main
Received Proxy Server Requestspan, which reads fromstandard_logging_object.hidden_params.Test run:
Result:
Type
🐛 Bug Fix
✅ Test
Changes
litellm_params.metadata.hidden_params.response_costfor assembled streaming responses using the already-calculatedmodel_call_details["response_cost"].standard_logging_object.hidden_params.response_costfrom the same calculated cost so OTEL/Jaeger spans include the streaming cost.hidden_params.response_cost._hidden_paramswhile constructing logging payloads.