diff --git a/litellm/litellm_core_utils/logging_callback_manager.py b/litellm/litellm_core_utils/logging_callback_manager.py index 34d7a7edaf5..f0d6dd2a5ae 100644 --- a/litellm/litellm_core_utils/logging_callback_manager.py +++ b/litellm/litellm_core_utils/logging_callback_manager.py @@ -1,4 +1,4 @@ -from collections.abc import Callable +from collections.abc import Callable, Sequence, Set from typing import TYPE_CHECKING, Final from weakref import WeakSet @@ -451,6 +451,35 @@ class LoggingCallbackManager: ): self.remove_callback_from_list_by_object(callback_list, obj, require_self=require_self) + def remove_callbacks_by_id(self, selector_ids: Set[int]) -> None: + """ + Remove every callback whose object identity is in ``selector_ids`` from + each callback list it may have been promoted into. + + Router strategy selectors are registered by identity (see + ``add_litellm_callback(..., dedupe_by_identity=True)``), so discarding a + Router must drop them by ``id()`` rather than by class key. + """ + for callback_list in ( + litellm.callbacks, + litellm.input_callback, + litellm.success_callback, + litellm.failure_callback, + litellm._async_success_callback, # pyright: ignore[reportPrivateUsage] # internal callback list promoted into by `function_setup` + litellm._async_failure_callback, # pyright: ignore[reportPrivateUsage] # internal callback list promoted into by `function_setup` + ): + self._remove_callbacks_by_id_in_place(callback_list, selector_ids) + + def _remove_callbacks_by_id_in_place( + self, + callback_list: Sequence[CustomLogger | Callable[..., object] | str], + selector_ids: Set[int], + ) -> None: + if not isinstance(callback_list, list): # immutable sequence -> nothing to filter + return + for callback in [c for c in callback_list if id(c) in selector_ids]: + callback_list.remove(callback) + def get_active_additional_logging_utils_from_custom_logger( self, ) -> set[AdditionalLoggingUtils]: diff --git a/litellm/router.py b/litellm/router.py index 3f8d557ff1a..1b7d5df2887 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -1561,18 +1561,7 @@ class Router: selector_ids: Final = {id(s) for s in selectors if s is not None} if not selector_ids: return - if isinstance(litellm.callbacks, list): - litellm.callbacks = [c for c in litellm.callbacks if id(c) not in selector_ids] - if isinstance(litellm.input_callback, list): - litellm.input_callback = [c for c in litellm.input_callback if id(c) not in selector_ids] - if isinstance(litellm.success_callback, list): - litellm.success_callback = [c for c in litellm.success_callback if id(c) not in selector_ids] - if isinstance(litellm.failure_callback, list): - litellm.failure_callback = [c for c in litellm.failure_callback if id(c) not in selector_ids] - if isinstance(litellm._async_success_callback, list): - litellm._async_success_callback = [c for c in litellm._async_success_callback if id(c) not in selector_ids] - if isinstance(litellm._async_failure_callback, list): - litellm._async_failure_callback = [c for c in litellm._async_failure_callback if id(c) not in selector_ids] + litellm.logging_callback_manager.remove_callbacks_by_id(selector_ids) def _apply_updated_routing_strategy_args(self) -> None: """