lmnr 0.6.16__py3-none-any.whl → 0.7.26__py3-none-any.whl

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 (113) hide show
  1. lmnr/__init__.py +6 -15
  2. lmnr/cli/__init__.py +270 -0
  3. lmnr/cli/datasets.py +371 -0
  4. lmnr/{cli.py → cli/evals.py} +20 -102
  5. lmnr/cli/rules.py +42 -0
  6. lmnr/opentelemetry_lib/__init__.py +9 -2
  7. lmnr/opentelemetry_lib/decorators/__init__.py +274 -168
  8. lmnr/opentelemetry_lib/litellm/__init__.py +352 -38
  9. lmnr/opentelemetry_lib/litellm/utils.py +82 -0
  10. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +849 -0
  11. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +13 -0
  12. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +211 -0
  13. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +41 -0
  14. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +401 -0
  15. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +425 -0
  16. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +332 -0
  17. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +1 -0
  18. lmnr/opentelemetry_lib/opentelemetry/instrumentation/claude_agent/__init__.py +451 -0
  19. lmnr/opentelemetry_lib/opentelemetry/instrumentation/claude_agent/proxy.py +144 -0
  20. lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_agent/__init__.py +100 -0
  21. lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/__init__.py +476 -0
  22. lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/utils.py +12 -0
  23. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +191 -129
  24. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +26 -0
  25. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +126 -41
  26. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +488 -0
  27. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +8 -0
  28. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +143 -0
  29. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +41 -0
  30. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +229 -0
  31. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +92 -0
  32. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +1 -0
  33. lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/__init__.py +381 -0
  34. lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/utils.py +36 -0
  35. lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +16 -16
  36. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +61 -0
  37. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +472 -0
  38. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +1185 -0
  39. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +305 -0
  40. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +16 -0
  41. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +312 -0
  42. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +100 -0
  43. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +41 -0
  44. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +68 -0
  45. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +197 -0
  46. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +176 -0
  47. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +368 -0
  48. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +325 -0
  49. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +135 -0
  50. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +786 -0
  51. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +1 -0
  52. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openhands_ai/__init__.py +388 -0
  53. lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +69 -0
  54. lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +59 -61
  55. lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +197 -0
  56. lmnr/opentelemetry_lib/tracing/__init__.py +119 -18
  57. lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +124 -25
  58. lmnr/opentelemetry_lib/tracing/attributes.py +4 -0
  59. lmnr/opentelemetry_lib/tracing/context.py +200 -0
  60. lmnr/opentelemetry_lib/tracing/exporter.py +109 -15
  61. lmnr/opentelemetry_lib/tracing/instruments.py +22 -5
  62. lmnr/opentelemetry_lib/tracing/processor.py +128 -30
  63. lmnr/opentelemetry_lib/tracing/span.py +398 -0
  64. lmnr/opentelemetry_lib/tracing/tracer.py +40 -1
  65. lmnr/opentelemetry_lib/tracing/utils.py +62 -0
  66. lmnr/opentelemetry_lib/utils/package_check.py +9 -0
  67. lmnr/opentelemetry_lib/utils/wrappers.py +11 -0
  68. lmnr/sdk/browser/background_send_events.py +158 -0
  69. lmnr/sdk/browser/browser_use_cdp_otel.py +100 -0
  70. lmnr/sdk/browser/browser_use_otel.py +12 -12
  71. lmnr/sdk/browser/bubus_otel.py +71 -0
  72. lmnr/sdk/browser/cdp_utils.py +518 -0
  73. lmnr/sdk/browser/inject_script.js +514 -0
  74. lmnr/sdk/browser/patchright_otel.py +18 -44
  75. lmnr/sdk/browser/playwright_otel.py +104 -187
  76. lmnr/sdk/browser/pw_utils.py +249 -210
  77. lmnr/sdk/browser/recorder/record.umd.min.cjs +84 -0
  78. lmnr/sdk/browser/utils.py +1 -1
  79. lmnr/sdk/client/asynchronous/async_client.py +47 -15
  80. lmnr/sdk/client/asynchronous/resources/__init__.py +2 -7
  81. lmnr/sdk/client/asynchronous/resources/browser_events.py +1 -0
  82. lmnr/sdk/client/asynchronous/resources/datasets.py +131 -0
  83. lmnr/sdk/client/asynchronous/resources/evals.py +122 -18
  84. lmnr/sdk/client/asynchronous/resources/evaluators.py +85 -0
  85. lmnr/sdk/client/asynchronous/resources/tags.py +4 -10
  86. lmnr/sdk/client/synchronous/resources/__init__.py +2 -2
  87. lmnr/sdk/client/synchronous/resources/datasets.py +131 -0
  88. lmnr/sdk/client/synchronous/resources/evals.py +83 -17
  89. lmnr/sdk/client/synchronous/resources/evaluators.py +85 -0
  90. lmnr/sdk/client/synchronous/resources/tags.py +4 -10
  91. lmnr/sdk/client/synchronous/sync_client.py +47 -15
  92. lmnr/sdk/datasets/__init__.py +94 -0
  93. lmnr/sdk/datasets/file_utils.py +91 -0
  94. lmnr/sdk/decorators.py +103 -23
  95. lmnr/sdk/evaluations.py +122 -33
  96. lmnr/sdk/laminar.py +816 -333
  97. lmnr/sdk/log.py +7 -2
  98. lmnr/sdk/types.py +124 -143
  99. lmnr/sdk/utils.py +115 -2
  100. lmnr/version.py +1 -1
  101. {lmnr-0.6.16.dist-info → lmnr-0.7.26.dist-info}/METADATA +71 -78
  102. lmnr-0.7.26.dist-info/RECORD +116 -0
  103. lmnr-0.7.26.dist-info/WHEEL +4 -0
  104. lmnr-0.7.26.dist-info/entry_points.txt +3 -0
  105. lmnr/opentelemetry_lib/tracing/context_properties.py +0 -65
  106. lmnr/sdk/browser/rrweb/rrweb.umd.min.cjs +0 -98
  107. lmnr/sdk/client/asynchronous/resources/agent.py +0 -329
  108. lmnr/sdk/client/synchronous/resources/agent.py +0 -323
  109. lmnr/sdk/datasets.py +0 -60
  110. lmnr-0.6.16.dist-info/LICENSE +0 -75
  111. lmnr-0.6.16.dist-info/RECORD +0 -61
  112. lmnr-0.6.16.dist-info/WHEEL +0 -4
  113. lmnr-0.6.16.dist-info/entry_points.txt +0 -3
