lmnr 0.4.56__tar.gz → 0.4.58__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.
- {lmnr-0.4.56 → lmnr-0.4.58}/PKG-INFO +51 -52
- lmnr-0.4.58/pyproject.toml +122 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/__init__.py +2 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/tracing.py +7 -1
- lmnr-0.4.58/src/lmnr/sdk/browser/playwright_patch.py +248 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/evaluations.py +110 -68
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/laminar.py +32 -20
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/types.py +8 -7
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/utils.py +1 -1
- lmnr-0.4.56/pyproject.toml +0 -123
- lmnr-0.4.56/src/lmnr/sdk/browser/playwright_patch.py +0 -192
- {lmnr-0.4.56 → lmnr-0.4.58}/LICENSE +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/README.md +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/cli.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/.flake8 +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/.python-version +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/config/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/decorators/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/decorators/base.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/instruments.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/attributes.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/content_allow_list.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/context_manager.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/in_memory_span_exporter.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/json_encoder.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/package_check.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/version.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/browser/__init__.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/datasets.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/decorators.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/eval_control.py +0 -0
- {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/log.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: lmnr
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.58
|
4
4
|
Summary: Python SDK for Laminar
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: lmnr.ai
|
@@ -41,65 +41,64 @@ Provides-Extra: watsonx
|
|
41
41
|
Provides-Extra: weaviate
|
42
42
|
Requires-Dist: aiohttp (>=3.0)
|
43
43
|
Requires-Dist: argparse (>=1.0)
|
44
|
-
Requires-Dist: deprecated (>=1.0)
|
45
44
|
Requires-Dist: grpcio (<1.68.0)
|
46
45
|
Requires-Dist: opentelemetry-api (>=1.28.0)
|
47
46
|
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (>=1.28.0)
|
48
47
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.28.0)
|
49
|
-
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.
|
50
|
-
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.
|
51
|
-
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.
|
52
|
-
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.
|
53
|
-
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.
|
54
|
-
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.
|
55
|
-
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.
|
56
|
-
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.
|
57
|
-
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.
|
58
|
-
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.
|
59
|
-
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.
|
60
|
-
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.
|
61
|
-
Requires-Dist: opentelemetry-instrumentation-groq (>=0.
|
62
|
-
Requires-Dist: opentelemetry-instrumentation-groq (>=0.
|
63
|
-
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.
|
64
|
-
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.
|
65
|
-
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.
|
66
|
-
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.
|
67
|
-
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.
|
68
|
-
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.
|
69
|
-
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.
|
70
|
-
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.
|
71
|
-
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.
|
72
|
-
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.
|
73
|
-
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.
|
74
|
-
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.
|
75
|
-
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.
|
76
|
-
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.
|
77
|
-
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.
|
78
|
-
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.
|
79
|
-
Requires-Dist: opentelemetry-instrumentation-openai (>=0.
|
80
|
-
Requires-Dist: opentelemetry-instrumentation-openai (>=0.
|
81
|
-
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.
|
82
|
-
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.
|
83
|
-
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.
|
84
|
-
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.
|
85
|
-
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.
|
86
|
-
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.
|
48
|
+
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.37.1) ; extra == "alephalpha"
|
49
|
+
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.37.1) ; extra == "all"
|
50
|
+
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.37.1) ; extra == "all"
|
51
|
+
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.37.1) ; extra == "anthropic"
|
52
|
+
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.37.1) ; extra == "all"
|
53
|
+
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.37.1) ; extra == "bedrock"
|
54
|
+
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.37.1) ; extra == "all"
|
55
|
+
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.37.1) ; extra == "chromadb"
|
56
|
+
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.37.1) ; extra == "all"
|
57
|
+
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.37.1) ; extra == "cohere"
|
58
|
+
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.37.1) ; extra == "all"
|
59
|
+
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.37.1) ; extra == "google-generativeai"
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-groq (>=0.37.1) ; extra == "all"
|
61
|
+
Requires-Dist: opentelemetry-instrumentation-groq (>=0.37.1) ; extra == "groq"
|
62
|
+
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.37.1) ; extra == "all"
|
63
|
+
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.37.1) ; extra == "haystack"
|
64
|
+
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.37.1) ; extra == "all"
|
65
|
+
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.37.1) ; extra == "lancedb"
|
66
|
+
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.37.1) ; extra == "all"
|
67
|
+
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.37.1) ; extra == "langchain"
|
68
|
+
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.37.1) ; extra == "all"
|
69
|
+
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.37.1) ; extra == "llamaindex"
|
70
|
+
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.37.1) ; extra == "all"
|
71
|
+
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.37.1) ; extra == "marqo"
|
72
|
+
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.37.1) ; extra == "all"
|
73
|
+
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.37.1) ; extra == "milvus"
|
74
|
+
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.37.1) ; extra == "all"
|
75
|
+
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.37.1) ; extra == "mistralai"
|
76
|
+
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.37.1) ; extra == "all"
|
77
|
+
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.37.1) ; extra == "ollama"
|
78
|
+
Requires-Dist: opentelemetry-instrumentation-openai (>=0.37.1) ; extra == "all"
|
79
|
+
Requires-Dist: opentelemetry-instrumentation-openai (>=0.37.1) ; extra == "openai"
|
80
|
+
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.37.1) ; extra == "all"
|
81
|
+
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.37.1) ; extra == "pinecone"
|
82
|
+
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.37.1) ; extra == "all"
|
83
|
+
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.37.1) ; extra == "qdrant"
|
84
|
+
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.37.1) ; extra == "all"
|
85
|
+
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.37.1) ; extra == "replicate"
|
87
86
|
Requires-Dist: opentelemetry-instrumentation-requests (>=0.50b0)
|
88
|
-
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.
|
89
|
-
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.
|
87
|
+
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.37.1) ; extra == "all"
|
88
|
+
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.37.1) ; extra == "sagemaker"
|
90
89
|
Requires-Dist: opentelemetry-instrumentation-sqlalchemy (>=0.50b0)
|
91
90
|
Requires-Dist: opentelemetry-instrumentation-threading (>=0.50b0)
|
92
|
-
Requires-Dist: opentelemetry-instrumentation-together (>=0.
|
93
|
-
Requires-Dist: opentelemetry-instrumentation-together (>=0.
|
94
|
-
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.
|
95
|
-
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.
|
91
|
+
Requires-Dist: opentelemetry-instrumentation-together (>=0.37.1) ; extra == "all"
|
92
|
+
Requires-Dist: opentelemetry-instrumentation-together (>=0.37.1) ; extra == "together"
|
93
|
+
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.37.1) ; extra == "all"
|
94
|
+
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.37.1) ; extra == "transformers"
|
96
95
|
Requires-Dist: opentelemetry-instrumentation-urllib3 (>=0.50b0)
|
97
|
-
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.
|
98
|
-
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.
|
99
|
-
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.
|
100
|
-
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.
|
101
|
-
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.
|
102
|
-
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.
|
96
|
+
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.37.1) ; extra == "all"
|
97
|
+
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.37.1) ; extra == "vertexai"
|
98
|
+
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.37.1) ; extra == "all"
|
99
|
+
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.37.1) ; extra == "watsonx"
|
100
|
+
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.37.1) ; extra == "all"
|
101
|
+
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.37.1) ; extra == "weaviate"
|
103
102
|
Requires-Dist: opentelemetry-sdk (>=1.28.0)
|
104
103
|
Requires-Dist: opentelemetry-semantic-conventions-ai (>=0.4.2)
|
105
104
|
Requires-Dist: pydantic (>=2.0.3)
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Laminar Python
|
2
|
+
|
3
|
+
# If you are looking for information about possible extras installations,
|
4
|
+
# i.e. what you can pass into `pip install 'lmnr[extra1,extra2]'`, please see the
|
5
|
+
# `[project.optional-dependencies]` section below.
|
6
|
+
|
7
|
+
[project]
|
8
|
+
name = "lmnr"
|
9
|
+
version = "0.4.58"
|
10
|
+
description = "Python SDK for Laminar"
|
11
|
+
authors = [
|
12
|
+
{ name = "lmnr.ai", email = "founders@lmnr.ai" }
|
13
|
+
]
|
14
|
+
readme = "README.md"
|
15
|
+
requires-python = ">=3.9,<4"
|
16
|
+
license = "Apache-2.0"
|
17
|
+
dependencies = [
|
18
|
+
"pydantic (>=2.0.3)",
|
19
|
+
"requests (>=2.0)",
|
20
|
+
"python-dotenv (>=1.0)",
|
21
|
+
"opentelemetry-api (>=1.28.0)",
|
22
|
+
"opentelemetry-sdk (>=1.28.0)",
|
23
|
+
"opentelemetry-exporter-otlp-proto-http (>=1.28.0)",
|
24
|
+
"opentelemetry-exporter-otlp-proto-grpc (>=1.28.0)",
|
25
|
+
"opentelemetry-instrumentation-requests (>=0.50b0)",
|
26
|
+
"opentelemetry-instrumentation-sqlalchemy (>=0.50b0)",
|
27
|
+
"opentelemetry-instrumentation-urllib3 (>=0.50b0)",
|
28
|
+
"opentelemetry-instrumentation-threading (>=0.50b0)",
|
29
|
+
"opentelemetry-semantic-conventions-ai (>=0.4.2)",
|
30
|
+
"tqdm (>=4.0)",
|
31
|
+
"argparse (>=1.0)",
|
32
|
+
"aiohttp (>=3.0)",
|
33
|
+
"tenacity (>=8.0)",
|
34
|
+
# explicitly freeze grpcio. Since 1.68.0, grpcio writes a warning message
|
35
|
+
# that looks scary, but is harmless.
|
36
|
+
# WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
|
37
|
+
# E0000 00:00:1737439981.199902 9456033 init.cc:229] grpc_wait_for_shutdown_with_timeout() timed out.
|
38
|
+
#
|
39
|
+
# Related issue:
|
40
|
+
# https://discuss.ai.google.dev/t/warning-all-log-messages-before-absl-initializelog-is-called-are-written-to-stderr-e0000-001731955515-629532-17124-init-cc-229-grpc-wait-for-shutdown-with-timeout-timed-out/50020
|
41
|
+
# https://github.com/grpc/grpc/issues/38490
|
42
|
+
"grpcio<1.68.0",
|
43
|
+
]
|
44
|
+
|
45
|
+
[project.scripts]
|
46
|
+
lmnr = "lmnr.cli:cli"
|
47
|
+
|
48
|
+
[project.optional-dependencies]
|
49
|
+
# List of all possible extras. You can specify one or more of these extras
|
50
|
+
# when installing the package, using any of the following examples:
|
51
|
+
# `pip install 'lmnr[anthropic,openai]'`
|
52
|
+
# `uv pip install 'lmnr[anthropic,openai]'`
|
53
|
+
# `uv add lmnr --extra anthropic --extra openai`
|
54
|
+
# `poetry add 'lmnr[anthropic,openai]'`
|
55
|
+
|
56
|
+
alephalpha=["opentelemetry-instrumentation-alephalpha>=0.37.1"]
|
57
|
+
anthropic=["opentelemetry-instrumentation-anthropic>=0.37.1"]
|
58
|
+
bedrock=["opentelemetry-instrumentation-bedrock>=0.37.1"]
|
59
|
+
chromadb=["opentelemetry-instrumentation-chromadb>=0.37.1"]
|
60
|
+
cohere=["opentelemetry-instrumentation-cohere>=0.37.1"]
|
61
|
+
google-generativeai=["opentelemetry-instrumentation-google-generativeai>=0.37.1"]
|
62
|
+
groq=["opentelemetry-instrumentation-groq>=0.37.1"]
|
63
|
+
haystack=["opentelemetry-instrumentation-haystack>=0.37.1"]
|
64
|
+
lancedb=["opentelemetry-instrumentation-lancedb>=0.37.1"]
|
65
|
+
langchain=["opentelemetry-instrumentation-langchain>=0.37.1"]
|
66
|
+
llamaindex=["opentelemetry-instrumentation-llamaindex>=0.37.1"]
|
67
|
+
marqo=["opentelemetry-instrumentation-marqo>=0.37.1"]
|
68
|
+
milvus=["opentelemetry-instrumentation-milvus>=0.37.1"]
|
69
|
+
mistralai=["opentelemetry-instrumentation-mistralai>=0.37.1"]
|
70
|
+
ollama=["opentelemetry-instrumentation-ollama>=0.37.1"]
|
71
|
+
openai=["opentelemetry-instrumentation-openai>=0.37.1"]
|
72
|
+
pinecone=["opentelemetry-instrumentation-pinecone>=0.37.1"]
|
73
|
+
qdrant=["opentelemetry-instrumentation-qdrant>=0.37.1"]
|
74
|
+
replicate=["opentelemetry-instrumentation-replicate>=0.37.1"]
|
75
|
+
sagemaker=["opentelemetry-instrumentation-sagemaker>=0.37.1"]
|
76
|
+
together=["opentelemetry-instrumentation-together>=0.37.1"]
|
77
|
+
transformers=["opentelemetry-instrumentation-transformers>=0.37.1"]
|
78
|
+
vertexai=["opentelemetry-instrumentation-vertexai>=0.37.1"]
|
79
|
+
watsonx=["opentelemetry-instrumentation-watsonx>=0.37.1"]
|
80
|
+
weaviate=["opentelemetry-instrumentation-weaviate>=0.37.1"]
|
81
|
+
# `all` is the group added for convenience, if you want to install all
|
82
|
+
# the instrumentations.
|
83
|
+
all = [
|
84
|
+
"opentelemetry-instrumentation-alephalpha>=0.37.1",
|
85
|
+
"opentelemetry-instrumentation-anthropic>=0.37.1",
|
86
|
+
"opentelemetry-instrumentation-bedrock>=0.37.1",
|
87
|
+
"opentelemetry-instrumentation-chromadb>=0.37.1",
|
88
|
+
"opentelemetry-instrumentation-cohere>=0.37.1",
|
89
|
+
"opentelemetry-instrumentation-google-generativeai>=0.37.1",
|
90
|
+
"opentelemetry-instrumentation-groq>=0.37.1",
|
91
|
+
"opentelemetry-instrumentation-haystack>=0.37.1",
|
92
|
+
"opentelemetry-instrumentation-lancedb>=0.37.1",
|
93
|
+
"opentelemetry-instrumentation-langchain>=0.37.1",
|
94
|
+
"opentelemetry-instrumentation-llamaindex>=0.37.1",
|
95
|
+
"opentelemetry-instrumentation-marqo>=0.37.1",
|
96
|
+
"opentelemetry-instrumentation-milvus>=0.37.1",
|
97
|
+
"opentelemetry-instrumentation-mistralai>=0.37.1",
|
98
|
+
"opentelemetry-instrumentation-ollama>=0.37.1",
|
99
|
+
"opentelemetry-instrumentation-openai>=0.37.1",
|
100
|
+
"opentelemetry-instrumentation-pinecone>=0.37.1",
|
101
|
+
"opentelemetry-instrumentation-qdrant>=0.37.1",
|
102
|
+
"opentelemetry-instrumentation-replicate>=0.37.1",
|
103
|
+
"opentelemetry-instrumentation-sagemaker>=0.37.1",
|
104
|
+
"opentelemetry-instrumentation-together>=0.37.1",
|
105
|
+
"opentelemetry-instrumentation-transformers>=0.37.1",
|
106
|
+
"opentelemetry-instrumentation-vertexai>=0.37.1",
|
107
|
+
"opentelemetry-instrumentation-watsonx>=0.37.1",
|
108
|
+
"opentelemetry-instrumentation-weaviate>=0.37.1"
|
109
|
+
]
|
110
|
+
|
111
|
+
[dependency-groups]
|
112
|
+
dev = [
|
113
|
+
"autopep8",
|
114
|
+
"flake8",
|
115
|
+
"pytest>=8.3.4",
|
116
|
+
"pytest-sugar",
|
117
|
+
"pytest-asyncio>=0.25.2"
|
118
|
+
]
|
119
|
+
|
120
|
+
[build-system]
|
121
|
+
requires = ["poetry-core"]
|
122
|
+
build-backend = "poetry.core.masonry.api"
|
@@ -34,6 +34,7 @@ class Traceloop:
|
|
34
34
|
instruments: Optional[Set[Instruments]] = None,
|
35
35
|
base_http_url: Optional[str] = None,
|
36
36
|
project_api_key: Optional[str] = None,
|
37
|
+
max_export_batch_size: Optional[int] = None,
|
37
38
|
) -> None:
|
38
39
|
if not is_tracing_enabled():
|
39
40
|
return
|
@@ -73,4 +74,5 @@ class Traceloop:
|
|
73
74
|
instruments=instruments,
|
74
75
|
base_http_url=base_http_url,
|
75
76
|
project_api_key=project_api_key,
|
77
|
+
max_export_batch_size=max_export_batch_size,
|
76
78
|
)
|
@@ -83,6 +83,7 @@ class TracerWrapper(object):
|
|
83
83
|
instruments: Optional[Set[Instruments]] = None,
|
84
84
|
base_http_url: Optional[str] = None,
|
85
85
|
project_api_key: Optional[str] = None,
|
86
|
+
max_export_batch_size: Optional[int] = None,
|
86
87
|
) -> "TracerWrapper":
|
87
88
|
cls._initialize_logger(cls)
|
88
89
|
if not hasattr(cls, "instance"):
|
@@ -109,7 +110,8 @@ class TracerWrapper(object):
|
|
109
110
|
)
|
110
111
|
else:
|
111
112
|
obj.__spans_processor: SpanProcessor = BatchSpanProcessor(
|
112
|
-
obj.__spans_exporter
|
113
|
+
obj.__spans_exporter,
|
114
|
+
max_export_batch_size=max_export_batch_size,
|
113
115
|
)
|
114
116
|
obj.__spans_processor_original_on_start = None
|
115
117
|
|
@@ -430,6 +432,10 @@ def init_openai_instrumentor(should_enrich_metrics: bool):
|
|
430
432
|
instrumentor = OpenAIInstrumentor(
|
431
433
|
enrich_assistant=should_enrich_metrics,
|
432
434
|
enrich_token_usage=should_enrich_metrics,
|
435
|
+
# Default in the package provided is an empty function, which
|
436
|
+
# results in dropping the image data if we don't explicitly
|
437
|
+
# set it to None.
|
438
|
+
upload_base64_image=None,
|
433
439
|
)
|
434
440
|
if not instrumentor.is_instrumented_by_opentelemetry:
|
435
441
|
instrumentor.instrument()
|
@@ -0,0 +1,248 @@
|
|
1
|
+
import opentelemetry
|
2
|
+
import uuid
|
3
|
+
import asyncio
|
4
|
+
|
5
|
+
try:
|
6
|
+
from playwright.async_api import BrowserContext, Page
|
7
|
+
from playwright.sync_api import (
|
8
|
+
BrowserContext as SyncBrowserContext,
|
9
|
+
Page as SyncPage,
|
10
|
+
)
|
11
|
+
except ImportError as e:
|
12
|
+
raise ImportError(
|
13
|
+
f"Attempted to import {__file__}, but it is designed "
|
14
|
+
"to patch Playwright, which is not installed. Use `pip install playwright` "
|
15
|
+
"to install Playwright or remove this import."
|
16
|
+
) from e
|
17
|
+
|
18
|
+
_original_new_page = None
|
19
|
+
_original_new_page_async = None
|
20
|
+
|
21
|
+
INJECT_PLACEHOLDER = """
|
22
|
+
([baseUrl, projectApiKey]) => {
|
23
|
+
const serverUrl = `${baseUrl}/v1/browser-sessions/events`;
|
24
|
+
const FLUSH_INTERVAL = 1000;
|
25
|
+
const HEARTBEAT_INTERVAL = 1000;
|
26
|
+
|
27
|
+
window.rrwebEventsBatch = [];
|
28
|
+
|
29
|
+
window.sendBatch = async () => {
|
30
|
+
if (window.rrwebEventsBatch.length === 0) return;
|
31
|
+
|
32
|
+
const eventsPayload = {
|
33
|
+
sessionId: window.rrwebSessionId,
|
34
|
+
traceId: window.traceId,
|
35
|
+
events: window.rrwebEventsBatch
|
36
|
+
};
|
37
|
+
|
38
|
+
try {
|
39
|
+
const jsonString = JSON.stringify(eventsPayload);
|
40
|
+
const uint8Array = new TextEncoder().encode(jsonString);
|
41
|
+
|
42
|
+
const cs = new CompressionStream('gzip');
|
43
|
+
const compressedStream = await new Response(
|
44
|
+
new Response(uint8Array).body.pipeThrough(cs)
|
45
|
+
).arrayBuffer();
|
46
|
+
|
47
|
+
const compressedArray = new Uint8Array(compressedStream);
|
48
|
+
|
49
|
+
const blob = new Blob([compressedArray], { type: 'application/octet-stream' });
|
50
|
+
|
51
|
+
const response = await fetch(serverUrl, {
|
52
|
+
method: 'POST',
|
53
|
+
headers: {
|
54
|
+
'Content-Type': 'application/json',
|
55
|
+
'Content-Encoding': 'gzip',
|
56
|
+
'Authorization': `Bearer ${projectApiKey}`
|
57
|
+
},
|
58
|
+
body: blob,
|
59
|
+
credentials: 'omit',
|
60
|
+
mode: 'cors',
|
61
|
+
cache: 'no-cache',
|
62
|
+
});
|
63
|
+
|
64
|
+
if (!response.ok) {
|
65
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
66
|
+
}
|
67
|
+
|
68
|
+
window.rrwebEventsBatch = [];
|
69
|
+
} catch (error) {
|
70
|
+
console.error('Failed to send events:', error);
|
71
|
+
}
|
72
|
+
};
|
73
|
+
|
74
|
+
setInterval(() => window.sendBatch(), FLUSH_INTERVAL);
|
75
|
+
|
76
|
+
setInterval(() => {
|
77
|
+
window.rrwebEventsBatch.push({
|
78
|
+
type: 6,
|
79
|
+
data: { source: 'heartbeat' },
|
80
|
+
timestamp: Date.now()
|
81
|
+
});
|
82
|
+
}, HEARTBEAT_INTERVAL);
|
83
|
+
|
84
|
+
window.rrweb.record({
|
85
|
+
emit(event) {
|
86
|
+
window.rrwebEventsBatch.push(event);
|
87
|
+
}
|
88
|
+
});
|
89
|
+
|
90
|
+
window.addEventListener('beforeunload', () => {
|
91
|
+
window.sendBatch();
|
92
|
+
});
|
93
|
+
}
|
94
|
+
"""
|
95
|
+
|
96
|
+
|
97
|
+
def init_playwright_tracing(http_url: str, project_api_key: str):
|
98
|
+
|
99
|
+
def inject_rrweb(page: SyncPage):
|
100
|
+
# Get current trace ID from active span
|
101
|
+
current_span = opentelemetry.trace.get_current_span()
|
102
|
+
current_span.set_attribute("lmnr.internal.has_browser_session", True)
|
103
|
+
trace_id = format(current_span.get_span_context().trace_id, "032x")
|
104
|
+
session_id = str(uuid.uuid4().hex)
|
105
|
+
|
106
|
+
# Generate UUID session ID and set trace ID
|
107
|
+
page.evaluate(
|
108
|
+
"""([traceId, sessionId]) => {
|
109
|
+
window.rrwebSessionId = sessionId;
|
110
|
+
window.traceId = traceId;
|
111
|
+
}""",
|
112
|
+
[trace_id, session_id],
|
113
|
+
)
|
114
|
+
|
115
|
+
# Load rrweb from CDN
|
116
|
+
page.add_script_tag(
|
117
|
+
url="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"
|
118
|
+
)
|
119
|
+
|
120
|
+
# Update the recording setup to include trace ID
|
121
|
+
page.evaluate(
|
122
|
+
INJECT_PLACEHOLDER,
|
123
|
+
[http_url, project_api_key],
|
124
|
+
)
|
125
|
+
|
126
|
+
async def inject_rrweb_async(page: Page):
|
127
|
+
try:
|
128
|
+
# Wait for the page to be in a ready state first
|
129
|
+
await page.wait_for_load_state("domcontentloaded")
|
130
|
+
|
131
|
+
# Get current trace ID from active span
|
132
|
+
current_span = opentelemetry.trace.get_current_span()
|
133
|
+
current_span.set_attribute("lmnr.internal.has_browser_session", True)
|
134
|
+
trace_id = format(current_span.get_span_context().trace_id, "032x")
|
135
|
+
session_id = str(uuid.uuid4().hex)
|
136
|
+
|
137
|
+
# Generate UUID session ID and set trace ID
|
138
|
+
await page.evaluate(
|
139
|
+
"""([traceId, sessionId]) => {
|
140
|
+
window.rrwebSessionId = sessionId;
|
141
|
+
window.traceId = traceId;
|
142
|
+
}""",
|
143
|
+
[trace_id, session_id],
|
144
|
+
)
|
145
|
+
|
146
|
+
# Load rrweb from CDN
|
147
|
+
await page.add_script_tag(
|
148
|
+
url="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"
|
149
|
+
)
|
150
|
+
|
151
|
+
await page.wait_for_function(
|
152
|
+
"""(() => window.rrweb || 'rrweb' in window)"""
|
153
|
+
)
|
154
|
+
|
155
|
+
# Update the recording setup to include trace ID
|
156
|
+
await page.evaluate(
|
157
|
+
INJECT_PLACEHOLDER,
|
158
|
+
[http_url, project_api_key],
|
159
|
+
)
|
160
|
+
except Exception as e:
|
161
|
+
print(f"Error injecting rrweb: {e}")
|
162
|
+
|
163
|
+
def handle_navigation(page: SyncPage):
|
164
|
+
def on_load():
|
165
|
+
inject_rrweb(page)
|
166
|
+
|
167
|
+
page.on("load", on_load)
|
168
|
+
inject_rrweb(page)
|
169
|
+
|
170
|
+
async def handle_navigation_async(page: Page):
|
171
|
+
async def on_load():
|
172
|
+
await inject_rrweb_async(page)
|
173
|
+
|
174
|
+
page.on("load", lambda: asyncio.create_task(on_load()))
|
175
|
+
await inject_rrweb_async(page)
|
176
|
+
|
177
|
+
async def patched_new_page_async(self: BrowserContext, *args, **kwargs):
|
178
|
+
# Modify CSP to allow required domains
|
179
|
+
async def handle_route(route):
|
180
|
+
try:
|
181
|
+
response = await route.fetch()
|
182
|
+
headers = dict(response.headers)
|
183
|
+
|
184
|
+
# Find and modify CSP header
|
185
|
+
for header_name in headers:
|
186
|
+
if header_name.lower() == "content-security-policy":
|
187
|
+
csp = headers[header_name]
|
188
|
+
parts = csp.split(";")
|
189
|
+
for i, part in enumerate(parts):
|
190
|
+
if "script-src" in part:
|
191
|
+
parts[i] = f"{part.strip()} cdn.jsdelivr.net"
|
192
|
+
elif "connect-src" in part:
|
193
|
+
parts[i] = f"{part.strip()} " + http_url
|
194
|
+
if not any("connect-src" in part for part in parts):
|
195
|
+
parts.append(" connect-src 'self' " + http_url)
|
196
|
+
headers[header_name] = ";".join(parts)
|
197
|
+
|
198
|
+
await route.fulfill(response=response, headers=headers)
|
199
|
+
except Exception:
|
200
|
+
await route.continue_()
|
201
|
+
|
202
|
+
await self.route("**/*", handle_route)
|
203
|
+
page = await _original_new_page_async(self, *args, **kwargs)
|
204
|
+
await handle_navigation_async(page)
|
205
|
+
return page
|
206
|
+
|
207
|
+
def patched_new_page(self: SyncBrowserContext, *args, **kwargs):
|
208
|
+
# Modify CSP to allow required domains
|
209
|
+
def handle_route(route):
|
210
|
+
try:
|
211
|
+
response = route.fetch()
|
212
|
+
headers = dict(response.headers)
|
213
|
+
|
214
|
+
# Find and modify CSP header
|
215
|
+
for header_name in headers:
|
216
|
+
if header_name.lower() == "content-security-policy":
|
217
|
+
csp = headers[header_name]
|
218
|
+
parts = csp.split(";")
|
219
|
+
for i, part in enumerate(parts):
|
220
|
+
if "script-src" in part:
|
221
|
+
parts[i] = f"{part.strip()} cdn.jsdelivr.net"
|
222
|
+
elif "connect-src" in part:
|
223
|
+
parts[i] = f"{part.strip()} " + http_url
|
224
|
+
if not any("connect-src" in part for part in parts):
|
225
|
+
parts.append(" connect-src 'self' " + http_url)
|
226
|
+
headers[header_name] = ";".join(parts)
|
227
|
+
|
228
|
+
route.fulfill(response=response, headers=headers)
|
229
|
+
except Exception:
|
230
|
+
# Continue with the original request without modification
|
231
|
+
route.continue_()
|
232
|
+
|
233
|
+
self.route("**/*", handle_route)
|
234
|
+
page = _original_new_page(self, *args, **kwargs)
|
235
|
+
handle_navigation(page)
|
236
|
+
return page
|
237
|
+
|
238
|
+
def patch_browser():
|
239
|
+
global _original_new_page, _original_new_page_async
|
240
|
+
if _original_new_page_async is None:
|
241
|
+
_original_new_page_async = BrowserContext.new_page
|
242
|
+
BrowserContext.new_page = patched_new_page_async
|
243
|
+
|
244
|
+
if _original_new_page is None:
|
245
|
+
_original_new_page = SyncBrowserContext.new_page
|
246
|
+
SyncBrowserContext.new_page = patched_new_page
|
247
|
+
|
248
|
+
patch_browser()
|