langfuse-haystack 2.0.0__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/CHANGELOG.md +6 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/PKG-INFO +1 -1
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/src/haystack_integrations/tracing/langfuse/tracer.py +59 -2
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/.gitignore +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/LICENSE.txt +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/README.md +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/example/basic_rag.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/example/chat.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/example/requirements.txt +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/pydoc/config.yml +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/pyproject.toml +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/src/haystack_integrations/components/connectors/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/src/haystack_integrations/components/connectors/langfuse/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/src/haystack_integrations/components/connectors/langfuse/langfuse_connector.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/src/haystack_integrations/tracing/langfuse/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/tests/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/tests/test_langfuse_connector.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/tests/test_tracer.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.0.1}/tests/test_tracing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langfuse-haystack
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: Langfuse integration for Haystack
|
|
5
5
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/langfuse#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
import contextlib
|
|
6
|
+
import json
|
|
6
7
|
import os
|
|
7
8
|
from abc import ABC, abstractmethod
|
|
8
9
|
from collections import Counter
|
|
@@ -45,6 +46,7 @@ _SUPPORTED_CHAT_GENERATORS = [
|
|
|
45
46
|
"HuggingFaceLocalChatGenerator",
|
|
46
47
|
"CohereChatGenerator",
|
|
47
48
|
"OllamaChatGenerator",
|
|
49
|
+
"GoogleGenAIChatGenerator",
|
|
48
50
|
]
|
|
49
51
|
_ALL_SUPPORTED_GENERATORS = _SUPPORTED_GENERATORS + _SUPPORTED_CHAT_GENERATORS
|
|
50
52
|
|
|
@@ -64,6 +66,61 @@ _COMPONENT_INPUT_KEY = "haystack.component.input"
|
|
|
64
66
|
tracing_context_var: ContextVar[Dict[Any, Any]] = ContextVar("tracing_context")
|
|
65
67
|
|
|
66
68
|
|
|
69
|
+
def _to_openai_dict_format(chat_message: ChatMessage) -> Dict[str, Any]:
|
|
70
|
+
"""
|
|
71
|
+
Convert a ChatMessage to the dictionary format expected by OpenAI's chat completion API.
|
|
72
|
+
|
|
73
|
+
Note: We already have such a method in Haystack's ChatMessage class.
|
|
74
|
+
However, the original method doesn't tolerate None values for ids of ToolCall and ToolCallResult.
|
|
75
|
+
Some generators, like GoogleGenAIChatGenerator, return None values for ids of ToolCall and ToolCallResult.
|
|
76
|
+
To seamlessly support these generators, we use this, Langfuse local, version of the method.
|
|
77
|
+
|
|
78
|
+
:param chat_message: The ChatMessage instance to convert.
|
|
79
|
+
:return: Dictionary in OpenAI Chat API format.
|
|
80
|
+
"""
|
|
81
|
+
text_contents = chat_message.texts
|
|
82
|
+
tool_calls = chat_message.tool_calls
|
|
83
|
+
tool_call_results = chat_message.tool_call_results
|
|
84
|
+
|
|
85
|
+
if not text_contents and not tool_calls and not tool_call_results:
|
|
86
|
+
message = "A `ChatMessage` must contain at least one `TextContent`, `ToolCall`, or `ToolCallResult`."
|
|
87
|
+
logger.error(message)
|
|
88
|
+
raise ValueError(message)
|
|
89
|
+
if len(text_contents) + len(tool_call_results) > 1:
|
|
90
|
+
message = "A `ChatMessage` can only contain one `TextContent` or one `ToolCallResult`."
|
|
91
|
+
logger.error(message)
|
|
92
|
+
raise ValueError(message)
|
|
93
|
+
|
|
94
|
+
openai_msg: Dict[str, Any] = {"role": chat_message._role.value}
|
|
95
|
+
|
|
96
|
+
# Add name field if present
|
|
97
|
+
if chat_message._name is not None:
|
|
98
|
+
openai_msg["name"] = chat_message._name
|
|
99
|
+
|
|
100
|
+
if tool_call_results:
|
|
101
|
+
result = tool_call_results[0]
|
|
102
|
+
openai_msg["content"] = result.result
|
|
103
|
+
openai_msg["tool_call_id"] = result.origin.id
|
|
104
|
+
# OpenAI does not provide a way to communicate errors in tool invocations, so we ignore the error field
|
|
105
|
+
return openai_msg
|
|
106
|
+
|
|
107
|
+
if text_contents:
|
|
108
|
+
openai_msg["content"] = text_contents[0]
|
|
109
|
+
if tool_calls:
|
|
110
|
+
openai_tool_calls = []
|
|
111
|
+
for tc in tool_calls:
|
|
112
|
+
openai_tool_calls.append(
|
|
113
|
+
{
|
|
114
|
+
"id": tc.id,
|
|
115
|
+
"type": "function",
|
|
116
|
+
# We disable ensure_ascii so special chars like emojis are not converted
|
|
117
|
+
"function": {"name": tc.tool_name, "arguments": json.dumps(tc.arguments, ensure_ascii=False)},
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
openai_msg["tool_calls"] = openai_tool_calls
|
|
121
|
+
return openai_msg
|
|
122
|
+
|
|
123
|
+
|
|
67
124
|
class LangfuseSpan(Span):
|
|
68
125
|
"""
|
|
69
126
|
Internal class representing a bridge between the Haystack span tracing API and Langfuse.
|
|
@@ -101,7 +158,7 @@ class LangfuseSpan(Span):
|
|
|
101
158
|
return
|
|
102
159
|
if key.endswith(".input"):
|
|
103
160
|
if "messages" in value:
|
|
104
|
-
messages = [m
|
|
161
|
+
messages = [_to_openai_dict_format(m) for m in value["messages"]]
|
|
105
162
|
self._span.update(input=messages)
|
|
106
163
|
else:
|
|
107
164
|
coerced_value = tracing_utils.coerce_tag_value(value)
|
|
@@ -109,7 +166,7 @@ class LangfuseSpan(Span):
|
|
|
109
166
|
elif key.endswith(".output"):
|
|
110
167
|
if "replies" in value:
|
|
111
168
|
if all(isinstance(r, ChatMessage) for r in value["replies"]):
|
|
112
|
-
replies = [m
|
|
169
|
+
replies = [_to_openai_dict_format(m) for m in value["replies"]]
|
|
113
170
|
else:
|
|
114
171
|
replies = value["replies"]
|
|
115
172
|
self._span.update(output=replies)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|