@@ -1,60 +1,31 @@
1
- from argparse import ArgumentParser
2
- import asyncio
1
+ from argparse import Namespace
2
+
3
3
  import glob
4
4
  import importlib.util
5
5
  import json
6
6
  import os
7
7
  import re
8
8
  import sys
9
- import urllib.request
10
- import urllib.error
11
- from pathlib import Path
12
9
 
13
10
  from lmnr.sdk.evaluations import Evaluation
14
-
15
- from .sdk.eval_control import PREPARE_ONLY, EVALUATION_INSTANCES
16
- from .sdk.log import get_default_logger
11
+ from lmnr.sdk.eval_control import PREPARE_ONLY, EVALUATION_INSTANCES
12
+ from lmnr.sdk.log import get_default_logger
17
13
 
18
14
  LOG = get_default_logger(__name__)
19
-
20
-
21
15
  EVAL_DIR = "evals"
16
+ DEFAULT_DATASET_PULL_BATCH_SIZE = 100
17
+ DEFAULT_DATASET_PUSH_BATCH_SIZE = 100
22
18
 
23
19
 
24
- def add_cursor_rules():
25
- """Download laminar.mdc file from a hardcoded public URL and save it to .cursor/rules/laminar.mdc"""
26
- # Hardcoded URL for the laminar.mdc file
27
- url = "https://raw.githubusercontent.com/lmnr-ai/lmnr/dev/rules/laminar.mdc"
28
-
29
- # Create .cursor/rules directory if it doesn't exist
30
- rules_dir = Path(".cursor/rules")
31
- rules_dir.mkdir(parents=True, exist_ok=True)
32
-
33
- # Define the target file path
34
- target_file = rules_dir / "laminar.mdc"
35
-
36
- try:
37
- LOG.info(f"Downloading laminar.mdc from {url}")
38
-
39
- # Download the file
40
- with urllib.request.urlopen(url) as response:
41
- content = response.read()
42
-
43
- # Write the content to the target file (this will overwrite if it exists)
44
- with open(target_file, "wb") as f:
45
- f.write(content)
46
-
47
- LOG.info(f"Successfully downloaded laminar.mdc to {target_file}")
48
-
49
- except urllib.error.URLError as e:
50
- LOG.error(f"Failed to download file from {url}: {e}")
51
- sys.exit(1)
52
- except Exception as e:
53
- LOG.error(f"Unexpected error: {e}")
54
- sys.exit(1)
20
+ def log_evaluation_instance_not_found() -> None:
21
+ LOG.warning(
22
+ "Evaluation instance not found. "
23
+ "`evaluate` must be called at the top level of the file, "
24
+ "not inside a function when running evaluations from the CLI."
25
+ )
55
26
 
