langfuse-haystack 2.0.0__tar.gz → 2.1.0__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.1.0}/CHANGELOG.md +16 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/PKG-INFO +11 -5
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/README.md +9 -3
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/pyproject.toml +29 -18
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/src/haystack_integrations/tracing/langfuse/tracer.py +59 -2
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/.gitignore +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/LICENSE.txt +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/example/basic_rag.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/example/chat.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/example/requirements.txt +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/pydoc/config.yml +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/src/haystack_integrations/components/connectors/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/src/haystack_integrations/components/connectors/langfuse/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/src/haystack_integrations/components/connectors/langfuse/langfuse_connector.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/src/haystack_integrations/tracing/langfuse/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/tests/__init__.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/tests/test_langfuse_connector.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/tests/test_tracer.py +0 -0
- {langfuse_haystack-2.0.0 → langfuse_haystack-2.1.0}/tests/test_tracing.py +0 -0
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/langfuse-v2.0.1] - 2025-06-02
|
|
4
|
+
|
|
5
|
+
### 🚀 Features
|
|
6
|
+
|
|
7
|
+
- Use Langfuse local _to_openai_dict_format function to serialize messages (#1885)
|
|
8
|
+
|
|
9
|
+
### 🌀 Miscellaneous
|
|
10
|
+
|
|
11
|
+
- Feat: Add detailed tracing for GoogleGenAIChatGenerator (#1887)
|
|
12
|
+
|
|
13
|
+
## [integrations/langfuse-v2.0.0] - 2025-05-27
|
|
14
|
+
|
|
15
|
+
### 🌀 Miscellaneous
|
|
16
|
+
|
|
17
|
+
- Add Langfuse pins (#1837)
|
|
18
|
+
|
|
3
19
|
## [integrations/langfuse-v1.1.2] - 2025-05-16
|
|
4
20
|
|
|
5
21
|
### 🌀 Miscellaneous
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langfuse-haystack
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
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
|
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
19
19
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
20
20
|
Requires-Python: >=3.9
|
|
21
21
|
Requires-Dist: haystack-ai>=2.13.0
|
|
22
|
-
Requires-Dist: langfuse
|
|
22
|
+
Requires-Dist: langfuse<3.0.0,>=2.9.0
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
25
25
|
# langfuse-haystack
|
|
@@ -135,12 +135,18 @@ pip install hatch
|
|
|
135
135
|
|
|
136
136
|
With `hatch` installed, run all the tests:
|
|
137
137
|
```
|
|
138
|
-
hatch run test
|
|
138
|
+
hatch run test:all
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
To format your code and perform linting using Ruff (with automatic fixes), run:
|
|
142
142
|
```
|
|
143
|
-
hatch run
|
|
143
|
+
hatch run fmt
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
To check for static type errors, run:
|
|
147
|
+
|
|
148
|
+
```console
|
|
149
|
+
$ hatch run test:types
|
|
144
150
|
```
|
|
145
151
|
|
|
146
152
|
## License
|
|
@@ -111,12 +111,18 @@ pip install hatch
|
|
|
111
111
|
|
|
112
112
|
With `hatch` installed, run all the tests:
|
|
113
113
|
```
|
|
114
|
-
hatch run test
|
|
114
|
+
hatch run test:all
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
To format your code and perform linting using Ruff (with automatic fixes), run:
|
|
118
118
|
```
|
|
119
|
-
hatch run
|
|
119
|
+
hatch run fmt
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
To check for static type errors, run:
|
|
123
|
+
|
|
124
|
+
```console
|
|
125
|
+
$ hatch run test:types
|
|
120
126
|
```
|
|
121
127
|
|
|
122
128
|
## License
|
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
|
22
22
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
23
23
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
24
24
|
]
|
|
25
|
-
dependencies = ["haystack-ai>=2.13.0", "langfuse>=2.9.0"]
|
|
25
|
+
dependencies = ["haystack-ai>=2.13.0", "langfuse>=2.9.0, <3.0.0"]
|
|
26
26
|
|
|
27
27
|
[project.urls]
|
|
28
28
|
Documentation = "https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/langfuse#readme"
|
|
@@ -43,23 +43,37 @@ git_describe_command = 'git describe --tags --match="integrations/langfuse-v[0-9
|
|
|
43
43
|
|
|
44
44
|
[tool.hatch.envs.default]
|
|
45
45
|
installer = "uv"
|
|
46
|
-
dependencies = [
|
|
47
|
-
|
|
48
|
-
"pytest",
|
|
49
|
-
"pytest-rerunfailures",
|
|
50
|
-
"haystack-pydoc-tools",
|
|
51
|
-
"anthropic-haystack",
|
|
52
|
-
"cohere-haystack"
|
|
53
|
-
]
|
|
46
|
+
dependencies = ["haystack-pydoc-tools", "ruff"]
|
|
47
|
+
|
|
54
48
|
[tool.hatch.envs.default.scripts]
|
|
55
|
-
test = "pytest {args:tests}"
|
|
56
|
-
test-cov = "coverage run -m pytest {args:tests}"
|
|
57
|
-
test-cov-retry = "test-cov --reruns 3 --reruns-delay 30 -x"
|
|
58
|
-
cov-report = ["- coverage combine", "coverage report"]
|
|
59
|
-
cov = ["test-cov", "cov-report"]
|
|
60
|
-
cov-retry = ["test-cov-retry", "cov-report"]
|
|
61
49
|
docs = ["pydoc-markdown pydoc/config.yml"]
|
|
50
|
+
fmt = "ruff check --fix {args} && ruff format {args}"
|
|
51
|
+
fmt-check = "ruff check {args} && ruff format --check {args}"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.envs.test]
|
|
54
|
+
dependencies = [
|
|
55
|
+
"pytest",
|
|
56
|
+
"pytest-asyncio",
|
|
57
|
+
"pytest-cov",
|
|
58
|
+
"pytest-rerunfailures",
|
|
59
|
+
"mypy",
|
|
60
|
+
"pip",
|
|
61
|
+
"anthropic-haystack",
|
|
62
|
+
"cohere-haystack",
|
|
63
|
+
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[tool.hatch.envs.test.scripts]
|
|
67
|
+
unit = 'pytest -m "not integration" {args:tests}'
|
|
68
|
+
integration = 'pytest -m "integration" {args:tests}'
|
|
69
|
+
all = 'pytest {args:tests}'
|
|
70
|
+
cov-retry = 'all --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x'
|
|
71
|
+
|
|
72
|
+
types = "mypy --install-types --non-interactive --explicit-package-bases {args:src/ tests}"
|
|
62
73
|
|
|
74
|
+
# TODO: remove lint environment once this integration is properly typed
|
|
75
|
+
# test environment should be used instead
|
|
76
|
+
# https://github.com/deepset-ai/haystack-core-integrations/issues/1771
|
|
63
77
|
[tool.hatch.envs.lint]
|
|
64
78
|
installer = "uv"
|
|
65
79
|
detached = true
|
|
@@ -72,9 +86,6 @@ dependencies = [
|
|
|
72
86
|
|
|
73
87
|
[tool.hatch.envs.lint.scripts]
|
|
74
88
|
typing = "mypy --install-types --non-interactive --explicit-package-bases {args:src/ tests}"
|
|
75
|
-
style = ["ruff check {args:}", "black --check --diff {args:.}"]
|
|
76
|
-
fmt = ["black {args:.}", "ruff check --fix {args:}", "style"]
|
|
77
|
-
all = ["style", "typing"]
|
|
78
89
|
|
|
79
90
|
[tool.hatch.metadata]
|
|
80
91
|
allow-direct-references = true
|
|
@@ -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
|