diff --git a/litellm/litellm_core_utils/initialize_dynamic_callback_params.py b/litellm/litellm_core_utils/initialize_dynamic_callback_params.py index a89dae52316..65044c8b7a2 100644 --- a/litellm/litellm_core_utils/initialize_dynamic_callback_params.py +++ b/litellm/litellm_core_utils/initialize_dynamic_callback_params.py @@ -1,5 +1,6 @@ from typing import Dict, Optional +from litellm.secret_managers.main import str_to_bool from litellm.types.utils import StandardCallbackDynamicParams @@ -23,9 +24,7 @@ def _raise_env_reference_error(param: str, *, source: str) -> None: ) -def validate_no_callback_env_reference( - param: str, value: object, *, source: str -) -> None: +def validate_no_callback_env_reference(param: str, value: object, *, source: str) -> None: if _is_env_reference(value): _raise_env_reference_error(param, source=source) @@ -78,9 +77,7 @@ def initialize_standard_callback_dynamic_params( continue if param in kwargs: _param_value = kwargs.get(param) - validate_no_callback_env_reference( - param, _param_value, source="request body" - ) + validate_no_callback_env_reference(param, _param_value, source="request body") standard_callback_dynamic_params[param] = _param_value # type: ignore # 2. Fallback: check "metadata" or "litellm_params" -> "metadata" @@ -95,9 +92,20 @@ def initialize_standard_callback_dynamic_params( continue if param not in standard_callback_dynamic_params and param in metadata: _param_value = metadata.get(param) - validate_no_callback_env_reference( - param, _param_value, source="metadata" - ) + validate_no_callback_env_reference(param, _param_value, source="metadata") standard_callback_dynamic_params[param] = _param_value # type: ignore + # turn_off_message_logging is admin-only and is read from top-level kwargs only + # (not from the metadata fallback path above, which clients can populate). + # The proxy strips any client-supplied top-level value at + # litellm_pre_call_utils.py before admin callback_vars repopulate it. + if "turn_off_message_logging" in kwargs: + _tom_value = kwargs["turn_off_message_logging"] + if isinstance(_tom_value, bool): + standard_callback_dynamic_params["turn_off_message_logging"] = _tom_value + elif isinstance(_tom_value, str): + _parsed = str_to_bool(_tom_value) + if _parsed is not None: + standard_callback_dynamic_params["turn_off_message_logging"] = _parsed + return standard_callback_dynamic_params diff --git a/tests/test_litellm/litellm_core_utils/test_initialize_dynamic_callback_params.py b/tests/test_litellm/litellm_core_utils/test_initialize_dynamic_callback_params.py index f63216b96d4..5f021b18bf9 100644 --- a/tests/test_litellm/litellm_core_utils/test_initialize_dynamic_callback_params.py +++ b/tests/test_litellm/litellm_core_utils/test_initialize_dynamic_callback_params.py @@ -100,10 +100,33 @@ def test_non_string_values_are_not_flagged(): assert params.get("langsmith_sampling_rate") == 0.5 -def test_turn_off_message_logging_not_extracted_from_request(): - """turn_off_message_logging is admin-only — must not be settable via request.""" +def test_turn_off_message_logging_extracted_from_top_level_kwargs_true(): + """turn_off_message_logging=True in top-level kwargs is picked up (admin callback_vars path).""" kwargs = {"turn_off_message_logging": True} params = initialize_standard_callback_dynamic_params(kwargs) + assert params.get("turn_off_message_logging") is True + + +def test_turn_off_message_logging_extracted_from_top_level_kwargs_false(): + """turn_off_message_logging=False (as bool or string) is picked up from top-level kwargs. + + This is the key fix: admin-configured callback_vars set turn_off_message_logging at the + top level of kwargs (litellm_pre_call_utils.py line 1733) to override global redaction. + The proxy already strips any client-supplied falsy value before admin vars are applied. + """ + for value in (False, "False", "false"): + params = initialize_standard_callback_dynamic_params({"turn_off_message_logging": value}) + assert params.get("turn_off_message_logging") is False, f"failed for value={value!r}" + + +def test_turn_off_message_logging_not_extracted_from_metadata(): + """turn_off_message_logging in request metadata is NOT picked up. + + Clients can populate metadata in their request body, so we must not read + turn_off_message_logging from the metadata fallback path. + """ + kwargs = {"metadata": {"turn_off_message_logging": False}} + params = initialize_standard_callback_dynamic_params(kwargs) assert params.get("turn_off_message_logging") is None