56
27
 
57
- async def run_evaluation(args):
28
+ async def run_evaluation(args: Namespace) -> None:
58
29
  sys.path.append(os.getcwd())
59
30
 
60
31
  if len(args.file) == 0:
@@ -86,6 +57,9 @@ async def run_evaluation(args):
86
57
  scores = []
87
58
  try:
88
59
  for file in files:
60
+ # Reset EVALUATION_INSTANCES before loading each file
61
+ EVALUATION_INSTANCES.set([])
62
+
89
63
  LOG.info(f"Running evaluation from {file}")
90
64
  file = os.path.abspath(file)
91
65
  name = "user_module" + file
@@ -116,11 +90,13 @@ async def run_evaluation(args):
116
90
 
117
91
  for evaluation in evaluations:
118
92
  try:
119
- eval_scores = await evaluation.run()
93
+ eval_result = await evaluation.run()
120
94
  scores.append(
121
95
  {
122
96
  "file": file,
123
- "scores": eval_scores,
97
+ "scores": eval_result["average_scores"],
98
+ "evaluation_id": str(eval_result["evaluation_id"]),
99
+ "url": eval_result["url"],
124
100
  }
125
101
  )
126
102
  except Exception as e:
@@ -133,61 +109,3 @@ async def run_evaluation(args):
133
109
  json.dump(scores, f, indent=2)
134
110
  finally:
135
111
  PREPARE_ONLY.reset(prep_token)
