Merge pull request #18938 from BerriAI/litellm_fix_generate_two_telemetry

[fix] generate two telemetry in responses
This commit is contained in:
YutaSaito
2026-01-14 12:35:23 +09:00
committed by GitHub
3 changed files with 104 additions and 58 deletions
+21 -58
View File
@@ -1853,6 +1853,14 @@ class Logging(LiteLLMLoggingBaseClass):
cache_hit=cache_hit,
standard_logging_object=kwargs.get("standard_logging_object", None),
)
litellm_params = self.model_call_details.get("litellm_params", {})
is_sync_request = (
litellm_params.get(CallTypes.acompletion.value, False) is not True
and litellm_params.get(CallTypes.aresponses.value, False) is not True
and litellm_params.get(CallTypes.aembedding.value, False) is not True
and litellm_params.get(CallTypes.aimage_generation.value, False) is not True
and litellm_params.get(CallTypes.atranscription.value, False) is not True
)
try:
## BUILD COMPLETE STREAMED RESPONSE
complete_streaming_response: Optional[
@@ -1915,7 +1923,6 @@ class Logging(LiteLLMLoggingBaseClass):
self.has_run_logging(event_type="sync_success")
for callback in callbacks:
try:
litellm_params = self.model_call_details.get("litellm_params", {})
should_run = self.should_run_callback(
callback=callback,
litellm_params=litellm_params,
@@ -2185,22 +2192,7 @@ class Logging(LiteLLMLoggingBaseClass):
if (
callback == "openmeter"
and self.model_call_details.get("litellm_params", {}).get(
"acompletion", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aembedding", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aimage_generation", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"atranscription", False
)
is not True
and is_sync_request
):
global openMeterLogger
if openMeterLogger is None:
@@ -2229,22 +2221,7 @@ class Logging(LiteLLMLoggingBaseClass):
)
if (
isinstance(callback, CustomLogger)
and self.model_call_details.get("litellm_params", {}).get(
"acompletion", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aembedding", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aimage_generation", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"atranscription", False
)
is not True
and is_sync_request
and self.call_type
!= CallTypes.pass_through.value # pass-through endpoints call async_log_success_event
): # custom logger class
@@ -2272,22 +2249,7 @@ class Logging(LiteLLMLoggingBaseClass):
)
if (
callable(callback) is True
and self.model_call_details.get("litellm_params", {}).get(
"acompletion", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aembedding", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aimage_generation", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"atranscription", False
)
is not True
and is_sync_request
and customLogger is not None
): # custom logger functions
print_verbose(
@@ -2737,6 +2699,15 @@ class Logging(LiteLLMLoggingBaseClass):
event_type="sync_failure"
): # prevent double logging
return
litellm_params = self.model_call_details.get("litellm_params", {})
is_sync_request = (
litellm_params.get(CallTypes.acompletion.value, False) is not True
and litellm_params.get(CallTypes.aresponses.value, False) is not True
and litellm_params.get(CallTypes.aembedding.value, False) is not True
and litellm_params.get(CallTypes.aimage_generation.value, False) is not True
and litellm_params.get(CallTypes.atranscription.value, False) is not True
)
try:
start_time, end_time = self._failure_handler_helper_fn(
exception=exception,
@@ -2762,7 +2733,6 @@ class Logging(LiteLLMLoggingBaseClass):
self.has_run_logging(event_type="sync_failure")
for callback in callbacks:
try:
litellm_params = self.model_call_details.get("litellm_params", {})
should_run = self.should_run_callback(
callback=callback,
litellm_params=litellm_params,
@@ -2830,14 +2800,7 @@ class Logging(LiteLLMLoggingBaseClass):
)
if (
isinstance(callback, CustomLogger)
and self.model_call_details.get("litellm_params", {}).get(
"acompletion", False
)
is not True
and self.model_call_details.get("litellm_params", {}).get(
"aembedding", False
)
is not True
and is_sync_request
): # custom logger class
callback.log_failure_event(
start_time=start_time,
+1
View File
@@ -668,6 +668,7 @@ def responses(
optional_params=dict(responses_api_request_params),
litellm_params={
**responses_api_request_params,
"aresponses": _is_async,
"litellm_call_id": litellm_call_id,
"metadata": metadata,
},
@@ -14,6 +14,7 @@ import time
from litellm.constants import SENTRY_DENYLIST, SENTRY_PII_DENYLIST
from litellm.litellm_core_utils.litellm_logging import Logging as LitellmLogging
from litellm.litellm_core_utils.litellm_logging import set_callbacks
from litellm.types.utils import ModelResponse
@pytest.fixture
@@ -277,6 +278,87 @@ async def test_logging_non_streaming_request():
litellm.callbacks = original_callbacks
@pytest.mark.parametrize("async_flag", ["acompletion", "aresponses"])
def test_success_handler_skips_sync_callbacks_for_async_requests(logging_obj, async_flag):
"""Ensure sync success callbacks are skipped when async call type flags are set."""
from litellm.integrations.custom_logger import CustomLogger
class DummyLogger(CustomLogger):
pass
logging_obj.stream = False # simulate non-streaming request where sync callbacks would normally run
logging_obj.model_call_details["litellm_params"] = {async_flag: True}
logging_obj.litellm_params = logging_obj.model_call_details["litellm_params"]
dummy_logger = DummyLogger()
dummy_logger.log_success_event = MagicMock()
dummy_logger.log_stream_event = MagicMock()
model_response = ModelResponse(
id="resp-123",
model="gpt-4o-mini",
choices=[
{
"message": {"role": "assistant", "content": "hello"},
"finish_reason": "stop",
"index": 0,
}
],
usage={"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
)
with patch.object(
logging_obj,
"get_combined_callback_list",
return_value=[dummy_logger],
):
logging_obj.success_handler(result=model_response)
dummy_logger.log_success_event.assert_not_called()
dummy_logger.log_stream_event.assert_not_called()
@pytest.mark.parametrize("call_type", ["completion", "responses"])
def test_success_handler_runs_sync_callbacks_for_sync_requests(logging_obj, call_type):
"""Ensure sync success callbacks execute when call type is sync (completion/responses)."""
from litellm.integrations.custom_logger import CustomLogger
class DummyLogger(CustomLogger):
pass
logging_obj.stream = False
logging_obj.call_type = call_type
logging_obj.model_call_details["litellm_params"] = {}
logging_obj.litellm_params = {}
dummy_logger = DummyLogger()
dummy_logger.log_success_event = MagicMock()
dummy_logger.log_stream_event = MagicMock()
model_response = ModelResponse(
id="resp-123",
model="gpt-4o-mini",
choices=[
{
"message": {"role": "assistant", "content": "hello"},
"finish_reason": "stop",
"index": 0,
}
],
usage={"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
)
with patch.object(
logging_obj,
"get_combined_callback_list",
return_value=[dummy_logger],
):
logging_obj.success_handler(result=model_response)
dummy_logger.log_success_event.assert_called_once()
dummy_logger.log_stream_event.assert_not_called()
def test_get_user_agent_tags():
from litellm.litellm_core_utils.litellm_logging import StandardLoggingPayloadSetup