lmnr 0.4.57__tar.gz → 0.4.59__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.57 → lmnr-0.4.59}/PKG-INFO +51 -51
- lmnr-0.4.59/pyproject.toml +122 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/config/__init__.py +3 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/decorators/base.py +45 -27
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/tracing/attributes.py +1 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/tracing/tracing.py +16 -1
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/browser/playwright_patch.py +93 -40
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/decorators.py +16 -3
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/evaluations.py +2 -3
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/laminar.py +37 -14
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/types.py +5 -3
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/utils.py +1 -1
- lmnr-0.4.57/pyproject.toml +0 -122
- {lmnr-0.4.57 → lmnr-0.4.59}/LICENSE +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/README.md +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/cli.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/.flake8 +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/.python-version +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/decorators/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/instruments.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/tracing/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/tracing/content_allow_list.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/tracing/context_manager.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/utils/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/utils/in_memory_span_exporter.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/utils/json_encoder.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/utils/package_check.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/openllmetry_sdk/version.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/browser/__init__.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/datasets.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/src/lmnr/sdk/eval_control.py +0 -0
- {lmnr-0.4.57 → lmnr-0.4.59}/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.59
|
4
4
|
Summary: Python SDK for Laminar
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: lmnr.ai
|
@@ -45,60 +45,60 @@ Requires-Dist: grpcio (<1.68.0)
|
|
45
45
|
Requires-Dist: opentelemetry-api (>=1.28.0)
|
46
46
|
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (>=1.28.0)
|
47
47
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.28.0)
|
48
|
-
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.
|
49
|
-
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.
|
50
|
-
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.
|
51
|
-
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.
|
52
|
-
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.
|
53
|
-
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.
|
54
|
-
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.
|
55
|
-
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.
|
56
|
-
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.
|
57
|
-
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.
|
58
|
-
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.
|
59
|
-
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.
|
60
|
-
Requires-Dist: opentelemetry-instrumentation-groq (>=0.
|
61
|
-
Requires-Dist: opentelemetry-instrumentation-groq (>=0.
|
62
|
-
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.
|
63
|
-
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.
|
64
|
-
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.
|
65
|
-
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.
|
66
|
-
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.
|
67
|
-
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.
|
68
|
-
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.
|
69
|
-
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.
|
70
|
-
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.
|
71
|
-
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.
|
72
|
-
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.
|
73
|
-
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.
|
74
|
-
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.
|
75
|
-
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.
|
76
|
-
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.
|
77
|
-
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.
|
78
|
-
Requires-Dist: opentelemetry-instrumentation-openai (>=0.
|
79
|
-
Requires-Dist: opentelemetry-instrumentation-openai (>=0.
|
80
|
-
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.
|
81
|
-
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.
|
82
|
-
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.
|
83
|
-
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.
|
84
|
-
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.
|
85
|
-
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"
|
86
86
|
Requires-Dist: opentelemetry-instrumentation-requests (>=0.50b0)
|
87
|
-
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.
|
88
|
-
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"
|
89
89
|
Requires-Dist: opentelemetry-instrumentation-sqlalchemy (>=0.50b0)
|
90
90
|
Requires-Dist: opentelemetry-instrumentation-threading (>=0.50b0)
|
91
|
-
Requires-Dist: opentelemetry-instrumentation-together (>=0.
|
92
|
-
Requires-Dist: opentelemetry-instrumentation-together (>=0.
|
93
|
-
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.
|
94
|
-
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"
|
95
95
|
Requires-Dist: opentelemetry-instrumentation-urllib3 (>=0.50b0)
|
96
|
-
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.
|
97
|
-
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.
|
98
|
-
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.
|
99
|
-
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.
|
100
|
-
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.
|
101
|
-
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"
|
102
102
|
Requires-Dist: opentelemetry-sdk (>=1.28.0)
|
103
103
|
Requires-Dist: opentelemetry-semantic-conventions-ai (>=0.4.2)
|
104
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.59"
|
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"
|
@@ -4,7 +4,7 @@ import logging
|
|
4
4
|
import os
|
5
5
|
import pydantic
|
6
6
|
import types
|
7
|
-
from typing import Any, Optional
|
7
|
+
from typing import Any, Literal, Optional, Union
|
8
8
|
|
9
9
|
from opentelemetry import trace
|
10
10
|
from opentelemetry import context as context_api
|
@@ -12,9 +12,10 @@ from opentelemetry.trace import Span
|
|
12
12
|
|
13
13
|
from lmnr.sdk.utils import get_input_from_func_args, is_method
|
14
14
|
from lmnr.openllmetry_sdk.tracing import get_tracer
|
15
|
-
from lmnr.openllmetry_sdk.tracing.attributes import SPAN_INPUT, SPAN_OUTPUT
|
15
|
+
from lmnr.openllmetry_sdk.tracing.attributes import SPAN_INPUT, SPAN_OUTPUT, SPAN_TYPE
|
16
16
|
from lmnr.openllmetry_sdk.tracing.tracing import TracerWrapper
|
17
17
|
from lmnr.openllmetry_sdk.utils.json_encoder import JSONEncoder
|
18
|
+
from lmnr.openllmetry_sdk.config import MAX_MANUAL_SPAN_PAYLOAD_SIZE
|
18
19
|
|
19
20
|
|
20
21
|
class CustomJSONEncoder(JSONEncoder):
|
@@ -38,6 +39,9 @@ def json_dumps(data: dict) -> str:
|
|
38
39
|
|
39
40
|
def entity_method(
|
40
41
|
name: Optional[str] = None,
|
42
|
+
ignore_input: bool = False,
|
43
|
+
ignore_output: bool = False,
|
44
|
+
span_type: Union[Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]] = "DEFAULT",
|
41
45
|
):
|
42
46
|
def decorate(fn):
|
43
47
|
@wraps(fn)
|
@@ -48,21 +52,22 @@ def entity_method(
|
|
48
52
|
span_name = name or fn.__name__
|
49
53
|
|
50
54
|
with get_tracer() as tracer:
|
51
|
-
span = tracer.start_span(span_name)
|
55
|
+
span = tracer.start_span(span_name, attributes={SPAN_TYPE: span_type})
|
52
56
|
|
53
57
|
ctx = trace.set_span_in_context(span, context_api.get_current())
|
54
58
|
ctx_token = context_api.attach(ctx)
|
55
59
|
|
56
60
|
try:
|
57
|
-
if _should_send_prompts():
|
58
|
-
|
59
|
-
|
60
|
-
json_dumps(
|
61
|
-
get_input_from_func_args(
|
62
|
-
fn, is_method(fn), args, kwargs
|
63
|
-
)
|
64
|
-
),
|
61
|
+
if _should_send_prompts() and not ignore_input:
|
62
|
+
inp = json_dumps(
|
63
|
+
get_input_from_func_args(fn, is_method(fn), args, kwargs)
|
65
64
|
)
|
65
|
+
if len(inp) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
66
|
+
span.set_attribute(
|
67
|
+
SPAN_INPUT, "Laminar: input too large to record"
|
68
|
+
)
|
69
|
+
else:
|
70
|
+
span.set_attribute(SPAN_INPUT, inp)
|
66
71
|
except TypeError:
|
67
72
|
pass
|
68
73
|
|
@@ -78,11 +83,14 @@ def entity_method(
|
|
78
83
|
return _handle_generator(span, res)
|
79
84
|
|
80
85
|
try:
|
81
|
-
if _should_send_prompts():
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
if _should_send_prompts() and not ignore_output:
|
87
|
+
output = json_dumps(res)
|
88
|
+
if len(output) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
89
|
+
span.set_attribute(
|
90
|
+
SPAN_OUTPUT, "Laminar: output too large to record"
|
91
|
+
)
|
92
|
+
else:
|
93
|
+
span.set_attribute(SPAN_OUTPUT, output)
|
86
94
|
except TypeError:
|
87
95
|
pass
|
88
96
|
|
@@ -99,6 +107,9 @@ def entity_method(
|
|
99
107
|
# Async Decorators
|
100
108
|
def aentity_method(
|
101
109
|
name: Optional[str] = None,
|
110
|
+
ignore_input: bool = False,
|
111
|
+
ignore_output: bool = False,
|
112
|
+
span_type: Union[Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]] = "DEFAULT",
|
102
113
|
):
|
103
114
|
def decorate(fn):
|
104
115
|
@wraps(fn)
|
@@ -109,21 +120,22 @@ def aentity_method(
|
|
109
120
|
span_name = name or fn.__name__
|
110
121
|
|
111
122
|
with get_tracer() as tracer:
|
112
|
-
span = tracer.start_span(span_name)
|
123
|
+
span = tracer.start_span(span_name, attributes={SPAN_TYPE: span_type})
|
113
124
|
|
114
125
|
ctx = trace.set_span_in_context(span, context_api.get_current())
|
115
126
|
ctx_token = context_api.attach(ctx)
|
116
127
|
|
117
128
|
try:
|
118
|
-
if _should_send_prompts():
|
119
|
-
|
120
|
-
|
121
|
-
json_dumps(
|
122
|
-
get_input_from_func_args(
|
123
|
-
fn, is_method(fn), args, kwargs
|
124
|
-
)
|
125
|
-
),
|
129
|
+
if _should_send_prompts() and not ignore_input:
|
130
|
+
inp = json_dumps(
|
131
|
+
get_input_from_func_args(fn, is_method(fn), args, kwargs)
|
126
132
|
)
|
133
|
+
if len(inp) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
134
|
+
span.set_attribute(
|
135
|
+
SPAN_INPUT, "Laminar: input too large to record"
|
136
|
+
)
|
137
|
+
else:
|
138
|
+
span.set_attribute(SPAN_INPUT, inp)
|
127
139
|
except TypeError:
|
128
140
|
pass
|
129
141
|
|
@@ -139,8 +151,14 @@ def aentity_method(
|
|
139
151
|
return await _ahandle_generator(span, ctx_token, res)
|
140
152
|
|
141
153
|
try:
|
142
|
-
if _should_send_prompts():
|
143
|
-
|
154
|
+
if _should_send_prompts() and not ignore_output:
|
155
|
+
output = json_dumps(res)
|
156
|
+
if len(output) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
157
|
+
span.set_attribute(
|
158
|
+
SPAN_OUTPUT, "Laminar: output too large to record"
|
159
|
+
)
|
160
|
+
else:
|
161
|
+
span.set_attribute(SPAN_OUTPUT, output)
|
144
162
|
except TypeError:
|
145
163
|
pass
|
146
164
|
|
@@ -5,6 +5,7 @@ SPAN_INPUT = "lmnr.span.input"
|
|
5
5
|
SPAN_OUTPUT = "lmnr.span.output"
|
6
6
|
SPAN_TYPE = "lmnr.span.type"
|
7
7
|
SPAN_PATH = "lmnr.span.path"
|
8
|
+
SPAN_IDS_PATH = "lmnr.span.ids_path"
|
8
9
|
SPAN_INSTRUMENTATION_SOURCE = "lmnr.span.instrumentation_source"
|
9
10
|
OVERRIDE_PARENT_SPAN = "lmnr.internal.override_parent_span"
|
10
11
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import atexit
|
2
2
|
import copy
|
3
3
|
import logging
|
4
|
-
|
4
|
+
import uuid
|
5
5
|
|
6
6
|
from contextvars import Context
|
7
7
|
from lmnr.sdk.log import VerboseColorfulFormatter
|
@@ -9,6 +9,7 @@ from lmnr.openllmetry_sdk.instruments import Instruments
|
|
9
9
|
from lmnr.sdk.browser import init_browser_tracing
|
10
10
|
from lmnr.openllmetry_sdk.tracing.attributes import (
|
11
11
|
ASSOCIATION_PROPERTIES,
|
12
|
+
SPAN_IDS_PATH,
|
12
13
|
SPAN_INSTRUMENTATION_SOURCE,
|
13
14
|
SPAN_PATH,
|
14
15
|
TRACING_LEVEL,
|
@@ -72,6 +73,7 @@ class TracerWrapper(object):
|
|
72
73
|
__tracer_provider: TracerProvider = None
|
73
74
|
__logger: logging.Logger = None
|
74
75
|
__span_id_to_path: dict[int, list[str]] = {}
|
76
|
+
__span_id_lists: dict[int, list[str]] = {}
|
75
77
|
|
76
78
|
def __new__(
|
77
79
|
cls,
|
@@ -162,10 +164,18 @@ class TracerWrapper(object):
|
|
162
164
|
parent_span_path = span_path_in_context or (
|
163
165
|
self.__span_id_to_path.get(span.parent.span_id) if span.parent else None
|
164
166
|
)
|
167
|
+
parent_span_ids_path = (
|
168
|
+
self.__span_id_lists.get(span.parent.span_id, []) if span.parent else []
|
169
|
+
)
|
165
170
|
span_path = parent_span_path + [span.name] if parent_span_path else [span.name]
|
171
|
+
span_ids_path = parent_span_ids_path + [
|
172
|
+
str(uuid.UUID(int=span.get_span_context().span_id))
|
173
|
+
]
|
166
174
|
span.set_attribute(SPAN_PATH, span_path)
|
175
|
+
span.set_attribute(SPAN_IDS_PATH, span_ids_path)
|
167
176
|
set_value("span_path", span_path, get_current())
|
168
177
|
self.__span_id_to_path[span.get_span_context().span_id] = span_path
|
178
|
+
self.__span_id_lists[span.get_span_context().span_id] = span_ids_path
|
169
179
|
|
170
180
|
span.set_attribute(SPAN_INSTRUMENTATION_SOURCE, "python")
|
171
181
|
|
@@ -203,6 +213,7 @@ class TracerWrapper(object):
|
|
203
213
|
def clear(cls):
|
204
214
|
# Any state cleanup. Now used in between tests
|
205
215
|
cls.__span_id_to_path = {}
|
216
|
+
cls.__span_id_lists = {}
|
206
217
|
|
207
218
|
def flush(self):
|
208
219
|
self.__spans_processor.force_flush()
|
@@ -432,6 +443,10 @@ def init_openai_instrumentor(should_enrich_metrics: bool):
|
|
432
443
|
instrumentor = OpenAIInstrumentor(
|
433
444
|
enrich_assistant=should_enrich_metrics,
|
434
445
|
enrich_token_usage=should_enrich_metrics,
|
446
|
+
# Default in the package provided is an empty function, which
|
447
|
+
# results in dropping the image data if we don't explicitly
|
448
|
+
# set it to None.
|
449
|
+
upload_base64_image=None,
|
435
450
|
)
|
436
451
|
if not instrumentor.is_instrumented_by_opentelemetry:
|
437
452
|
instrumentor.instrument()
|
@@ -1,6 +1,10 @@
|
|
1
1
|
import opentelemetry
|
2
2
|
import uuid
|
3
3
|
import asyncio
|
4
|
+
import logging
|
5
|
+
import time
|
6
|
+
|
7
|
+
logger = logging.getLogger(__name__)
|
4
8
|
|
5
9
|
try:
|
6
10
|
from playwright.async_api import BrowserContext, Page
|
@@ -56,7 +60,6 @@ INJECT_PLACEHOLDER = """
|
|
56
60
|
'Authorization': `Bearer ${projectApiKey}`
|
57
61
|
},
|
58
62
|
body: blob,
|
59
|
-
compress: false,
|
60
63
|
credentials: 'omit',
|
61
64
|
mode: 'cors',
|
62
65
|
cache: 'no-cache',
|
@@ -98,9 +101,44 @@ INJECT_PLACEHOLDER = """
|
|
98
101
|
def init_playwright_tracing(http_url: str, project_api_key: str):
|
99
102
|
|
100
103
|
def inject_rrweb(page: SyncPage):
|
104
|
+
# Wait for the page to be in a ready state first
|
105
|
+
page.wait_for_load_state("domcontentloaded")
|
106
|
+
|
107
|
+
# First check if rrweb is already loaded
|
108
|
+
is_loaded = page.evaluate(
|
109
|
+
"""
|
110
|
+
() => typeof window.rrweb !== 'undefined'
|
111
|
+
"""
|
112
|
+
)
|
113
|
+
|
114
|
+
if not is_loaded:
|
115
|
+
try:
|
116
|
+
# Add retry logic for script loading
|
117
|
+
retries = 3
|
118
|
+
for attempt in range(retries):
|
119
|
+
try:
|
120
|
+
page.add_script_tag(
|
121
|
+
url="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"
|
122
|
+
)
|
123
|
+
# Verify script loaded successfully
|
124
|
+
page.wait_for_function(
|
125
|
+
"""(() => typeof window.rrweb !== 'undefined')""",
|
126
|
+
timeout=5000,
|
127
|
+
)
|
128
|
+
break
|
129
|
+
except Exception:
|
130
|
+
if attempt == retries - 1: # Last attempt
|
131
|
+
raise
|
132
|
+
time.sleep(0.5) # Wait before retry
|
133
|
+
except Exception as script_error:
|
134
|
+
logger.error("Failed to load rrweb after all retries: %s", script_error)
|
135
|
+
return
|
136
|
+
|
101
137
|
# Get current trace ID from active span
|
102
138
|
current_span = opentelemetry.trace.get_current_span()
|
103
|
-
current_span.
|
139
|
+
if current_span.is_recording():
|
140
|
+
current_span.set_attribute("lmnr.internal.has_browser_session", True)
|
141
|
+
|
104
142
|
trace_id = format(current_span.get_span_context().trace_id, "032x")
|
105
143
|
session_id = str(uuid.uuid4().hex)
|
106
144
|
|
@@ -113,11 +151,6 @@ def init_playwright_tracing(http_url: str, project_api_key: str):
|
|
113
151
|
[trace_id, session_id],
|
114
152
|
)
|
115
153
|
|
116
|
-
# Load rrweb from CDN
|
117
|
-
page.add_script_tag(
|
118
|
-
url="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"
|
119
|
-
)
|
120
|
-
|
121
154
|
# Update the recording setup to include trace ID
|
122
155
|
page.evaluate(
|
123
156
|
INJECT_PLACEHOLDER,
|
@@ -125,41 +158,61 @@ def init_playwright_tracing(http_url: str, project_api_key: str):
|
|
125
158
|
)
|
126
159
|
|
127
160
|
async def inject_rrweb_async(page: Page):
|
128
|
-
try:
|
129
|
-
# Wait for the page to be in a ready state first
|
130
|
-
await page.wait_for_load_state("domcontentloaded")
|
131
161
|
|
132
|
-
|
133
|
-
|
162
|
+
# Wait for the page to be in a ready state first
|
163
|
+
await page.wait_for_load_state("domcontentloaded")
|
164
|
+
|
165
|
+
# First check if rrweb is already loaded
|
166
|
+
is_loaded = await page.evaluate(
|
167
|
+
"""
|
168
|
+
() => typeof window.rrweb !== 'undefined'
|
169
|
+
"""
|
170
|
+
)
|
171
|
+
|
172
|
+
if not is_loaded:
|
173
|
+
try:
|
174
|
+
# Add retry logic for script loading
|
175
|
+
retries = 3
|
176
|
+
for attempt in range(retries):
|
177
|
+
try:
|
178
|
+
await page.add_script_tag(
|
179
|
+
url="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"
|
180
|
+
)
|
181
|
+
# Verify script loaded successfully
|
182
|
+
await page.wait_for_function(
|
183
|
+
"""(() => typeof window.rrweb !== 'undefined')""",
|
184
|
+
timeout=5000,
|
185
|
+
)
|
186
|
+
break
|
187
|
+
except Exception:
|
188
|
+
if attempt == retries - 1: # Last attempt
|
189
|
+
raise
|
190
|
+
await asyncio.sleep(0.5) # Wait before retry
|
191
|
+
except Exception as script_error:
|
192
|
+
logger.error("Failed to load rrweb after all retries: %s", script_error)
|
193
|
+
return
|
194
|
+
# Get current trace ID from active span
|
195
|
+
current_span = opentelemetry.trace.get_current_span()
|
196
|
+
if current_span.is_recording():
|
134
197
|
current_span.set_attribute("lmnr.internal.has_browser_session", True)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
"""(() => window.rrweb || 'rrweb' in window)"""
|
154
|
-
)
|
155
|
-
|
156
|
-
# Update the recording setup to include trace ID
|
157
|
-
await page.evaluate(
|
158
|
-
INJECT_PLACEHOLDER,
|
159
|
-
[http_url, project_api_key],
|
160
|
-
)
|
161
|
-
except Exception as e:
|
162
|
-
print(f"Error injecting rrweb: {e}")
|
198
|
+
|
199
|
+
trace_id = format(current_span.get_span_context().trace_id, "032x")
|
200
|
+
session_id = str(uuid.uuid4().hex)
|
201
|
+
|
202
|
+
# Generate UUID session ID and set trace ID
|
203
|
+
await page.evaluate(
|
204
|
+
"""([traceId, sessionId]) => {
|
205
|
+
window.rrwebSessionId = sessionId;
|
206
|
+
window.traceId = traceId;
|
207
|
+
}""",
|
208
|
+
[trace_id, session_id],
|
209
|
+
)
|
210
|
+
|
211
|
+
# Update the recording setup to include trace ID
|
212
|
+
await page.evaluate(
|
213
|
+
INJECT_PLACEHOLDER,
|
214
|
+
[http_url, project_api_key],
|
215
|
+
)
|
163
216
|
|
164
217
|
def handle_navigation(page: SyncPage):
|
165
218
|
def on_load():
|
@@ -4,7 +4,7 @@ from lmnr.openllmetry_sdk.decorators.base import (
|
|
4
4
|
)
|
5
5
|
from opentelemetry.trace import INVALID_SPAN, get_current_span
|
6
6
|
|
7
|
-
from typing import Callable, Optional, TypeVar, cast
|
7
|
+
from typing import Callable, Literal, Optional, TypeVar, Union, cast
|
8
8
|
from typing_extensions import ParamSpec
|
9
9
|
|
10
10
|
from lmnr.openllmetry_sdk.tracing.attributes import SESSION_ID
|
@@ -21,6 +21,9 @@ def observe(
|
|
21
21
|
*,
|
22
22
|
name: Optional[str] = None,
|
23
23
|
session_id: Optional[str] = None,
|
24
|
+
ignore_input: bool = False,
|
25
|
+
ignore_output: bool = False,
|
26
|
+
span_type: Union[Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]] = "DEFAULT",
|
24
27
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
25
28
|
"""The main decorator entrypoint for Laminar. This is used to wrap
|
26
29
|
functions and methods to create spans.
|
@@ -50,9 +53,19 @@ def observe(
|
|
50
53
|
association_properties["session_id"] = session_id
|
51
54
|
update_association_properties(association_properties)
|
52
55
|
return (
|
53
|
-
aentity_method(
|
56
|
+
aentity_method(
|
57
|
+
name=name,
|
58
|
+
ignore_input=ignore_input,
|
59
|
+
ignore_output=ignore_output,
|
60
|
+
span_type=span_type,
|
61
|
+
)(func)
|
54
62
|
if is_async(func)
|
55
|
-
else entity_method(
|
63
|
+
else entity_method(
|
64
|
+
name=name,
|
65
|
+
ignore_input=ignore_input,
|
66
|
+
ignore_output=ignore_output,
|
67
|
+
span_type=span_type,
|
68
|
+
)(func)
|
56
69
|
)
|
57
70
|
|
58
71
|
return cast(Callable, decorator)
|
@@ -222,9 +222,6 @@ class Evaluation:
|
|
222
222
|
self.is_finished = True
|
223
223
|
return
|
224
224
|
|
225
|
-
for result_datapoint in result_datapoints:
|
226
|
-
result_datapoint.human_evaluators = self.human_evaluators or {}
|
227
|
-
|
228
225
|
average_scores = get_average_scores(result_datapoints)
|
229
226
|
self.reporter.stop(average_scores, evaluation.projectId, evaluation.id)
|
230
227
|
self.is_finished = True
|
@@ -342,6 +339,7 @@ def evaluate(
|
|
342
339
|
http_port: Optional[int] = None,
|
343
340
|
grpc_port: Optional[int] = None,
|
344
341
|
instruments: Optional[Set[Instruments]] = None,
|
342
|
+
max_export_batch_size: Optional[int] = MAX_EXPORT_BATCH_SIZE,
|
345
343
|
) -> Optional[Awaitable[None]]:
|
346
344
|
"""
|
347
345
|
If added to the file which is called through `lmnr eval` command, then
|
@@ -422,6 +420,7 @@ def evaluate(
|
|
422
420
|
http_port=http_port,
|
423
421
|
grpc_port=grpc_port,
|
424
422
|
instruments=instruments,
|
423
|
+
max_export_batch_size=max_export_batch_size,
|
425
424
|
)
|
426
425
|
|
427
426
|
if PREPARE_ONLY.get():
|
@@ -9,6 +9,7 @@ from lmnr.openllmetry_sdk.tracing.attributes import (
|
|
9
9
|
SPAN_TYPE,
|
10
10
|
OVERRIDE_PARENT_SPAN,
|
11
11
|
)
|
12
|
+
from lmnr.openllmetry_sdk.config import MAX_MANUAL_SPAN_PAYLOAD_SIZE
|
12
13
|
from lmnr.openllmetry_sdk.decorators.base import json_dumps
|
13
14
|
from opentelemetry import context as context_api, trace
|
14
15
|
from opentelemetry.context import attach, detach
|
@@ -47,7 +48,6 @@ from lmnr.openllmetry_sdk.tracing.tracing import (
|
|
47
48
|
from .log import VerboseColorfulFormatter
|
48
49
|
|
49
50
|
from .types import (
|
50
|
-
HumanEvaluator,
|
51
51
|
InitEvaluationResponse,
|
52
52
|
EvaluationResultDatapoint,
|
53
53
|
GetDatapointsResponse,
|
@@ -323,7 +323,9 @@ class Laminar:
|
|
323
323
|
cls,
|
324
324
|
name: str,
|
325
325
|
input: Any = None,
|
326
|
-
span_type: Union[
|
326
|
+
span_type: Union[
|
327
|
+
Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]
|
328
|
+
] = "DEFAULT",
|
327
329
|
context: Optional[Context] = None,
|
328
330
|
trace_id: Optional[uuid.UUID] = None,
|
329
331
|
labels: Optional[dict[str, str]] = None,
|
@@ -402,10 +404,17 @@ class Laminar:
|
|
402
404
|
if trace_id is not None and isinstance(trace_id, uuid.UUID):
|
403
405
|
span.set_attribute(OVERRIDE_PARENT_SPAN, True)
|
404
406
|
if input is not None:
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
407
|
+
serialized_input = json_dumps(input)
|
408
|
+
if len(serialized_input) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
409
|
+
span.set_attribute(
|
410
|
+
SPAN_INPUT,
|
411
|
+
"Laminar: input too large to record",
|
412
|
+
)
|
413
|
+
else:
|
414
|
+
span.set_attribute(
|
415
|
+
SPAN_INPUT,
|
416
|
+
serialized_input,
|
417
|
+
)
|
409
418
|
yield span
|
410
419
|
|
411
420
|
# TODO: Figure out if this is necessary
|
@@ -454,7 +463,9 @@ class Laminar:
|
|
454
463
|
cls,
|
455
464
|
name: str,
|
456
465
|
input: Any = None,
|
457
|
-
span_type: Union[
|
466
|
+
span_type: Union[
|
467
|
+
Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]
|
468
|
+
] = "DEFAULT",
|
458
469
|
context: Optional[Context] = None,
|
459
470
|
trace_id: Optional[uuid.UUID] = None,
|
460
471
|
labels: Optional[dict[str, str]] = None,
|
@@ -546,10 +557,17 @@ class Laminar:
|
|
546
557
|
if trace_id is not None and isinstance(trace_id, uuid.UUID):
|
547
558
|
span.set_attribute(OVERRIDE_PARENT_SPAN, True)
|
548
559
|
if input is not None:
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
560
|
+
serialized_input = json_dumps(input)
|
561
|
+
if len(serialized_input) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
562
|
+
span.set_attribute(
|
563
|
+
SPAN_INPUT,
|
564
|
+
"Laminar: input too large to record",
|
565
|
+
)
|
566
|
+
else:
|
567
|
+
span.set_attribute(
|
568
|
+
SPAN_INPUT,
|
569
|
+
serialized_input,
|
570
|
+
)
|
553
571
|
return span
|
554
572
|
|
555
573
|
@classmethod
|
@@ -563,7 +581,14 @@ class Laminar:
|
|
563
581
|
"""
|
564
582
|
span = trace.get_current_span()
|
565
583
|
if output is not None and span != trace.INVALID_SPAN:
|
566
|
-
|
584
|
+
serialized_output = json_dumps(output)
|
585
|
+
if len(serialized_output) > MAX_MANUAL_SPAN_PAYLOAD_SIZE:
|
586
|
+
span.set_attribute(
|
587
|
+
SPAN_OUTPUT,
|
588
|
+
"Laminar: output too large to record",
|
589
|
+
)
|
590
|
+
else:
|
591
|
+
span.set_attribute(SPAN_OUTPUT, serialized_output)
|
567
592
|
|
568
593
|
@classmethod
|
569
594
|
@contextmanager
|
@@ -713,7 +738,6 @@ class Laminar:
|
|
713
738
|
eval_id: uuid.UUID,
|
714
739
|
datapoints: list[EvaluationResultDatapoint],
|
715
740
|
groupName: Optional[str] = None,
|
716
|
-
human_evaluators: Optional[list[HumanEvaluator]] = None,
|
717
741
|
):
|
718
742
|
async with aiohttp.ClientSession() as session:
|
719
743
|
|
@@ -722,7 +746,6 @@ class Laminar:
|
|
722
746
|
json={
|
723
747
|
"points": [datapoint.to_dict() for datapoint in datapoints],
|
724
748
|
"groupName": groupName,
|
725
|
-
"humanEvaluators": human_evaluators,
|
726
749
|
},
|
727
750
|
headers=cls._headers(),
|
728
751
|
) as response:
|
@@ -164,9 +164,11 @@ class EvaluationResultDatapoint(pydantic.BaseModel):
|
|
164
164
|
def to_dict(self):
|
165
165
|
try:
|
166
166
|
return {
|
167
|
-
|
168
|
-
|
169
|
-
"
|
167
|
+
# preserve only preview of the data, target and executor output
|
168
|
+
# (full data is in trace)
|
169
|
+
"data": str(serialize(self.data))[:100],
|
170
|
+
"target": str(serialize(self.target))[:100],
|
171
|
+
"executorOutput": str(serialize(self.executor_output))[:100],
|
170
172
|
"scores": self.scores,
|
171
173
|
"traceId": str(self.trace_id),
|
172
174
|
"humanEvaluators": [
|
@@ -49,7 +49,7 @@ def is_iterator(o: typing.Any) -> bool:
|
|
49
49
|
return hasattr(o, "__iter__") and hasattr(o, "__next__")
|
50
50
|
|
51
51
|
|
52
|
-
def serialize(obj: typing.Any) -> dict[str, typing.Any]:
|
52
|
+
def serialize(obj: typing.Any) -> typing.Union[str, dict[str, typing.Any]]:
|
53
53
|
def serialize_inner(o: typing.Any):
|
54
54
|
if isinstance(o, (datetime.datetime, datetime.date)):
|
55
55
|
return o.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
|
lmnr-0.4.57/pyproject.toml
DELETED
@@ -1,122 +0,0 @@
|
|
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.57"
|
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.36.1"]
|
57
|
-
anthropic=["opentelemetry-instrumentation-anthropic>=0.36.1"]
|
58
|
-
bedrock=["opentelemetry-instrumentation-bedrock>=0.36.1"]
|
59
|
-
chromadb=["opentelemetry-instrumentation-chromadb>=0.36.1"]
|
60
|
-
cohere=["opentelemetry-instrumentation-cohere>=0.36.1"]
|
61
|
-
google-generativeai=["opentelemetry-instrumentation-google-generativeai>=0.36.1"]
|
62
|
-
groq=["opentelemetry-instrumentation-groq>=0.36.1"]
|
63
|
-
haystack=["opentelemetry-instrumentation-haystack>=0.36.1"]
|
64
|
-
lancedb=["opentelemetry-instrumentation-lancedb>=0.36.1"]
|
65
|
-
langchain=["opentelemetry-instrumentation-langchain>=0.36.1"]
|
66
|
-
llamaindex=["opentelemetry-instrumentation-llamaindex>=0.36.1"]
|
67
|
-
marqo=["opentelemetry-instrumentation-marqo>=0.36.1"]
|
68
|
-
milvus=["opentelemetry-instrumentation-milvus>=0.36.1"]
|
69
|
-
mistralai=["opentelemetry-instrumentation-mistralai>=0.36.1"]
|
70
|
-
ollama=["opentelemetry-instrumentation-ollama>=0.36.1"]
|
71
|
-
openai=["opentelemetry-instrumentation-openai>=0.36.1"]
|
72
|
-
pinecone=["opentelemetry-instrumentation-pinecone>=0.36.1"]
|
73
|
-
qdrant=["opentelemetry-instrumentation-qdrant>=0.36.1"]
|
74
|
-
replicate=["opentelemetry-instrumentation-replicate>=0.36.1"]
|
75
|
-
sagemaker=["opentelemetry-instrumentation-sagemaker>=0.36.1"]
|
76
|
-
together=["opentelemetry-instrumentation-together>=0.36.1"]
|
77
|
-
transformers=["opentelemetry-instrumentation-transformers>=0.36.1"]
|
78
|
-
vertexai=["opentelemetry-instrumentation-vertexai>=0.36.1"]
|
79
|
-
watsonx=["opentelemetry-instrumentation-watsonx>=0.36.1"]
|
80
|
-
weaviate=["opentelemetry-instrumentation-weaviate>=0.36.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.36.1",
|
85
|
-
"opentelemetry-instrumentation-anthropic>=0.36.1",
|
86
|
-
"opentelemetry-instrumentation-bedrock>=0.36.1",
|
87
|
-
"opentelemetry-instrumentation-chromadb>=0.36.1",
|
88
|
-
"opentelemetry-instrumentation-cohere>=0.36.1",
|
89
|
-
"opentelemetry-instrumentation-google-generativeai>=0.36.1",
|
90
|
-
"opentelemetry-instrumentation-groq>=0.36.1",
|
91
|
-
"opentelemetry-instrumentation-haystack>=0.36.1",
|
92
|
-
"opentelemetry-instrumentation-lancedb>=0.36.1",
|
93
|
-
"opentelemetry-instrumentation-langchain>=0.36.1",
|
94
|
-
"opentelemetry-instrumentation-llamaindex>=0.36.1",
|
95
|
-
"opentelemetry-instrumentation-marqo>=0.36.1",
|
96
|
-
"opentelemetry-instrumentation-milvus>=0.36.1",
|
97
|
-
"opentelemetry-instrumentation-mistralai>=0.36.1",
|
98
|
-
"opentelemetry-instrumentation-ollama>=0.36.1",
|
99
|
-
"opentelemetry-instrumentation-openai>=0.36.1",
|
100
|
-
"opentelemetry-instrumentation-pinecone>=0.36.1",
|
101
|
-
"opentelemetry-instrumentation-qdrant>=0.36.1",
|
102
|
-
"opentelemetry-instrumentation-replicate>=0.36.1",
|
103
|
-
"opentelemetry-instrumentation-sagemaker>=0.36.1",
|
104
|
-
"opentelemetry-instrumentation-together>=0.36.1",
|
105
|
-
"opentelemetry-instrumentation-transformers>=0.36.1",
|
106
|
-
"opentelemetry-instrumentation-vertexai>=0.36.1",
|
107
|
-
"opentelemetry-instrumentation-watsonx>=0.36.1",
|
108
|
-
"opentelemetry-instrumentation-weaviate>=0.36.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"
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|