langfuse-haystack 0.8.0__tar.gz → 0.9.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-0.8.0 → langfuse_haystack-0.9.0}/CHANGELOG.md +35 -9
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/PKG-INFO +3 -3
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/pyproject.toml +2 -6
- langfuse_haystack-0.9.0/src/haystack_integrations/components/connectors/__init__.py +3 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/src/haystack_integrations/components/connectors/langfuse/__init__.py +1 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/src/haystack_integrations/components/connectors/langfuse/langfuse_connector.py +8 -4
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/src/haystack_integrations/tracing/langfuse/__init__.py +1 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/src/haystack_integrations/tracing/langfuse/tracer.py +37 -8
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/tests/test_langfuse_span.py +4 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/tests/test_tracer.py +4 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/tests/test_tracing.py +43 -80
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/.gitignore +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/LICENSE.txt +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/README.md +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/example/basic_rag.py +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/example/chat.py +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/example/requirements.txt +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/pydoc/config.yml +0 -0
- {langfuse_haystack-0.8.0 → langfuse_haystack-0.9.0}/tests/__init__.py +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/langfuse-v0.8.0] - 2025-01-28
|
|
4
|
+
|
|
5
|
+
### 🚀 Features
|
|
6
|
+
|
|
7
|
+
- Add custom Langfuse span handling support (#1313)
|
|
8
|
+
|
|
9
|
+
|
|
3
10
|
## [integrations/langfuse-v0.7.0] - 2025-01-21
|
|
4
11
|
|
|
5
12
|
### 🚀 Features
|
|
@@ -22,7 +29,7 @@
|
|
|
22
29
|
|
|
23
30
|
### 🌀 Miscellaneous
|
|
24
31
|
|
|
25
|
-
-
|
|
32
|
+
- Pin haystack-ai>=2.9.0 and simplify (#1292)
|
|
26
33
|
|
|
27
34
|
## [integrations/langfuse-v0.6.2] - 2025-01-02
|
|
28
35
|
|
|
@@ -36,7 +43,7 @@
|
|
|
36
43
|
|
|
37
44
|
### 🌀 Miscellaneous
|
|
38
45
|
|
|
39
|
-
-
|
|
46
|
+
- Fix tracing_context_var lint errors (#1220)
|
|
40
47
|
- Fix messages conversion to OpenAI format (#1272)
|
|
41
48
|
|
|
42
49
|
## [integrations/langfuse-v0.6.0] - 2024-11-18
|
|
@@ -53,6 +60,25 @@
|
|
|
53
60
|
|
|
54
61
|
- Fixed TypeError in LangfuseTrace (#1184)
|
|
55
62
|
|
|
63
|
+
* Added parent_span functionality in trace method
|
|
64
|
+
|
|
65
|
+
* solved PR comments
|
|
66
|
+
|
|
67
|
+
* Readded "end()" for solving Latency issues
|
|
68
|
+
|
|
69
|
+
* chore: fix ruff linting
|
|
70
|
+
|
|
71
|
+
* Handle multiple runs
|
|
72
|
+
|
|
73
|
+
* Fix indentation and span closing
|
|
74
|
+
|
|
75
|
+
* Fix tests
|
|
76
|
+
|
|
77
|
+
---------
|
|
78
|
+
|
|
79
|
+
Co-authored-by: Vladimir Blagojevic <dovlex@gmail.com>
|
|
80
|
+
Co-authored-by: Silvano Cerza <silvanocerza@gmail.com>
|
|
81
|
+
|
|
56
82
|
## [integrations/langfuse-v0.5.0] - 2024-10-01
|
|
57
83
|
|
|
58
84
|
### 🧹 Chores
|
|
@@ -61,7 +87,7 @@
|
|
|
61
87
|
|
|
62
88
|
### 🌀 Miscellaneous
|
|
63
89
|
|
|
64
|
-
-
|
|
90
|
+
- Add delay to flush the Langfuse traces (#1091)
|
|
65
91
|
- Add invocation_context to identify traces (#1089)
|
|
66
92
|
|
|
67
93
|
## [integrations/langfuse-v0.4.0] - 2024-09-17
|
|
@@ -93,15 +119,15 @@
|
|
|
93
119
|
|
|
94
120
|
### 🌀 Miscellaneous
|
|
95
121
|
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
122
|
+
- Install pytest-rerunfailures; change test-cov script (#845)
|
|
123
|
+
- Update Langfuse README to avoid common initialization issues (#952)
|
|
124
|
+
- Ruff update, don't ruff tests (#992)
|
|
99
125
|
|
|
100
126
|
## [integrations/langfuse-v0.2.0] - 2024-06-18
|
|
101
127
|
|
|
102
128
|
### 🌀 Miscellaneous
|
|
103
129
|
|
|
104
|
-
-
|
|
130
|
+
- Add support for Azure generators (#815)
|
|
105
131
|
|
|
106
132
|
## [integrations/langfuse-v0.1.0] - 2024-06-13
|
|
107
133
|
|
|
@@ -119,7 +145,7 @@
|
|
|
119
145
|
|
|
120
146
|
### 🌀 Miscellaneous
|
|
121
147
|
|
|
122
|
-
-
|
|
123
|
-
-
|
|
148
|
+
- Change the pydoc renderer class (#718)
|
|
149
|
+
- Missing api references (#728)
|
|
124
150
|
|
|
125
151
|
<!-- generated by git-cliff -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langfuse-haystack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/langfuse#readme
|
|
5
5
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
6
6
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/langfuse
|
|
@@ -9,14 +9,14 @@ License-Expression: Apache-2.0
|
|
|
9
9
|
License-File: LICENSE.txt
|
|
10
10
|
Classifier: Development Status :: 4 - Beta
|
|
11
11
|
Classifier: Programming Language :: Python
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
18
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
20
|
Requires-Dist: haystack-ai>=2.9.0
|
|
21
21
|
Requires-Dist: langfuse
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
@@ -7,18 +7,18 @@ name = "langfuse-haystack"
|
|
|
7
7
|
dynamic = ["version"]
|
|
8
8
|
description = ''
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = []
|
|
13
13
|
authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
|
|
14
14
|
classifiers = [
|
|
15
15
|
"Development Status :: 4 - Beta",
|
|
16
16
|
"Programming Language :: Python",
|
|
17
|
-
"Programming Language :: Python :: 3.8",
|
|
18
17
|
"Programming Language :: Python :: 3.9",
|
|
19
18
|
"Programming Language :: Python :: 3.10",
|
|
20
19
|
"Programming Language :: Python :: 3.11",
|
|
21
20
|
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
22
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
23
23
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
24
24
|
]
|
|
@@ -60,10 +60,6 @@ cov = ["test-cov", "cov-report"]
|
|
|
60
60
|
cov-retry = ["test-cov-retry", "cov-report"]
|
|
61
61
|
docs = ["pydoc-markdown pydoc/config.yml"]
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
[[tool.hatch.envs.all.matrix]]
|
|
65
|
-
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
|
66
|
-
|
|
67
63
|
[tool.hatch.envs.lint]
|
|
68
64
|
installer = "uv"
|
|
69
65
|
detached = true
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
1
5
|
from typing import Any, Dict, Optional
|
|
2
6
|
|
|
3
7
|
import httpx
|
|
4
8
|
from haystack import component, default_from_dict, default_to_dict, logging, tracing
|
|
5
9
|
from haystack.utils import Secret, deserialize_secrets_inplace
|
|
6
10
|
from haystack.utils.base_serialization import deserialize_class_instance, serialize_class_instance
|
|
11
|
+
from langfuse import Langfuse
|
|
7
12
|
|
|
8
13
|
from haystack_integrations.tracing.langfuse import LangfuseTracer, SpanHandler
|
|
9
|
-
from langfuse import Langfuse
|
|
10
14
|
|
|
11
15
|
logger = logging.getLogger(__name__)
|
|
12
16
|
|
|
@@ -28,7 +32,7 @@ class LangfuseConnector:
|
|
|
28
32
|
enable Haystack tracing in your pipeline.
|
|
29
33
|
|
|
30
34
|
Lastly, you may disable flushing the data after each component by setting the `HAYSTACK_LANGFUSE_ENFORCE_FLUSH`
|
|
31
|
-
|
|
35
|
+
environment variable to `false`. By default, the data is flushed after each component and blocks the thread until
|
|
32
36
|
the data is sent to Langfuse. **Caution**: Disabling this feature may result in data loss if the program crashes
|
|
33
37
|
before the data is sent to Langfuse. Make sure you will call langfuse.flush() explicitly before the program exits.
|
|
34
38
|
E.g. by using tracer.actual_tracer.flush():
|
|
@@ -159,7 +163,7 @@ class LangfuseConnector:
|
|
|
159
163
|
)
|
|
160
164
|
tracing.enable_tracing(self.tracer)
|
|
161
165
|
|
|
162
|
-
@component.output_types(name=str, trace_url=str)
|
|
166
|
+
@component.output_types(name=str, trace_url=str, trace_id=str)
|
|
163
167
|
def run(self, invocation_context: Optional[Dict[str, Any]] = None):
|
|
164
168
|
"""
|
|
165
169
|
Runs the LangfuseConnector component.
|
|
@@ -176,7 +180,7 @@ class LangfuseConnector:
|
|
|
176
180
|
"Langfuse tracer invoked with the following context: '{invocation_context}'",
|
|
177
181
|
invocation_context=invocation_context,
|
|
178
182
|
)
|
|
179
|
-
return {"name": self.name, "trace_url": self.tracer.get_trace_url()}
|
|
183
|
+
return {"name": self.name, "trace_url": self.tracer.get_trace_url(), "trace_id": self.tracer.get_trace_id()}
|
|
180
184
|
|
|
181
185
|
def to_dict(self) -> Dict[str, Any]:
|
|
182
186
|
"""
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2024-present deepset GmbH <info@deepset.ai>
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
4
5
|
from .tracer import DefaultSpanHandler, LangfuseSpan, LangfuseTracer, SpanContext, SpanHandler
|
|
5
6
|
|
|
6
7
|
__all__ = ["DefaultSpanHandler", "LangfuseSpan", "LangfuseTracer", "SpanContext", "SpanHandler"]
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
1
5
|
import contextlib
|
|
2
6
|
import os
|
|
3
7
|
from abc import ABC, abstractmethod
|
|
@@ -43,6 +47,8 @@ _ALL_SUPPORTED_GENERATORS = _SUPPORTED_GENERATORS + _SUPPORTED_CHAT_GENERATORS
|
|
|
43
47
|
|
|
44
48
|
# These are the keys used by Haystack for traces and span.
|
|
45
49
|
# We keep them here to avoid making typos when using them.
|
|
50
|
+
_PIPELINE_INPUT_KEY = "haystack.pipeline.input_data"
|
|
51
|
+
_PIPELINE_OUTPUT_KEY = "haystack.pipeline.output_data"
|
|
46
52
|
_PIPELINE_RUN_KEY = "haystack.pipeline.run"
|
|
47
53
|
_COMPONENT_NAME_KEY = "haystack.component.name"
|
|
48
54
|
_COMPONENT_TYPE_KEY = "haystack.component.type"
|
|
@@ -114,6 +120,14 @@ class LangfuseSpan(Span):
|
|
|
114
120
|
"""
|
|
115
121
|
return self._span
|
|
116
122
|
|
|
123
|
+
def get_data(self) -> Dict[str, Any]:
|
|
124
|
+
"""
|
|
125
|
+
Return the data associated with the span.
|
|
126
|
+
|
|
127
|
+
:return: The data associated with the span.
|
|
128
|
+
"""
|
|
129
|
+
return self._data
|
|
130
|
+
|
|
117
131
|
def get_correlation_data_for_logs(self) -> Dict[str, Any]:
|
|
118
132
|
return {}
|
|
119
133
|
|
|
@@ -209,7 +223,7 @@ class SpanHandler(ABC):
|
|
|
209
223
|
"""
|
|
210
224
|
Process a span after component execution by attaching metadata and metrics.
|
|
211
225
|
|
|
212
|
-
This method is called after the component yields its span, allowing you to:
|
|
226
|
+
This method is called after the component or pipeline yields its span, allowing you to:
|
|
213
227
|
- Extract and attach token usage statistics
|
|
214
228
|
- Add model information
|
|
215
229
|
- Record timing data (e.g., time-to-first-token)
|
|
@@ -234,9 +248,10 @@ class DefaultSpanHandler(SpanHandler):
|
|
|
234
248
|
"""DefaultSpanHandler provides the default Langfuse tracing behavior for Haystack."""
|
|
235
249
|
|
|
236
250
|
def create_span(self, context: SpanContext) -> LangfuseSpan:
|
|
237
|
-
message = "Tracer is not initialized"
|
|
238
251
|
if self.tracer is None:
|
|
252
|
+
message = "Tracer is not initialized"
|
|
239
253
|
raise RuntimeError(message)
|
|
254
|
+
|
|
240
255
|
tracing_ctx = tracing_context_var.get({})
|
|
241
256
|
if not context.parent_span:
|
|
242
257
|
if context.operation_name != _PIPELINE_RUN_KEY:
|
|
@@ -262,13 +277,20 @@ class DefaultSpanHandler(SpanHandler):
|
|
|
262
277
|
return LangfuseSpan(context.parent_span.raw_span().span(name=context.name))
|
|
263
278
|
|
|
264
279
|
def handle(self, span: LangfuseSpan, component_type: Optional[str]) -> None:
|
|
280
|
+
# If the span is at the pipeline level, we add input and output keys to the span
|
|
281
|
+
at_pipeline_level = span.get_data().get(_PIPELINE_INPUT_KEY) is not None
|
|
282
|
+
if at_pipeline_level:
|
|
283
|
+
span.raw_span().update(
|
|
284
|
+
input=span.get_data().get(_PIPELINE_INPUT_KEY), output=span.get_data().get(_PIPELINE_OUTPUT_KEY)
|
|
285
|
+
)
|
|
286
|
+
|
|
265
287
|
if component_type in _SUPPORTED_GENERATORS:
|
|
266
|
-
meta = span.
|
|
288
|
+
meta = span.get_data().get(_COMPONENT_OUTPUT_KEY, {}).get("meta")
|
|
267
289
|
if meta:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
replies = span.
|
|
290
|
+
span.raw_span().update(usage=meta[0].get("usage") or None, model=meta[0].get("model"))
|
|
291
|
+
|
|
292
|
+
if component_type in _SUPPORTED_CHAT_GENERATORS:
|
|
293
|
+
replies = span.get_data().get(_COMPONENT_OUTPUT_KEY, {}).get("replies")
|
|
272
294
|
if replies:
|
|
273
295
|
meta = replies[0].meta
|
|
274
296
|
completion_start_time = meta.get("completion_start_time")
|
|
@@ -278,7 +300,7 @@ class DefaultSpanHandler(SpanHandler):
|
|
|
278
300
|
except ValueError:
|
|
279
301
|
logger.error(f"Failed to parse completion_start_time: {completion_start_time}")
|
|
280
302
|
completion_start_time = None
|
|
281
|
-
span.
|
|
303
|
+
span.raw_span().update(
|
|
282
304
|
usage=meta.get("usage") or None,
|
|
283
305
|
model=meta.get("model"),
|
|
284
306
|
completion_start_time=completion_start_time,
|
|
@@ -380,3 +402,10 @@ class LangfuseTracer(Tracer):
|
|
|
380
402
|
:return: The URL to the tracing data.
|
|
381
403
|
"""
|
|
382
404
|
return self._tracer.get_trace_url()
|
|
405
|
+
|
|
406
|
+
def get_trace_id(self) -> str:
|
|
407
|
+
"""
|
|
408
|
+
Return the trace ID.
|
|
409
|
+
:return: The trace ID.
|
|
410
|
+
"""
|
|
411
|
+
return self._tracer.get_trace_id()
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
1
5
|
import os
|
|
2
6
|
import time
|
|
3
7
|
from urllib.parse import urlparse
|
|
@@ -11,7 +15,6 @@ from haystack.components.generators.chat import OpenAIChatGenerator
|
|
|
11
15
|
from haystack.dataclasses import ChatMessage
|
|
12
16
|
from haystack.utils import Secret
|
|
13
17
|
from requests.auth import HTTPBasicAuth
|
|
14
|
-
import httpx
|
|
15
18
|
|
|
16
19
|
from haystack_integrations.components.connectors.langfuse import LangfuseConnector
|
|
17
20
|
from haystack_integrations.components.generators.anthropic import AnthropicChatGenerator
|
|
@@ -23,51 +26,34 @@ from haystack_integrations.tracing.langfuse.tracer import _COMPONENT_OUTPUT_KEY
|
|
|
23
26
|
os.environ["HAYSTACK_CONTENT_TRACING_ENABLED"] = "true"
|
|
24
27
|
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
pipe.add_component("tracer", LangfuseConnector(name=f"Chat example - {expected_trace}", public=True))
|
|
31
|
-
pipe.add_component("prompt_builder", ChatPromptBuilder())
|
|
32
|
-
pipe.add_component("llm", llm_class())
|
|
33
|
-
pipe.connect("prompt_builder.prompt", "llm.messages")
|
|
34
|
-
return pipe
|
|
29
|
+
def poll_langfuse(url: str):
|
|
30
|
+
"""Utility function to poll Langfuse API until the trace is ready"""
|
|
31
|
+
# Initial wait for trace creation
|
|
32
|
+
time.sleep(10)
|
|
35
33
|
|
|
34
|
+
auth = HTTPBasicAuth(os.environ["LANGFUSE_PUBLIC_KEY"], os.environ["LANGFUSE_SECRET_KEY"])
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
pipe.connect("prompt_builder.prompt", "llm.messages")
|
|
53
|
-
return pipe
|
|
36
|
+
attempts = 5
|
|
37
|
+
delay = 1
|
|
38
|
+
|
|
39
|
+
res = None
|
|
40
|
+
while attempts > 0:
|
|
41
|
+
res = requests.get(url, auth=auth)
|
|
42
|
+
if res.status_code == 200:
|
|
43
|
+
return res
|
|
44
|
+
|
|
45
|
+
attempts -= 1
|
|
46
|
+
if attempts > 0:
|
|
47
|
+
time.sleep(delay)
|
|
48
|
+
delay *= 2
|
|
49
|
+
|
|
50
|
+
return res
|
|
54
51
|
|
|
55
52
|
|
|
56
53
|
@pytest.fixture
|
|
57
|
-
def
|
|
58
|
-
"""Pipeline factory using custom httpx client for Langfuse"""
|
|
54
|
+
def pipeline_with_env_vars(llm_class, expected_trace):
|
|
59
55
|
pipe = Pipeline()
|
|
60
|
-
|
|
61
|
-
pipe.add_component(
|
|
62
|
-
"tracer",
|
|
63
|
-
LangfuseConnector(
|
|
64
|
-
name=f"Chat example - {expected_trace}",
|
|
65
|
-
public=True,
|
|
66
|
-
secret_key=Secret.from_env_var("LANGFUSE_SECRET_KEY"),
|
|
67
|
-
public_key=Secret.from_env_var("LANGFUSE_PUBLIC_KEY"),
|
|
68
|
-
httpx_client=custom_client,
|
|
69
|
-
),
|
|
70
|
-
)
|
|
56
|
+
pipe.add_component("tracer", LangfuseConnector(name=f"Chat example - {expected_trace}", public=True))
|
|
71
57
|
pipe.add_component("prompt_builder", ChatPromptBuilder())
|
|
72
58
|
pipe.add_component("llm", llm_class())
|
|
73
59
|
pipe.connect("prompt_builder.prompt", "llm.messages")
|
|
@@ -83,9 +69,7 @@ def pipeline_with_custom_client(llm_class, expected_trace):
|
|
|
83
69
|
(CohereChatGenerator, "COHERE_API_KEY", "Cohere"),
|
|
84
70
|
],
|
|
85
71
|
)
|
|
86
|
-
@pytest.mark.parametrize(
|
|
87
|
-
"pipeline_fixture", ["pipeline_with_env_vars", "pipeline_with_secrets", "pipeline_with_custom_client"]
|
|
88
|
-
)
|
|
72
|
+
@pytest.mark.parametrize("pipeline_fixture", ["pipeline_with_env_vars"])
|
|
89
73
|
def test_tracing_integration(llm_class, env_var, expected_trace, pipeline_fixture, request):
|
|
90
74
|
if not all([os.environ.get("LANGFUSE_SECRET_KEY"), os.environ.get("LANGFUSE_PUBLIC_KEY"), os.environ.get(env_var)]):
|
|
91
75
|
pytest.skip(f"Missing required environment variables: LANGFUSE_SECRET_KEY, LANGFUSE_PUBLIC_KEY, or {env_var}")
|
|
@@ -104,32 +88,23 @@ def test_tracing_integration(llm_class, env_var, expected_trace, pipeline_fixtur
|
|
|
104
88
|
)
|
|
105
89
|
assert "Berlin" in response["llm"]["replies"][0].text
|
|
106
90
|
assert response["tracer"]["trace_url"]
|
|
91
|
+
assert response["tracer"]["trace_id"]
|
|
107
92
|
|
|
108
93
|
trace_url = response["tracer"]["trace_url"]
|
|
109
94
|
uuid = os.path.basename(urlparse(trace_url).path)
|
|
110
95
|
url = f"https://cloud.langfuse.com/api/public/traces/{uuid}"
|
|
111
96
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
delay = 1
|
|
115
|
-
while attempts >= 0:
|
|
116
|
-
res = requests.get(
|
|
117
|
-
url, auth=HTTPBasicAuth(os.environ["LANGFUSE_PUBLIC_KEY"], os.environ["LANGFUSE_SECRET_KEY"])
|
|
118
|
-
)
|
|
119
|
-
if attempts > 0 and res.status_code != 200:
|
|
120
|
-
attempts -= 1
|
|
121
|
-
time.sleep(delay)
|
|
122
|
-
delay *= 2
|
|
123
|
-
continue
|
|
124
|
-
assert res.status_code == 200, f"Failed to retrieve data from Langfuse API: {res.status_code}"
|
|
97
|
+
res = poll_langfuse(url)
|
|
98
|
+
assert res.status_code == 200, f"Failed to retrieve data from Langfuse API: {res.status_code}"
|
|
125
99
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
100
|
+
res_json = res.json()
|
|
101
|
+
assert res_json["name"] == f"Chat example - {expected_trace}"
|
|
102
|
+
assert isinstance(res_json["input"], dict)
|
|
103
|
+
assert res_json["input"]["tracer"]["invocation_context"]["user_id"] == "user_42"
|
|
104
|
+
assert isinstance(res_json["output"], dict)
|
|
105
|
+
assert isinstance(res_json["metadata"], dict)
|
|
106
|
+
assert isinstance(res_json["observations"], list)
|
|
107
|
+
assert res_json["observations"][0]["type"] == "GENERATION"
|
|
133
108
|
|
|
134
109
|
|
|
135
110
|
def test_pipeline_serialization(monkeypatch):
|
|
@@ -237,21 +212,9 @@ def test_custom_span_handler():
|
|
|
237
212
|
uuid = os.path.basename(urlparse(trace_url).path)
|
|
238
213
|
url = f"https://cloud.langfuse.com/api/public/traces/{uuid}"
|
|
239
214
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
delay = 1
|
|
243
|
-
while attempts >= 0:
|
|
244
|
-
res = requests.get(
|
|
245
|
-
url, auth=HTTPBasicAuth(os.environ["LANGFUSE_PUBLIC_KEY"], os.environ["LANGFUSE_SECRET_KEY"])
|
|
246
|
-
)
|
|
247
|
-
if attempts > 0 and res.status_code != 200:
|
|
248
|
-
attempts -= 1
|
|
249
|
-
time.sleep(delay)
|
|
250
|
-
delay *= 2
|
|
251
|
-
continue
|
|
215
|
+
res = poll_langfuse(url)
|
|
216
|
+
assert res.status_code == 200, f"Failed to retrieve data from Langfuse API: {res.status_code}"
|
|
252
217
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
assert "Response too long" in content
|
|
257
|
-
break
|
|
218
|
+
content = str(res.content)
|
|
219
|
+
assert "WARNING" in content
|
|
220
|
+
assert "Response too long" in content
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|