From 63d7d04232131913b523db0660abb729a0cd012a Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Tue, 21 Jan 2025 20:26:09 -0800 Subject: [PATCH] (fix langfuse tags) - read tags from `StandardLoggingPayload` (#7903) * fix _get_langfuse_tags * fix _get_langfuse_tags * fix _get_langfuse_tags * _get_langfuse_tags * test_get_langfuse_tags * fix langfuse --- litellm/integrations/langfuse/langfuse.py | 18 ++-- .../test_langfuse_unit_tests.py | 83 ++++++++++++++++++- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 13236b210f9..6f97fd4f228 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -1,7 +1,6 @@ #### What this does #### # On success, logs events to Langfuse import copy -import json import os import traceback from collections.abc import MutableMapping, MutableSequence, MutableSet @@ -458,12 +457,15 @@ class LangFuseLogger: supports_costs = langfuse_version >= Version("2.7.3") supports_completion_start_time = langfuse_version >= Version("2.7.3") - tags = self._get_langfuse_tags(metadata) if supports_tags else [] - standard_logging_object: Optional[StandardLoggingPayload] = cast( Optional[StandardLoggingPayload], kwargs.get("standard_logging_object", None), ) + tags = ( + self._get_langfuse_tags(standard_logging_object=standard_logging_object) + if supports_tags + else [] + ) if standard_logging_object is None: end_user_id = None @@ -734,12 +736,12 @@ class LangFuseLogger: return None, None @staticmethod - def _get_langfuse_tags(metadata: dict) -> List[str]: - try: - return json.loads(metadata.pop("tags", "[]")) - except Exception as e: - verbose_logger.exception("error getting langfuse tags %s", str(e)) + def _get_langfuse_tags( + standard_logging_object: Optional[StandardLoggingPayload], + ) -> List[str]: + if standard_logging_object is None: return [] + return standard_logging_object.get("request_tags", []) or [] def add_default_langfuse_tags(self, tags, kwargs, metadata): """ diff --git a/tests/logging_callback_tests/test_langfuse_unit_tests.py b/tests/logging_callback_tests/test_langfuse_unit_tests.py index c10b6110ccf..5a551dbd7db 100644 --- a/tests/logging_callback_tests/test_langfuse_unit_tests.py +++ b/tests/logging_callback_tests/test_langfuse_unit_tests.py @@ -12,10 +12,68 @@ from litellm.integrations.langfuse.langfuse import ( LangFuseLogger, ) from litellm.integrations.langfuse.langfuse_handler import LangFuseHandler -from litellm.types.utils import StandardCallbackDynamicParams from litellm.litellm_core_utils.litellm_logging import DynamicLoggingCache from unittest.mock import Mock, patch +from litellm.types.utils import ( + StandardLoggingPayload, + StandardLoggingModelInformation, + StandardLoggingMetadata, + StandardLoggingHiddenParams, + StandardCallbackDynamicParams, +) + + +def create_standard_logging_payload() -> StandardLoggingPayload: + return StandardLoggingPayload( + id="test_id", + call_type="completion", + response_cost=0.1, + response_cost_failure_debug_info=None, + status="success", + total_tokens=30, + prompt_tokens=20, + completion_tokens=10, + startTime=1234567890.0, + endTime=1234567891.0, + completionStartTime=1234567890.5, + model_map_information=StandardLoggingModelInformation( + model_map_key="gpt-3.5-turbo", model_map_value=None + ), + model="gpt-3.5-turbo", + model_id="model-123", + model_group="openai-gpt", + api_base="https://api.openai.com", + metadata=StandardLoggingMetadata( + user_api_key_hash="test_hash", + user_api_key_org_id=None, + user_api_key_alias="test_alias", + user_api_key_team_id="test_team", + user_api_key_user_id="test_user", + user_api_key_team_alias="test_team_alias", + spend_logs_metadata=None, + requester_ip_address="127.0.0.1", + requester_metadata=None, + ), + cache_hit=False, + cache_key=None, + saved_cache_cost=0.0, + request_tags=[], + end_user=None, + requester_ip_address="127.0.0.1", + messages=[{"role": "user", "content": "Hello, world!"}], + response={"choices": [{"message": {"content": "Hi there!"}}]}, + error_str=None, + model_parameters={"stream": True}, + hidden_params=StandardLoggingHiddenParams( + model_id="model-123", + cache_key=None, + api_base="https://api.openai.com", + response_cost="0.1", + additional_headers=None, + ), + ) + @pytest.fixture def dynamic_logging_cache(): @@ -257,3 +315,26 @@ def test_get_langfuse_logger_for_request_with_cached_logger(): def test_langfuse_logger_prepare_metadata(metadata, expected_metadata): result = global_langfuse_logger._prepare_metadata(metadata) assert result == expected_metadata + + +def test_get_langfuse_tags(): + """ + Test that _get_langfuse_tags correctly extracts tags from the standard logging payload + """ + # Create a mock logging payload with tags + mock_payload = create_standard_logging_payload() + mock_payload["request_tags"] = ["tag1", "tag2", "test_tag"] + + # Test with payload containing tags + result = global_langfuse_logger._get_langfuse_tags(mock_payload) + assert result == ["tag1", "tag2", "test_tag"] + + # Test with payload without tags + mock_payload["request_tags"] = None + result = global_langfuse_logger._get_langfuse_tags(mock_payload) + assert result == [] + + # Test with empty tags list + mock_payload["request_tags"] = [] + result = global_langfuse_logger._get_langfuse_tags(mock_payload) + assert result == []