From 6ca9282857a59b5e838c7e7e4f1bc4087554ad2d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 12 Jan 2026 07:37:40 +0900 Subject: [PATCH 1/7] refactor: make variable --- litellm/litellm_core_utils/litellm_logging.py | 74 ++++--------------- 1 file changed, 16 insertions(+), 58 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index e0a799d8e5..45eceea9fb 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1853,6 +1853,13 @@ 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_async_logging_request = ( + litellm_params.get("acompletion", False) is not True + and litellm_params.get("aembedding", False) is not True + and litellm_params.get("aimage_generation", False) is not True + and litellm_params.get("atranscription", False) is not True + ) try: ## BUILD COMPLETE STREAMED RESPONSE complete_streaming_response: Optional[ @@ -1915,7 +1922,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 +2191,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_async_logging_request ): global openMeterLogger if openMeterLogger is None: @@ -2229,22 +2220,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_async_logging_request and self.call_type != CallTypes.pass_through.value # pass-through endpoints call async_log_success_event ): # custom logger class @@ -2272,22 +2248,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_async_logging_request and customLogger is not None ): # custom logger functions print_verbose( @@ -2737,6 +2698,11 @@ class Logging(LiteLLMLoggingBaseClass): event_type="sync_failure" ): # prevent double logging return + litellm_params = self.model_call_details.get("litellm_params", {}) + is_async_logging_request = ( + litellm_params.get("acompletion", False) is not True + and litellm_params.get("aembedding", False) is not True + ) try: start_time, end_time = self._failure_handler_helper_fn( exception=exception, @@ -2762,7 +2728,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 +2795,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_async_logging_request ): # custom logger class callback.log_failure_event( start_time=start_time, From bc02d462ff37f6a839e71410c2a29d65e44014f1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 12 Jan 2026 07:46:40 +0900 Subject: [PATCH 2/7] fix: add call type aresponses --- litellm/litellm_core_utils/litellm_logging.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 45eceea9fb..f8c932db4d 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1855,10 +1855,11 @@ class Logging(LiteLLMLoggingBaseClass): ) litellm_params = self.model_call_details.get("litellm_params", {}) is_async_logging_request = ( - litellm_params.get("acompletion", False) is not True - and litellm_params.get("aembedding", False) is not True - and litellm_params.get("aimage_generation", False) is not True - and litellm_params.get("atranscription", False) is not True + 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 @@ -2700,9 +2701,13 @@ class Logging(LiteLLMLoggingBaseClass): return litellm_params = self.model_call_details.get("litellm_params", {}) is_async_logging_request = ( - litellm_params.get("acompletion", False) is not True - and litellm_params.get("aembedding", False) is not True + 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, From fde68e4a29b26a1b808ee779cc48817175e24a2a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 12 Jan 2026 07:54:19 +0900 Subject: [PATCH 3/7] fix: mastake env variable name --- litellm/litellm_core_utils/litellm_logging.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index f8c932db4d..f70524426a 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1854,7 +1854,7 @@ class Logging(LiteLLMLoggingBaseClass): standard_logging_object=kwargs.get("standard_logging_object", None), ) litellm_params = self.model_call_details.get("litellm_params", {}) - is_async_logging_request = ( + 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 @@ -2221,7 +2221,7 @@ class Logging(LiteLLMLoggingBaseClass): ) if ( isinstance(callback, CustomLogger) - and is_async_logging_request + and is_sync_request and self.call_type != CallTypes.pass_through.value # pass-through endpoints call async_log_success_event ): # custom logger class @@ -2249,7 +2249,7 @@ class Logging(LiteLLMLoggingBaseClass): ) if ( callable(callback) is True - and is_async_logging_request + and is_sync_request and customLogger is not None ): # custom logger functions print_verbose( @@ -2700,7 +2700,7 @@ class Logging(LiteLLMLoggingBaseClass): ): # prevent double logging return litellm_params = self.model_call_details.get("litellm_params", {}) - is_async_logging_request = ( + 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 @@ -2800,7 +2800,7 @@ class Logging(LiteLLMLoggingBaseClass): ) if ( isinstance(callback, CustomLogger) - and is_async_logging_request + and is_sync_request ): # custom logger class callback.log_failure_event( start_time=start_time, From b71e30a8ac39cec853c50ef13dd073d1635b2dd8 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 12 Jan 2026 09:29:53 +0900 Subject: [PATCH 4/7] fix: mastake env variable name --- litellm/litellm_core_utils/litellm_logging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index f70524426a..7d036615f5 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -2192,7 +2192,7 @@ class Logging(LiteLLMLoggingBaseClass): if ( callback == "openmeter" - and is_async_logging_request + and is_sync_request ): global openMeterLogger if openMeterLogger is None: From c3d0dd6897e94d30f680a24cc008c75335cee4f0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 12 Jan 2026 09:33:54 +0900 Subject: [PATCH 5/7] fix: add aresponses litellm_params --- litellm/responses/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litellm/responses/main.py b/litellm/responses/main.py index 07fc3cb02c..8db6f4b9ff 100644 --- a/litellm/responses/main.py +++ b/litellm/responses/main.py @@ -543,7 +543,7 @@ def responses( try: litellm_logging_obj: LiteLLMLoggingObj = kwargs.get("litellm_logging_obj") # type: ignore litellm_call_id: Optional[str] = kwargs.get("litellm_call_id", None) - _is_async = kwargs.pop("aresponses", False) is True + _is_async = kwargs.get("aresponses", False) is True # Convert text_format to text parameter if provided text = ResponsesAPIRequestUtils.convert_text_format_to_text_param( @@ -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, }, From 2814d3dd3d4e399a704048c5473595551987c54a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Jan 2026 10:52:14 +0900 Subject: [PATCH 6/7] test: cover success handler sync/async logging branches --- .../test_litellm_logging.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py index bae0e5bbb4..a4d3206fdc 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -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 From a1bceb8403161096b7a195a277c3fa1121643124 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Jan 2026 11:15:29 +0900 Subject: [PATCH 7/7] fix: anthropic Extra inputs are not permitted error --- litellm/responses/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/responses/main.py b/litellm/responses/main.py index 8db6f4b9ff..71d94287e8 100644 --- a/litellm/responses/main.py +++ b/litellm/responses/main.py @@ -543,7 +543,7 @@ def responses( try: litellm_logging_obj: LiteLLMLoggingObj = kwargs.get("litellm_logging_obj") # type: ignore litellm_call_id: Optional[str] = kwargs.get("litellm_call_id", None) - _is_async = kwargs.get("aresponses", False) is True + _is_async = kwargs.pop("aresponses", False) is True # Convert text_format to text parameter if provided text = ResponsesAPIRequestUtils.convert_text_format_to_text_param(