From 53cbe2e24cc27fbb4b3d7c9ca34f01542682eab0 Mon Sep 17 00:00:00 2001 From: yucheng Date: Fri, 18 Sep 2026 04:42:01 +0000 Subject: [PATCH] fix(langfuse): store resolved credentials on LangfusePromptManagement The Slack alert trace link reads langfuse_host from every registered LangFuseLogger. Prompt management subclasses it without calling the parent constructor, so it never set the attribute and the alerting handler crashed before posting Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../langfuse/langfuse_prompt_management.py | 8 +++--- .../test_slack_alerting_utils.py | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py index 9b0dfde41d2..020706aeaa8 100644 --- a/litellm/integrations/langfuse/langfuse_prompt_management.py +++ b/litellm/integrations/langfuse/langfuse_prompt_management.py @@ -163,15 +163,15 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge langfuse_host=langfuse_host, flush_interval=flush_interval, ) - public_key, secret_key, host = resolve_langfuse_credentials( + self.public_key, self.secret_key, self.langfuse_host = resolve_langfuse_credentials( langfuse_public_key=langfuse_public_key, langfuse_secret=langfuse_secret, langfuse_host=langfuse_host, ) self.tracing = acquire_langfuse_tracing( - public_key=str(public_key), - secret_key=str(secret_key), - base_url=host, + public_key=str(self.public_key), + secret_key=str(self.secret_key), + base_url=self.langfuse_host, environment=LangFuseLogger.resolve_deployment_environment(), release=os.getenv("LANGFUSE_RELEASE"), flush_interval=LangFuseLogger._get_langfuse_flush_interval(flush_interval), # pyright: ignore[reportPrivateUsage] # shared env-fallback helper, not part of the logger's API diff --git a/tests/test_litellm/integrations/SlackAlerting/test_slack_alerting_utils.py b/tests/test_litellm/integrations/SlackAlerting/test_slack_alerting_utils.py index d7e9a1c97cf..b02dbea64b8 100644 --- a/tests/test_litellm/integrations/SlackAlerting/test_slack_alerting_utils.py +++ b/tests/test_litellm/integrations/SlackAlerting/test_slack_alerting_utils.py @@ -86,6 +86,31 @@ async def test_langfuse_trace_url_when_callback_registered_as_logger_instance(mo assert result == "http://127.0.0.1:1/trace/trace-from-instance" +@pytest.mark.asyncio +async def test_langfuse_trace_url_when_prompt_management_is_the_registered_callback(monkeypatch): + """Prompt management registers a LangFuseLogger subclass; the alert must read its host, not crash.""" + from litellm.integrations.langfuse.langfuse_prompt_management import LangfusePromptManagement + + prompt_callback = LangfusePromptManagement( + langfuse_public_key="pk-slack-prompt", + langfuse_secret="sk-slack-prompt", + langfuse_host="http://127.0.0.1:2", + ) + monkeypatch.setattr(litellm, "success_callback", ["langfuse"]) + monkeypatch.setattr(litellm, "failure_callback", []) + monkeypatch.setattr(litellm, "_async_success_callback", []) + monkeypatch.setattr(litellm, "_async_failure_callback", []) + monkeypatch.setattr(litellm, "callbacks", [prompt_callback]) + monkeypatch.setenv("LANGFUSE_HOST", "http://env-host.invalid") + logging_obj = MagicMock() + logging_obj._get_trace_id.return_value = "trace-from-prompt-callback" + logging_obj.standard_callback_dynamic_params = {} + + result = await _add_langfuse_trace_id_to_alert({"litellm_logging_obj": logging_obj}) + + assert result == "http://127.0.0.1:2/trace/trace-from-prompt-callback" + + @pytest.mark.asyncio async def test_langfuse_trace_url_absent_when_trace_id_never_arrives(monkeypatch): monkeypatch.setattr(litellm, "success_callback", ["langfuse"])