lmnr 0.4.53.dev0__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 (133) hide show
  1. lmnr/__init__.py +32 -11
  2. lmnr/cli/__init__.py +270 -0
  3. lmnr/cli/datasets.py +371 -0
  4. lmnr/cli/evals.py +111 -0
  5. lmnr/cli/rules.py +42 -0
  6. lmnr/opentelemetry_lib/__init__.py +70 -0
  7. lmnr/opentelemetry_lib/decorators/__init__.py +337 -0
  8. lmnr/opentelemetry_lib/litellm/__init__.py +685 -0
  9. lmnr/opentelemetry_lib/litellm/utils.py +100 -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 +599 -0
  24. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/config.py +9 -0
  25. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +26 -0
  26. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +330 -0
  27. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +488 -0
  28. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +8 -0
  29. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +143 -0
  30. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +41 -0
  31. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +229 -0
  32. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +92 -0
  33. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +1 -0
  34. lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/__init__.py +381 -0
  35. lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/utils.py +36 -0
  36. lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +121 -0
  37. lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/utils.py +60 -0
  38. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +61 -0
  39. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +472 -0
  40. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +1185 -0
  41. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +305 -0
  42. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +16 -0
  43. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +312 -0
  44. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +100 -0
  45. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +41 -0
  46. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +68 -0
  47. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +197 -0
  48. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +176 -0
  49. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +368 -0
  50. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +325 -0
  51. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +135 -0
  52. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +786 -0
  53. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +1 -0
  54. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openhands_ai/__init__.py +388 -0
  55. lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +69 -0
  56. lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +191 -0
  57. lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +197 -0
  58. lmnr/opentelemetry_lib/tracing/__init__.py +263 -0
  59. lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +516 -0
  60. lmnr/{openllmetry_sdk → opentelemetry_lib}/tracing/attributes.py +21 -8
  61. lmnr/opentelemetry_lib/tracing/context.py +200 -0
  62. lmnr/opentelemetry_lib/tracing/exporter.py +153 -0
  63. lmnr/opentelemetry_lib/tracing/instruments.py +140 -0
  64. lmnr/opentelemetry_lib/tracing/processor.py +193 -0
  65. lmnr/opentelemetry_lib/tracing/span.py +398 -0
  66. lmnr/opentelemetry_lib/tracing/tracer.py +57 -0
  67. lmnr/opentelemetry_lib/tracing/utils.py +62 -0
  68. lmnr/opentelemetry_lib/utils/package_check.py +18 -0
  69. lmnr/opentelemetry_lib/utils/wrappers.py +11 -0
  70. lmnr/sdk/browser/__init__.py +0 -0
  71. lmnr/sdk/browser/background_send_events.py +158 -0
  72. lmnr/sdk/browser/browser_use_cdp_otel.py +100 -0
  73. lmnr/sdk/browser/browser_use_otel.py +142 -0
  74. lmnr/sdk/browser/bubus_otel.py +71 -0
  75. lmnr/sdk/browser/cdp_utils.py +518 -0
  76. lmnr/sdk/browser/inject_script.js +514 -0
  77. lmnr/sdk/browser/patchright_otel.py +151 -0
  78. lmnr/sdk/browser/playwright_otel.py +322 -0
  79. lmnr/sdk/browser/pw_utils.py +363 -0
  80. lmnr/sdk/browser/recorder/record.umd.min.cjs +84 -0
  81. lmnr/sdk/browser/utils.py +70 -0
  82. lmnr/sdk/client/asynchronous/async_client.py +180 -0
  83. lmnr/sdk/client/asynchronous/resources/__init__.py +6 -0
  84. lmnr/sdk/client/asynchronous/resources/base.py +32 -0
  85. lmnr/sdk/client/asynchronous/resources/browser_events.py +41 -0
  86. lmnr/sdk/client/asynchronous/resources/datasets.py +131 -0
  87. lmnr/sdk/client/asynchronous/resources/evals.py +266 -0
  88. lmnr/sdk/client/asynchronous/resources/evaluators.py +85 -0
  89. lmnr/sdk/client/asynchronous/resources/tags.py +83 -0
  90. lmnr/sdk/client/synchronous/resources/__init__.py +6 -0
  91. lmnr/sdk/client/synchronous/resources/base.py +32 -0
  92. lmnr/sdk/client/synchronous/resources/browser_events.py +40 -0
  93. lmnr/sdk/client/synchronous/resources/datasets.py +131 -0
  94. lmnr/sdk/client/synchronous/resources/evals.py +263 -0
  95. lmnr/sdk/client/synchronous/resources/evaluators.py +85 -0
  96. lmnr/sdk/client/synchronous/resources/tags.py +83 -0
  97. lmnr/sdk/client/synchronous/sync_client.py +191 -0
  98. lmnr/sdk/datasets/__init__.py +94 -0
  99. lmnr/sdk/datasets/file_utils.py +91 -0
  100. lmnr/sdk/decorators.py +163 -26
  101. lmnr/sdk/eval_control.py +3 -2
  102. lmnr/sdk/evaluations.py +403 -191
  103. lmnr/sdk/laminar.py +1080 -549
  104. lmnr/sdk/log.py +7 -2
  105. lmnr/sdk/types.py +246 -134
  106. lmnr/sdk/utils.py +151 -7
  107. lmnr/version.py +46 -0
  108. {lmnr-0.4.53.dev0.dist-info → lmnr-0.7.26.dist-info}/METADATA +152 -106
  109. lmnr-0.7.26.dist-info/RECORD +116 -0
  110. lmnr-0.7.26.dist-info/WHEEL +4 -0
  111. lmnr-0.7.26.dist-info/entry_points.txt +3 -0
  112. lmnr/cli.py +0 -101
  113. lmnr/openllmetry_sdk/.python-version +0 -1
  114. lmnr/openllmetry_sdk/__init__.py +0 -72
  115. lmnr/openllmetry_sdk/config/__init__.py +0 -9
  116. lmnr/openllmetry_sdk/decorators/base.py +0 -185
  117. lmnr/openllmetry_sdk/instruments.py +0 -38
  118. lmnr/openllmetry_sdk/tracing/__init__.py +0 -1
  119. lmnr/openllmetry_sdk/tracing/content_allow_list.py +0 -24
  120. lmnr/openllmetry_sdk/tracing/context_manager.py +0 -13
  121. lmnr/openllmetry_sdk/tracing/tracing.py +0 -884
  122. lmnr/openllmetry_sdk/utils/in_memory_span_exporter.py +0 -61
  123. lmnr/openllmetry_sdk/utils/package_check.py +0 -7
  124. lmnr/openllmetry_sdk/version.py +0 -1
  125. lmnr/sdk/datasets.py +0 -55
  126. lmnr-0.4.53.dev0.dist-info/LICENSE +0 -75
  127. lmnr-0.4.53.dev0.dist-info/RECORD +0 -33
  128. lmnr-0.4.53.dev0.dist-info/WHEEL +0 -4
  129. lmnr-0.4.53.dev0.dist-info/entry_points.txt +0 -3
  130. /lmnr/{openllmetry_sdk → opentelemetry_lib}/.flake8 +0 -0
  131. /lmnr/{openllmetry_sdk → opentelemetry_lib}/utils/__init__.py +0 -0
  132. /lmnr/{openllmetry_sdk → opentelemetry_lib}/utils/json_encoder.py +0 -0
  133. /lmnr/{openllmetry_sdk/decorators/__init__.py → py.typed} +0 -0
