diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index b3ed5354382..7f1c06e32a0 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -5609,8 +5609,8 @@ async def async_data_generator( except Exception as e: yield f"data: {str(e)}\n\n" - # Post-guardrail log: only for successful stream completion, not when we got an SSE error - if error_message is None: + # Post-guardrail log: only for successful stream completion with chunks to process + if error_message is None and _streaming_chunks_for_log: def _discard_task(t: asyncio.Task[None]) -> None: _post_guardrail_log_tasks.discard(t) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 4e20ac532c3..4771fbd9691 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -1994,7 +1994,12 @@ class ProxyLogging: if logging_obj is not None and getattr( logging_obj, "model_call_details", None ): + # Merge so request data wins overall, but model_call_details wins for + # LLM-lifecycle timing fields so callbacks get accurate start/end times. kwargs = {**logging_obj.model_call_details, **kwargs} + for key in ("start_time", "end_time"): + if key in logging_obj.model_call_details: + kwargs[key] = logging_obj.model_call_details[key] kwargs["user_api_key_dict"] = user_api_key_dict start_time = None if logging_obj is not None: