fix(logging): handle ResponseCompletedEvent in anthropic_messages spe… - #28628
Conversation
Greptile SummaryThis PR adds guards in
Confidence Score: 4/5Safe to merge for the crash fix; the streaming spend-logging gap was already broken before and remains so. The fix correctly prevents the ValidationError crash for all four event types, and the non-streaming logging path works end-to-end. The streaming path still does not produce a complete_streaming_response because _get_assembled_streaming_response has no branch for an already-unwrapped ResponsesAPIResponse, so spend-log rows for streaming anthropic_messages Responses API calls continue to be silently dropped — the same symptom the PR states it fixes. litellm/litellm_core_utils/litellm_logging.py — specifically the _get_assembled_streaming_response method which needs a ResponsesAPIResponse passthrough branch to complete the streaming fix.
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/litellm_logging.py | Adds ResponseCompletedEvent/ResponseIncompleteEvent/ResponseFailedEvent/ResponsesAPIResponse guards to _handle_anthropic_messages_response_logging; fixes the ValidationError crash but does not fix spend logging for streaming because _get_assembled_streaming_response still returns None for ResponsesAPIResponse, leaving complete_streaming_response unset. |
| tests/test_litellm/litellm_core_utils/test_litellm_logging.py | Adds four unit tests covering all new branches in _handle_anthropic_messages_response_logging; all tests are properly mocked with no network calls, but they test the helper in isolation and do not verify that _get_assembled_streaming_response produces a non-None complete_streaming_response for the streaming path. |
Reviews (2): Last reviewed commit: "test(logging): add ResponseFailedEvent c..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…s responses bridge
|
This also fixes the @greptileai request re-review |
| if isinstance( | ||
| result, | ||
| (ResponseCompletedEvent, ResponseIncompleteEvent, ResponseFailedEvent), | ||
| ): | ||
| return result.response | ||
| elif isinstance(result, ResponsesAPIResponse): | ||
| return result |
There was a problem hiding this comment.
Streaming spend-log still dropped after this fix
_handle_anthropic_messages_response_logging is called inside _success_handler_helper_fn before _get_assembled_streaming_response. After the fix, a ResponseCompletedEvent is converted to ResponsesAPIResponse here and returned to the caller. _get_assembled_streaming_response then receives a ResponsesAPIResponse, falls through to its else: return None branch (lines 3424-3425), and returns None. Because complete_streaming_response is None, neither response_cost nor standard_logging_object is ever set for the streaming path, so the LiteLLM_SpendLogs row is still silently dropped.
The non-streaming path is fine (self.stream is not True triggers _process_hidden_params_and_response_cost at line 1891 which builds the payload). For the streaming path, _get_assembled_streaming_response needs a ResponsesAPIResponse passthrough branch identical to the one that already exists for ModelResponse (line 3398).
Relevant issues
Fixes 28595
Pre-Submission checklist
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 reviewScreenshots / Proof of Fix
Type
🐛 Bug Fix
Changes
When
/v1/messagesroutes to a non-Anthropic backend via the Responses API, the streaming success handler delivers aResponseCompletedEventto_handle_anthropic_messages_response_logging. That function had no branch for this type and fell through toAnthropicResponse.model_validate(result), which raised aValidationErrorbecauseResponseCompletedEventis not an anthropic-shaped object. The exception was caught by_success_handler_helper_fnas "Non-Blocking", so client received the correct response but the request was silently dropped fromLiteLLM_SpendLogs.The fix adds two guards before the existing httpx_response branch -
If result is a
ResponseCompletedEvent,ResponseIncompleteEvent, orResponseFailedEvent, unwrapresult.response(the ResponsesAPIResponse); if it is already aResponsesAPIResponse, return it directly. Both types flow through the downstream logging pipeline correctly._transform_usage_objectsalready handlesResponsesAPIResponseand converts its usage format for spend logging.