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.
Files changed (36) hide show
  1. {lmnr-0.4.56 → lmnr-0.4.58}/PKG-INFO +51 -52
  2. lmnr-0.4.58/pyproject.toml +122 -0
  3. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/__init__.py +2 -0
  4. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/tracing.py +7 -1
  5. lmnr-0.4.58/src/lmnr/sdk/browser/playwright_patch.py +248 -0
  6. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/evaluations.py +110 -68
  7. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/laminar.py +32 -20
  8. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/types.py +8 -7
  9. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/utils.py +1 -1
  10. lmnr-0.4.56/pyproject.toml +0 -123
  11. lmnr-0.4.56/src/lmnr/sdk/browser/playwright_patch.py +0 -192
  12. {lmnr-0.4.56 → lmnr-0.4.58}/LICENSE +0 -0
  13. {lmnr-0.4.56 → lmnr-0.4.58}/README.md +0 -0
  14. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/__init__.py +0 -0
  15. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/cli.py +0 -0
  16. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/.flake8 +0 -0
  17. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/.python-version +0 -0
  18. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/config/__init__.py +0 -0
  19. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/decorators/__init__.py +0 -0
  20. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/decorators/base.py +0 -0
  21. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/instruments.py +0 -0
  22. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/__init__.py +0 -0
  23. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/attributes.py +0 -0
  24. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/content_allow_list.py +0 -0
  25. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/tracing/context_manager.py +0 -0
  26. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/__init__.py +0 -0
  27. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/in_memory_span_exporter.py +0 -0
  28. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/json_encoder.py +0 -0
  29. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/utils/package_check.py +0 -0
  30. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/openllmetry_sdk/version.py +0 -0
  31. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/__init__.py +0 -0
  32. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/browser/__init__.py +0 -0
  33. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/datasets.py +0 -0
  34. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/decorators.py +0 -0
  35. {lmnr-0.4.56 → lmnr-0.4.58}/src/lmnr/sdk/eval_control.py +0 -0
  36. {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.56
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.36.1) ; extra == "alephalpha"
50
- Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.36.1) ; extra == "all"
51
- Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.36.1) ; extra == "all"
52
- Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.36.1) ; extra == "anthropic"
53
- Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.36.1) ; extra == "all"
54
- Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.36.1) ; extra == "bedrock"
55
- Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.36.1) ; extra == "all"
56
- Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.36.1) ; extra == "chromadb"
57
- Requires-Dist: opentelemetry-instrumentation-cohere (>=0.36.1) ; extra == "all"
58
- Requires-Dist: opentelemetry-instrumentation-cohere (>=0.36.1) ; extra == "cohere"
59
- Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.36.1) ; extra == "all"
60
- Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.36.1) ; extra == "google-generativeai"
61
- Requires-Dist: opentelemetry-instrumentation-groq (>=0.36.1) ; extra == "all"
62
- Requires-Dist: opentelemetry-instrumentation-groq (>=0.36.1) ; extra == "groq"
63
- Requires-Dist: opentelemetry-instrumentation-haystack (>=0.36.1) ; extra == "all"
64
- Requires-Dist: opentelemetry-instrumentation-haystack (>=0.36.1) ; extra == "haystack"
65
- Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.36.1) ; extra == "all"
66
- Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.36.1) ; extra == "lancedb"
67
- Requires-Dist: opentelemetry-instrumentation-langchain (>=0.36.1) ; extra == "all"
68
- Requires-Dist: opentelemetry-instrumentation-langchain (>=0.36.1) ; extra == "langchain"
69
- Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.36.1) ; extra == "all"
70
- Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.36.1) ; extra == "llamaindex"
71
- Requires-Dist: opentelemetry-instrumentation-marqo (>=0.36.1) ; extra == "all"
72
- Requires-Dist: opentelemetry-instrumentation-marqo (>=0.36.1) ; extra == "marqo"
73
- Requires-Dist: opentelemetry-instrumentation-milvus (>=0.36.1) ; extra == "all"
74
- Requires-Dist: opentelemetry-instrumentation-milvus (>=0.36.1) ; extra == "milvus"
75
- Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.36.1) ; extra == "all"
76
- Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.36.1) ; extra == "mistralai"
77
- Requires-Dist: opentelemetry-instrumentation-ollama (>=0.36.1) ; extra == "all"
78
- Requires-Dist: opentelemetry-instrumentation-ollama (>=0.36.1) ; extra == "ollama"
79
- Requires-Dist: opentelemetry-instrumentation-openai (>=0.36.1) ; extra == "all"
80
- Requires-Dist: opentelemetry-instrumentation-openai (>=0.36.1) ; extra == "openai"
81
- Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.36.1) ; extra == "all"
82
- Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.36.1) ; extra == "pinecone"
83
- Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.36.1) ; extra == "all"
84
- Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.36.1) ; extra == "qdrant"
85
- Requires-Dist: opentelemetry-instrumentation-replicate (>=0.36.1) ; extra == "all"
86
- Requires-Dist: opentelemetry-instrumentation-replicate (>=0.36.1) ; extra == "replicate"
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.36.1) ; extra == "all"
89
- Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.36.1) ; extra == "sagemaker"
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.36.1) ; extra == "all"
93
- Requires-Dist: opentelemetry-instrumentation-together (>=0.36.1) ; extra == "together"
94
- Requires-Dist: opentelemetry-instrumentation-transformers (>=0.36.1) ; extra == "all"
95
- Requires-Dist: opentelemetry-instrumentation-transformers (>=0.36.1) ; extra == "transformers"
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.36.1) ; extra == "all"
98
- Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.36.1) ; extra == "vertexai"
99
- Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.36.1) ; extra == "all"
100
- Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.36.1) ; extra == "watsonx"
101
- Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.36.1) ; extra == "all"
102
- Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.36.1) ; extra == "weaviate"
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()