diff --git a/integrations/langfuse/src/haystack_integrations/tracing/langfuse/tracer.py b/integrations/langfuse/src/haystack_integrations/tracing/langfuse/tracer.py index 6304607793..f95569a9c7 100644 --- a/integrations/langfuse/src/haystack_integrations/tracing/langfuse/tracer.py +++ b/integrations/langfuse/src/haystack_integrations/tracing/langfuse/tracer.py @@ -90,7 +90,7 @@ def set_content_tag(self, key: str, value: Any) -> None: return if key.endswith(".input"): if "messages" in value: - messages = [m.to_openai_dict_format(require_tool_call_ids=False) for m in value["messages"]] + messages = [m.to_openai_dict_format(require_tool_call_ids=False) for m in (value.get("messages") or [])] if isinstance(gen_kwargs := value.get("generation_kwargs"), dict): self._span.update(input={"messages": messages, "generation_kwargs": gen_kwargs}) else: @@ -100,10 +100,11 @@ def set_content_tag(self, key: str, value: Any) -> None: self._span.update(input=coerced_value) elif key.endswith(".output"): if "replies" in value: - if all(isinstance(r, ChatMessage) for r in value["replies"]): - replies = [m.to_openai_dict_format(require_tool_call_ids=False) for m in value["replies"]] + replies_list = value.get("replies") or [] + if all(isinstance(r, ChatMessage) for r in replies_list): + replies = [m.to_openai_dict_format(require_tool_call_ids=False) for m in replies_list] else: - replies = value["replies"] + replies = replies_list self._span.update(output=replies) else: coerced_value = tracing_utils.coerce_tag_value(value) diff --git a/integrations/langfuse/tests/test_tracer.py b/integrations/langfuse/tests/test_tracer.py index 5ec1d391cb..27d0e0d4b5 100644 --- a/integrations/langfuse/tests/test_tracer.py +++ b/integrations/langfuse/tests/test_tracer.py @@ -180,6 +180,24 @@ def test_set_content_tag_updates_input_and_output_with_messages(self): # check we handle properly string list replies assert mock_context_manager._span.update.call_args_list[0][1] == {"output": ["reply1", "reply2"]} + def test_set_content_tag_messages_none_does_not_raise(self): + mock_context_manager = MockContextManager() + span = LangfuseSpan(mock_context_manager) + + with patch("haystack_integrations.tracing.langfuse.tracer.proxy_tracer.is_content_tracing_enabled", True): + span.set_content_tag("key.input", {"messages": None}) + assert mock_context_manager._span.update.call_count == 1 + assert mock_context_manager._span.update.call_args_list[0][1] == {"input": []} + + def test_set_content_tag_replies_none_does_not_raise(self): + mock_context_manager = MockContextManager() + span = LangfuseSpan(mock_context_manager) + + with patch("haystack_integrations.tracing.langfuse.tracer.proxy_tracer.is_content_tracing_enabled", True): + span.set_content_tag("key.output", {"replies": None}) + assert mock_context_manager._span.update.call_count == 1 + assert mock_context_manager._span.update.call_args_list[0][1] == {"output": []} + class TestSpanContext: def test_post_init(self):