@@ -0,0 +1,476 @@
1
+ """OpenTelemetry CUA instrumentation"""
2
+
3
+ import logging
4
+ from typing import Collection
5
+
6
+ from lmnr.sdk.utils import get_input_from_func_args, json_dumps
7
+ from lmnr import Laminar
8
+ from lmnr.opentelemetry_lib.tracing.context import get_current_context
9
+ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
10
+ from opentelemetry.instrumentation.utils import unwrap
11
+
12
+ from opentelemetry import trace
13
+ from opentelemetry.trace import Span
14
+ from opentelemetry.trace.status import Status, StatusCode
15
+ from wrapt import wrap_function_wrapper
16
+
17
+ from .utils import payload_to_placeholder
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ _instruments = ("cua-computer >= 0.4.0",)
22
+
23
+
24
+ WRAPPED_METHODS = [
25
+ {
26
+ "package": "computer.interface.generic",
27
+ "object": "GenericComputerInterface",
28
+ "method": "close",
29
+ },
30
+ {
31
+ "package": "computer.interface.generic",
32
+ "object": "GenericComputerInterface",
33
+ "method": "force_close",
34
+ },
35
+ ]
36
+ WRAPPED_AMETHODS = [
37
+ {
38
+ "package": "computer.computer",
39
+ "object": "Computer",
40
+ "method": "__aenter__",
41
+ "action": "start_parent_span",
42
+ },
43
+ {
44
+ "package": "computer.computer",
45
+ "object": "Computer",
46
+ "method": "__aexit__",
47
+ "action": "end_parent_span",
48
+ },
49
+ {
50
+ "package": "computer.interface.generic",
51
+ "object": "GenericComputerInterface",
52
+ "method": "mouse_down",
53
+ },
54
+ {
55
+ "package": "computer.interface.generic",
56
+ "object": "GenericComputerInterface",
57
+ "method": "mouse_up",
58
+ },
59
+ {
60
+ "package": "computer.interface.generic",
61
+ "object": "GenericComputerInterface",
62
+ "method": "left_click",
63
+ },
64
+ {
65
+ "package": "computer.interface.generic",
66
+ "object": "GenericComputerInterface",
67
+ "method": "right_click",
68
+ },
69
+ {
70
+ "package": "computer.interface.generic",
71
+ "object": "GenericComputerInterface",
72
+ "method": "double_click",
73
+ },
74
+ {
75
+ "package": "computer.interface.generic",
76
+ "object": "GenericComputerInterface",
77
+ "method": "move_cursor",
78
+ },
79
+ {
80
+ "package": "computer.interface.generic",
81
+ "object": "GenericComputerInterface",
82
+ "method": "drag_to",
83
+ },
84
+ {
85
+ "package": "computer.interface.generic",
86
+ "object": "GenericComputerInterface",
87
+ "method": "drag",
88
+ },
89
+ {
90
+ "package": "computer.interface.generic",
91
+ "object": "GenericComputerInterface",
92
+ "method": "key_down",
93
+ },
94
+ {
95
+ "package": "computer.interface.generic",
96
+ "object": "GenericComputerInterface",
97
+ "method": "key_up",
98
+ },
99
+ {
100
+ "package": "computer.interface.generic",
101
+ "object": "GenericComputerInterface",
102
+ "method": "type_text",
103
+ },
104
+ {
105
+ "package": "computer.interface.generic",
106
+ "object": "GenericComputerInterface",
107
+ "method": "press",
108
+ },
109
+ {
110
+ "package": "computer.interface.generic",
111
+ "object": "GenericComputerInterface",
112
+ "method": "hotkey",
113
+ },
114
+ {
115
+ "package": "computer.interface.generic",
116
+ "object": "GenericComputerInterface",
117
+ "method": "scroll",
118
+ },
119
+ {
120
+ "package": "computer.interface.generic",
121
+ "object": "GenericComputerInterface",
122
+ "method": "scroll_down",
123
+ },
124
+ {
125
+ "package": "computer.interface.generic",
126
+ "object": "GenericComputerInterface",
127
+ "method": "scroll_up",
128
+ },
129
+ {
130
+ "package": "computer.interface.generic",
131
+ "object": "GenericComputerInterface",
132
+ "method": "screenshot",
133
+ "output_formatter": payload_to_placeholder,
134
+ },
135
+ {
136
+ "package": "computer.interface.generic",
137
+ "object": "GenericComputerInterface",
138
+ "method": "get_screen_size",
139
+ },
140
+ {
141
+ "package": "computer.interface.generic",
142
+ "object": "GenericComputerInterface",
143
+ "method": "get_cursor_position",
144
+ },
145
+ {
146
+ "package": "computer.interface.generic",
147
+ "object": "GenericComputerInterface",
148
+ "method": "copy_to_clipboard",
149
+ },
150
+ {
151
+ "package": "computer.interface.generic",
152
+ "object": "GenericComputerInterface",
153
+ "method": "set_clipboard",
154
+ },
155
+ {
156
+ "package": "computer.interface.generic",
157
+ "object": "GenericComputerInterface",
158
+ "method": "file_exists",
159
+ },
160
+ {
161
+ "package": "computer.interface.generic",
162
+ "object": "GenericComputerInterface",
163
+ "method": "directory_exists",
164
+ },
165
+ {
166
+ "package": "computer.interface.generic",
167
+ "object": "GenericComputerInterface",
168
+ "method": "list_dir",
169
+ },
170
+ {
171
+ "package": "computer.interface.generic",
172
+ "object": "GenericComputerInterface",
173
+ "method": "read_text",
174
+ },
175
+ {
176
+ "package": "computer.interface.generic",
177
+ "object": "GenericComputerInterface",
178
+ "method": "write_text",
179
+ },
180
+ {
181
+ "package": "computer.interface.generic",
182
+ "object": "GenericComputerInterface",
183
+ "method": "read_bytes",
184
+ },
185
+ {
186
+ "package": "computer.interface.generic",
187
+ "object": "GenericComputerInterface",
188
+ "method": "write_bytes",
189
+ },
190
+ {
191
+ "package": "computer.interface.generic",
192
+ "object": "GenericComputerInterface",
193
+ "method": "delete_file",
194
+ },
195
+ {
196
+ "package": "computer.interface.generic",
197
+ "object": "GenericComputerInterface",
198
+ "method": "create_dir",
199
+ },
200
+ {
201
+ "package": "computer.interface.generic",
202
+ "object": "GenericComputerInterface",
203
+ "method": "delete_dir",
204
+ },
205
+ {
206
+ "package": "computer.interface.generic",
207
+ "object": "GenericComputerInterface",
208
+ "method": "get_file_size",
209
+ },
210
+ {
211
+ "package": "computer.interface.generic",
212
+ "object": "GenericComputerInterface",
213
+ "method": "run_command",
214
+ },
215
+ {
216
+ "package": "computer.interface.generic",
217
+ "object": "GenericComputerInterface",
218
+ "method": "get_accessibility_tree",
219
+ },
220
+ {
221
+ "package": "computer.interface.generic",
222
+ "object": "GenericComputerInterface",
223
+ "method": "to_screen_coordinates",
224
+ },
225
+ {
226
+ "package": "computer.interface.generic",
227
+ "object": "GenericComputerInterface",
228
+ "method": "get_active_window_bounds",
229
+ },
230
+ {
231
+ "package": "computer.interface.generic",
232
+ "object": "GenericComputerInterface",
233
+ "method": "to_screenshot_coordinates",
234
+ },
235
+ ]
236
+
237
+
238
+ def _with_wrapper(func):
239
+ """Helper for providing tracer for wrapper functions. Includes metric collectors."""
240
+
241
+ def wrapper(
242
+ to_wrap,
243
+ ):
244
+ def wrapper(wrapped, instance, args, kwargs):
245
+ return func(
246
+ to_wrap,
247
+ wrapped,
248
+ instance,
249
+ args,
250
+ kwargs,
251
+ )
252
+
253
+ return wrapper
254
+
255
+ return wrapper
256
+
257
+
258
+ def add_input_to_parent_span(span, instance):
259
+ # api_key is skipped on purpose
260
+ params = {}
261
+ if hasattr(instance, "display"):
262
+ params["display"] = instance.display
263
+ if hasattr(instance, "memory"):
264
+ params["memory"] = instance.memory
265
+ if hasattr(instance, "cpu"):
266
+ params["cpu"] = instance.cpu
267
+ if hasattr(instance, "os_type"):
268
+ params["os_type"] = instance.os_type
269
+ if hasattr(instance, "name"):
270
+ params["name"] = instance.name
271
+ if hasattr(instance, "image"):
272
+ params["image"] = instance.image
273
+ if hasattr(instance, "shared_directories"):
274
+ params["shared_directories"] = instance.shared_directories
275
+ if hasattr(instance, "use_host_computer_server"):
276
+ params["use_host_computer_server"] = instance.use_host_computer_server
277
+ if hasattr(instance, "verbosity"):
278
+ if (
279
+ isinstance(instance.verbosity, int)
280
+ and instance.verbosity in logging._levelToName
281
+ ):
282
+ params["verbosity"] = logging._levelToName[instance.verbosity]
283
+ else:
284
+ params["verbosity"] = instance.verbosity
285
+ if hasattr(instance, "telemetry_enabled"):
286
+ params["telemetry_enabled"] = instance.telemetry_enabled
287
+ if hasattr(instance, "provider_type"):
288
+ params["provider_type"] = instance.provider_type
289
+ if hasattr(instance, "port"):
290
+ params["port"] = instance.port
291
+ if hasattr(instance, "noVNC_port"):
292
+ params["noVNC_port"] = instance.noVNC_port
293
+ if hasattr(instance, "host"):
294
+ params["host"] = instance.host
295
+ if hasattr(instance, "storage"):
296
+ params["storage"] = instance.storage
297
+ if hasattr(instance, "ephemeral"):
298
+ params["ephemeral"] = instance.ephemeral
299
+ if hasattr(instance, "experiments"):
300
+ params["experiments"] = instance.experiments
301
+ span.set_attribute("lmnr.span.input", json_dumps(params))
302
+
303
+
304
+ @_with_wrapper
305
+ def _wrap(
306
+ to_wrap,
307
+ wrapped,
308
+ instance,
309
+ args,
310
+ kwargs,
311
+ ):
312
+ if to_wrap.get("action") == "start_parent_span":
313
+ parent_span = Laminar.start_span("computer.run")
314
+ add_input_to_parent_span(parent_span, instance)
315
+ result = wrapped(*args, **kwargs)
316
+ try:
317
+ instance._interface._lmnr_parent_span = parent_span
318
+ except Exception:
319
+ pass
320
+ return result
321
+ elif to_wrap.get("action") == "end_parent_span":
322
+ result = wrapped(*args, **kwargs)
323
+ try:
324
+ parent_span: Span = instance._interface._lmnr_parent_span
325
+ if parent_span and parent_span.is_recording():
326
+ parent_span.end()
327
+ except Exception:
328
+ pass
329
+ return result
330
+
331
+ # if there's no parent span, use
332
+ parent_span = trace.get_current_span(context=get_current_context())
333
+ try:
334
+ if instance._lmnr_parent_span:
335
+ parent_span: Span = instance._lmnr_parent_span
336
+ except Exception:
337
+ pass
338
+
339
+ with Laminar.use_span(parent_span):
340
+ instance_name = "interface"
341
+ with Laminar.start_as_current_span(
342
+ f"{instance_name}.{to_wrap.get('method')}", span_type="TOOL"
343
+ ) as span:
344
+ span.set_attribute(
345
+ "lmnr.span.input",
346
+ json_dumps(get_input_from_func_args(wrapped, True, args, kwargs)),
347
+ )
348
+ try:
349
+ result = wrapped(*args, **kwargs)
350
+ except Exception as e: # pylint: disable=broad-except
351
+ span.set_status(Status(StatusCode.ERROR))
352
+ span.record_exception(e)
353
+ span.end()
354
+ raise
355
+ output_formatter = to_wrap.get("output_formatter") or (
356
+ lambda x: json_dumps(x)
357
+ )
358
+ span.set_attribute("lmnr.span.output", output_formatter(result))
359
+ return result
360
+
361
+
362
+ @_with_wrapper
363
+ async def _wrap_async(
364
+ to_wrap,
365
+ wrapped,
366
+ instance,
367
+ args,
368
+ kwargs,
369
+ ):
370
+ if to_wrap.get("action") == "start_parent_span":
371
+ parent_span = Laminar.start_span("computer.run")
372
+ add_input_to_parent_span(parent_span, instance)
373
+ result = await wrapped(*args, **kwargs)
374
+ try:
375
+ instance._interface._lmnr_parent_span = parent_span
376
+ except Exception:
377
+ pass
378
+ return result
379
+ elif to_wrap.get("action") == "end_parent_span":
380
+ result = await wrapped(*args, **kwargs)
381
+ try:
382
+ parent_span: Span = instance._interface._lmnr_parent_span
383
+ if parent_span and parent_span.is_recording():
384
+ parent_span.end()
385
+ except Exception:
386
+ pass
387
+ return result
388
+
389
+ # if there's no parent span, use
390
+ parent_span = trace.get_current_span(context=get_current_context())
391
+ try:
392
+ parent_span: Span = instance._lmnr_parent_span
393
+ except Exception:
394
+ pass
395
+
396
+ with Laminar.use_span(parent_span):
397
+ instance_name = "interface"
398
+ with Laminar.start_as_current_span(
399
+ f"{instance_name}.{to_wrap.get('method')}",
400
+ span_type="TOOL",
401
+ ) as span:
402
+ span.set_attribute(
403
+ "lmnr.span.input",
404
+ json_dumps(get_input_from_func_args(wrapped, True, args, kwargs)),
405
+ )
406
+ try:
407
+ result = await wrapped(*args, **kwargs)
408
+ except Exception as e: # pylint: disable=broad-except
409
+ span.set_status(Status(StatusCode.ERROR))
410
+ span.record_exception(e)
411
+ span.end()
412
+ raise
413
+ output_formatter = to_wrap.get("output_formatter") or (
414
+ lambda x: json_dumps(x)
415
+ )
416
+ span.set_attribute("lmnr.span.output", output_formatter(result))
417
+ return result
418
+
419
+
420
+ class CuaComputerInstrumentor(BaseInstrumentor):
421
+ def __init__(self):
422
+ super().__init__()
423
+
424
+ def instrumentation_dependencies(self) -> Collection[str]:
425
+ return _instruments
426
+
427
+ def _instrument(self, **kwargs):
428
+ for wrapped_method in WRAPPED_METHODS:
429
+ wrap_package = wrapped_method.get("package")
430
+ wrap_object = wrapped_method.get("object")
431
+ wrap_method = wrapped_method.get("method")
432
+
433
+ try:
434
+ wrap_function_wrapper(
435
+ wrap_package,
436
+ f"{wrap_object}.{wrap_method}",
437
+ _wrap(wrapped_method),
438
+ )
439
+ except ModuleNotFoundError:
440
+ pass # that's ok, we don't want to fail if some methods do not exist
441
+
442
+ for wrapped_method in WRAPPED_AMETHODS:
443
+ wrap_package = wrapped_method.get("package")
444
+ wrap_object = wrapped_method.get("object")
445
+ wrap_method = wrapped_method.get("method")
446
+ try:
447
+ wrap_function_wrapper(
448
+ wrap_package,
449
+ f"{wrap_object}.{wrap_method}",
450
+ _wrap_async(wrapped_method),
451
+ )
452
+ except ModuleNotFoundError:
453
+ pass # that's ok, we don't want to fail if some methods do not exist
454
+
455
+ def _uninstrument(self, **kwargs):
456
+ for wrapped_method in WRAPPED_METHODS:
457
+ wrap_package = wrapped_method.get("package")
458
+ wrap_object = wrapped_method.get("object")
459
+ try:
460
+ unwrap(
461
+ f"{wrap_package}.{wrap_object}",
462
+ wrapped_method.get("method"),
463
+ )
464
+ except ModuleNotFoundError:
465
+ pass # that's ok, we don't want to fail if some methods do not exist
466
+
467
+ for wrapped_method in WRAPPED_AMETHODS:
468
+ wrap_package = wrapped_method.get("package")
469
+ wrap_object = wrapped_method.get("object")
470
+ try:
471
+ unwrap(
472
+ f"{wrap_package}.{wrap_object}",
473
+ wrapped_method.get("method"),
474
+ )
475
+ except ModuleNotFoundError:
476
+ pass # that's ok, we don't want to fail if some methods do not exist
@@ -0,0 +1,12 @@
1
+ import base64
2
+ import orjson
3
+
4
+
5
+ def payload_to_base64url(payload_bytes: bytes) -> bytes:
6
+ data = base64.b64encode(payload_bytes).decode("utf-8")
7
+ url = f"data:image/png;base64,{data}"
8
+ return orjson.dumps({"base64url": url})
9
+
10
+
11
+ def payload_to_placeholder(payload_bytes: bytes) -> str:
12
+ return "<BINARY_BLOB_SCREENSHOT>"