diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index c0750bb94e7..5df4523afcf 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1042,7 +1042,7 @@ class Logging(LiteLLMLoggingBaseClass): ) for logger in prompt_management_loggers: - if prompt_id is None and not self._prompt_manager_runs_without_prompt_id( + if not prompt_id and not self._prompt_manager_runs_without_prompt_id( logger=logger, prompt_spec=prompt_spec, dynamic_callback_params=dynamic_callback_params, 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 0222e756ba1..ae898b17e3b 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -5973,3 +5973,34 @@ def test_failure_handler_helper_fn_builds_payload_once_per_exception(): other_exc = _raise_and_catch(_ClientError(status_code=429, message="rate limited")) obj._failure_handler_helper_fn(exception=other_exc, traceback_exception="") assert obj.model_call_details["standard_logging_object"] is not first_payload + + +def test_prompt_hooks_skip_prompt_managers_when_prompt_id_is_empty(logging_obj, tmp_path, monkeypatch): + """ + `should_run_prompt_management_hooks` gates on `if prompt_id`, so an empty string reaches + dispatch as a call that names no prompt. Dispatch gated on `prompt_id is None`, so it + handed the call to the dotprompt manager anyway and the cache_control hook never ran. + """ + from litellm.integrations.dotprompt.dotprompt_manager import DotpromptManager + + (tmp_path / "stem.prompt").write_text("---\nmodel: claude-opus-4-5\n---\nyou are a stem tutor\n") + dotprompt_manager = DotpromptManager(prompt_directory=str(tmp_path)) + monkeypatch.setattr(litellm, "callbacks", [dotprompt_manager]) + + cache_control_params = {"cache_control_injection_points": [{"role": "system", "location": "message"}]} + messages = [ + {"role": "system", "content": "you are a stem tutor"}, + {"role": "user", "content": "hi"}, + ] + + assert logging_obj.should_run_prompt_management_hooks(prompt_id="", non_default_params=cache_control_params) + + _, compiled_messages, _ = logging_obj.get_chat_completion_prompt( + model="claude-opus-4-5", + messages=messages, + non_default_params=cache_control_params, + prompt_variables=None, + prompt_id="", + ) + + assert compiled_messages[0]["cache_control"] == {"type": "ephemeral"}