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.
- lmnr/__init__.py +6 -15
- lmnr/cli/__init__.py +270 -0
- lmnr/cli/datasets.py +371 -0
- lmnr/{cli.py → cli/evals.py} +20 -102
- lmnr/cli/rules.py +42 -0
- lmnr/opentelemetry_lib/__init__.py +9 -2
- lmnr/opentelemetry_lib/decorators/__init__.py +274 -168
- lmnr/opentelemetry_lib/litellm/__init__.py +352 -38
- lmnr/opentelemetry_lib/litellm/utils.py +82 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +849 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +13 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +211 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +41 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +401 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +425 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +332 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +1 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/claude_agent/__init__.py +451 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/claude_agent/proxy.py +144 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_agent/__init__.py +100 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/__init__.py +476 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/utils.py +12 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +191 -129
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +26 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +126 -41
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +488 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +8 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +143 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +41 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +229 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +92 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +1 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/__init__.py +381 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/utils.py +36 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +16 -16
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +61 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +472 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +1185 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +305 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +16 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +312 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +100 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +41 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +68 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +197 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +176 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +368 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +325 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +135 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +786 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +1 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openhands_ai/__init__.py +388 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +69 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +59 -61
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +197 -0
- lmnr/opentelemetry_lib/tracing/__init__.py +119 -18
- lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +124 -25
- lmnr/opentelemetry_lib/tracing/attributes.py +4 -0
- lmnr/opentelemetry_lib/tracing/context.py +200 -0
- lmnr/opentelemetry_lib/tracing/exporter.py +109 -15
- lmnr/opentelemetry_lib/tracing/instruments.py +22 -5
- lmnr/opentelemetry_lib/tracing/processor.py +128 -30
- lmnr/opentelemetry_lib/tracing/span.py +398 -0
- lmnr/opentelemetry_lib/tracing/tracer.py +40 -1
- lmnr/opentelemetry_lib/tracing/utils.py +62 -0
- lmnr/opentelemetry_lib/utils/package_check.py +9 -0
- lmnr/opentelemetry_lib/utils/wrappers.py +11 -0
- lmnr/sdk/browser/background_send_events.py +158 -0
- lmnr/sdk/browser/browser_use_cdp_otel.py +100 -0
- lmnr/sdk/browser/browser_use_otel.py +12 -12
- lmnr/sdk/browser/bubus_otel.py +71 -0
- lmnr/sdk/browser/cdp_utils.py +518 -0
- lmnr/sdk/browser/inject_script.js +514 -0
- lmnr/sdk/browser/patchright_otel.py +18 -44
- lmnr/sdk/browser/playwright_otel.py +104 -187
- lmnr/sdk/browser/pw_utils.py +249 -210
- lmnr/sdk/browser/recorder/record.umd.min.cjs +84 -0
- lmnr/sdk/browser/utils.py +1 -1
- lmnr/sdk/client/asynchronous/async_client.py +47 -15
- lmnr/sdk/client/asynchronous/resources/__init__.py +2 -7
- lmnr/sdk/client/asynchronous/resources/browser_events.py +1 -0
- lmnr/sdk/client/asynchronous/resources/datasets.py +131 -0
- lmnr/sdk/client/asynchronous/resources/evals.py +122 -18
- lmnr/sdk/client/asynchronous/resources/evaluators.py +85 -0
- lmnr/sdk/client/asynchronous/resources/tags.py +4 -10
- lmnr/sdk/client/synchronous/resources/__init__.py +2 -2
- lmnr/sdk/client/synchronous/resources/datasets.py +131 -0
- lmnr/sdk/client/synchronous/resources/evals.py +83 -17
- lmnr/sdk/client/synchronous/resources/evaluators.py +85 -0
- lmnr/sdk/client/synchronous/resources/tags.py +4 -10
- lmnr/sdk/client/synchronous/sync_client.py +47 -15
- lmnr/sdk/datasets/__init__.py +94 -0
- lmnr/sdk/datasets/file_utils.py +91 -0
- lmnr/sdk/decorators.py +103 -23
- lmnr/sdk/evaluations.py +122 -33
- lmnr/sdk/laminar.py +816 -333
- lmnr/sdk/log.py +7 -2
- lmnr/sdk/types.py +124 -143
- lmnr/sdk/utils.py +115 -2
- lmnr/version.py +1 -1
- {lmnr-0.6.16.dist-info → lmnr-0.7.26.dist-info}/METADATA +71 -78
- lmnr-0.7.26.dist-info/RECORD +116 -0
- lmnr-0.7.26.dist-info/WHEEL +4 -0
- lmnr-0.7.26.dist-info/entry_points.txt +3 -0
- lmnr/opentelemetry_lib/tracing/context_properties.py +0 -65
- lmnr/sdk/browser/rrweb/rrweb.umd.min.cjs +0 -98
- lmnr/sdk/client/asynchronous/resources/agent.py +0 -329
- lmnr/sdk/client/synchronous/resources/agent.py +0 -323
- lmnr/sdk/datasets.py +0 -60
- lmnr-0.6.16.dist-info/LICENSE +0 -75
- lmnr-0.6.16.dist-info/RECORD +0 -61
- lmnr-0.6.16.dist-info/WHEEL +0 -4
- lmnr-0.6.16.dist-info/entry_points.txt +0 -3
lmnr/{cli.py → cli/evals.py}
RENAMED
|
@@ -1,60 +1,31 @@
|
|
|
1
|
-
from argparse import
|
|
2
|
-
|
|
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.
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
93
|
+
eval_result = await evaluation.run()
|
|
120
94
|
scores.append(
|
|
121
95
|
{
|
|
122
96
|
"file": file,
|
|
123
|
-
"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()
|