136
-
137
-
138
- def log_evaluation_instance_not_found():
139
- LOG.warning(
140
- "Evaluation instance not found. "
141
- "`evaluate` must be called at the top level of the file, "
142
- "not inside a function when running evaluations from the CLI."
143
- )
144
-
145
-
146
- def cli():
147
- parser = ArgumentParser(
148
- prog="lmnr",
149
- description="CLI for Laminar. Call `lmnr [subcommand] --help` for more information on each subcommand.",
150
- )
151
-
152
- subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
153
-
154
- parser_eval = subparsers.add_parser(
155
- "eval",
156
- description="Run an evaluation",
157
- help="Run an evaluation",
158
- )
159
- parser_eval.add_argument(
160
- "file",
161
- nargs="*",
162
- help="Files or a file containing the evaluation to run."
163
- + "If no file name is provided, all evaluation files in the `evals` directory are run as long"
164
- + "as they match *_eval.py or eval_*.py",
165
- default=[],
166
- )
167
-
168
- parser_eval.add_argument(
169
- "--continue-on-error",
170
- action="store_true",
171
- default=False,
172
- help="Continue execution upon errors",
173
- )
174
-
175
- parser_eval.add_argument(
176
- "--output-file",
177
- help="Output file to write the results to. Outputs are written in JSON format.",
178
- nargs="?",
179
- )
180
-
181
- subparsers.add_parser(
182
- "add-cursor-rules",
183
- description="Download laminar.mdc file and add it to .cursor/rules",
184
- help="Download laminar.mdc file and add it to .cursor/rules",
185
- )
186
-
187
- parsed = parser.parse_args()
188
- if parsed.subcommand == "eval":
189
- asyncio.run(run_evaluation(parsed))
190
- elif parsed.subcommand == "add-cursor-rules":
191
- add_cursor_rules()
192
- else:
193
- parser.print_help()
lmnr/cli/rules.py ADDED
@@ -0,0 +1,42 @@
1
+ from pathlib import Path
2
+ import urllib.request
3
+ import urllib.error
4
+ import sys
5
+
6
+
7
+ from lmnr.sdk.log import get_default_logger
8
+
9
+ LOG = get_default_logger(__name__)
10
+
11
+
12
+ def add_cursor_rules() -> None:
13
+ """Download laminar.mdc file from a hardcoded public URL and save it to .cursor/rules/laminar.mdc"""
14
+ # Hardcoded URL for the laminar.mdc file
15
+ url = "https://raw.githubusercontent.com/lmnr-ai/lmnr/dev/rules/laminar.mdc"
16
+
17
+ # Create .cursor/rules directory if it doesn't exist
18
+ rules_dir = Path(".cursor/rules")
19
+ rules_dir.mkdir(parents=True, exist_ok=True)
20
+
21
+ # Define the target file path
22
+ target_file = rules_dir / "laminar.mdc"
23
+
24
+ try:
25
+ LOG.info(f"Downloading laminar.mdc from {url}")
26
+
27
+ # Download the file
28
+ with urllib.request.urlopen(url) as response:
29
+ content = response.read()
30
+
31
+ # Write the content to the target file (this will overwrite if it exists)
32
+ with open(target_file, "wb") as f:
33
+ f.write(content)
34
+
35
+ LOG.info(f"Successfully downloaded laminar.mdc to {target_file}")
36
+
37
+ except urllib.error.URLError as e:
38
+ LOG.error(f"Failed to download file from {url}: {e}")
39
+ sys.exit(1)
40
+ except Exception as e:
41
+ LOG.error(f"Unexpected error: {e}")
42
+ sys.exit(1)
@@ -6,8 +6,7 @@ from opentelemetry.sdk.resources import SERVICE_NAME
6
6
 
7
7
  from lmnr.opentelemetry_lib.tracing.instruments import Instruments
8
8
  from lmnr.opentelemetry_lib.tracing import TracerWrapper
9
-
10
- MAX_MANUAL_SPAN_PAYLOAD_SIZE = 1024 * 1024 * 10 # 10MB
9
+ from lmnr.sdk.types import SessionRecordingOptions
11
10
 
12
11
 
13
12
  class TracerManager:
@@ -30,6 +29,7 @@ class TracerManager:
30
29
  timeout_seconds: int = 30,
31
30
  set_global_tracer_provider: bool = True,
32
31
  otel_logger_level: int = logging.ERROR,
32
+ session_recording_options: SessionRecordingOptions | None = None,
33
33
  ) -> None:
34
34
  enable_content_tracing = True
35
35
 
@@ -50,6 +50,7 @@ class TracerManager:
50
50
  timeout_seconds=timeout_seconds,
51
51
  set_global_tracer_provider=set_global_tracer_provider,
52
52
  otel_logger_level=otel_logger_level,
53
+ session_recording_options=session_recording_options,
53
54
  )
54
55
 
55
56
  @staticmethod
@@ -61,3 +62,9 @@ class TracerManager:
61
62
  @staticmethod
62
63
  def shutdown():
63
64
  TracerManager.__tracer_wrapper.shutdown()
65
+
66
+ @staticmethod
67
+ def force_reinit_processor():
68
+ if not hasattr(TracerManager, "_TracerManager__tracer_wrapper"):
69
+ return False
70
+ return TracerManager.__tracer_wrapper.force_reinit_processor()