lmnr 0.4.29b3__py3-none-any.whl → 0.4.30__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 +1 -0
- lmnr/sdk/laminar.py +135 -21
- lmnr/sdk/types.py +1 -1
- lmnr/traceloop_sdk/tracing/attributes.py +1 -0
- lmnr/traceloop_sdk/tracing/tracing.py +0 -13
- {lmnr-0.4.29b3.dist-info → lmnr-0.4.30.dist-info}/METADATA +1 -1
- {lmnr-0.4.29b3.dist-info → lmnr-0.4.30.dist-info}/RECORD +10 -10
- {lmnr-0.4.29b3.dist-info → lmnr-0.4.30.dist-info}/LICENSE +0 -0
- {lmnr-0.4.29b3.dist-info → lmnr-0.4.30.dist-info}/WHEEL +0 -0
- {lmnr-0.4.29b3.dist-info → lmnr-0.4.30.dist-info}/entry_points.txt +0 -0
lmnr/__init__.py
CHANGED
lmnr/sdk/laminar.py
CHANGED
@@ -1,28 +1,31 @@
|
|
1
|
-
import
|
2
|
-
from
|
3
|
-
from opentelemetry import context
|
4
|
-
from opentelemetry.trace import (
|
5
|
-
INVALID_SPAN,
|
6
|
-
get_current_span,
|
7
|
-
)
|
1
|
+
from contextlib import contextmanager
|
2
|
+
from contextvars import Context
|
3
|
+
from opentelemetry import context, trace
|
8
4
|
from opentelemetry.util.types import AttributeValue
|
9
5
|
from opentelemetry.context import set_value, attach, detach
|
10
6
|
from lmnr.traceloop_sdk import Traceloop
|
7
|
+
from lmnr.traceloop_sdk.instruments import Instruments
|
11
8
|
from lmnr.traceloop_sdk.tracing import get_tracer
|
12
|
-
from lmnr.traceloop_sdk.tracing.attributes import
|
9
|
+
from lmnr.traceloop_sdk.tracing.attributes import (
|
10
|
+
Attributes,
|
11
|
+
SPAN_TYPE,
|
12
|
+
OVERRIDE_PARENT_SPAN,
|
13
|
+
)
|
13
14
|
from lmnr.traceloop_sdk.decorators.base import json_dumps
|
14
|
-
from contextlib import contextmanager
|
15
15
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
16
16
|
|
17
17
|
from pydantic.alias_generators import to_snake
|
18
18
|
from typing import Any, Literal, Optional, Set, Union
|
19
19
|
|
20
|
+
import aiohttp
|
20
21
|
import copy
|
21
22
|
import datetime
|
22
23
|
import dotenv
|
23
24
|
import json
|
24
25
|
import logging
|
25
26
|
import os
|
27
|
+
import random
|
28
|
+
import re
|
26
29
|
import requests
|
27
30
|
import urllib.parse
|
28
31
|
import uuid
|
@@ -196,8 +199,8 @@ class Laminar:
|
|
196
199
|
"API key or set the LMNR_PROJECT_API_KEY environment variable"
|
197
200
|
)
|
198
201
|
try:
|
199
|
-
current_span = get_current_span()
|
200
|
-
if current_span != INVALID_SPAN:
|
202
|
+
current_span = trace.get_current_span()
|
203
|
+
if current_span != trace.INVALID_SPAN:
|
201
204
|
parent_span_id = parent_span_id or uuid.UUID(
|
202
205
|
int=current_span.get_span_context().span_id
|
203
206
|
)
|
@@ -276,8 +279,8 @@ class Laminar:
|
|
276
279
|
if value is not None:
|
277
280
|
event["lmnr.event.value"] = value
|
278
281
|
|
279
|
-
current_span = get_current_span()
|
280
|
-
if current_span == INVALID_SPAN:
|
282
|
+
current_span = trace.get_current_span()
|
283
|
+
if current_span == trace.INVALID_SPAN:
|
281
284
|
cls.__logger.warning(
|
282
285
|
"`Laminar().event()` called outside of span context. "
|
283
286
|
f"Event '{name}' will not be recorded in the trace. "
|
@@ -294,6 +297,8 @@ class Laminar:
|
|
294
297
|
name: str,
|
295
298
|
input: Any = None,
|
296
299
|
span_type: Union[Literal["DEFAULT"], Literal["LLM"]] = "DEFAULT",
|
300
|
+
context: Optional[Context] = None,
|
301
|
+
trace_id: Optional[uuid.UUID] = None,
|
297
302
|
):
|
298
303
|
"""Start a new span as the current span. Useful for manual
|
299
304
|
instrumentation. If `span_type` is set to `"LLM"`, you should report
|
@@ -314,30 +319,139 @@ class Laminar:
|
|
314
319
|
span_type (Union[Literal["DEFAULT"], Literal["LLM"]], optional):\
|
315
320
|
type of the span. If you use `"LLM"`, you should report usage\
|
316
321
|
and response attributes manually. Defaults to "DEFAULT".
|
322
|
+
context (Optional[Context], optional): raw OpenTelemetry context\
|
323
|
+
to attach the span to. Defaults to None.
|
324
|
+
trace_id (Optional[uuid.UUID], optional): [EXPERIMENTAL] override\
|
325
|
+
the trace id for the span. If not provided, use the current\
|
326
|
+
trace id. Defaults to None.
|
317
327
|
"""
|
328
|
+
|
318
329
|
with get_tracer() as tracer:
|
319
330
|
span_path = get_span_path(name)
|
320
|
-
ctx = set_value("span_path", span_path)
|
331
|
+
ctx = set_value("span_path", span_path, context)
|
332
|
+
if trace_id is not None:
|
333
|
+
if isinstance(trace_id, uuid.UUID):
|
334
|
+
span_context = trace.SpanContext(
|
335
|
+
trace_id=int(trace_id),
|
336
|
+
span_id=random.getrandbits(64),
|
337
|
+
is_remote=False,
|
338
|
+
trace_flags=trace.TraceFlags(trace.TraceFlags.SAMPLED),
|
339
|
+
)
|
340
|
+
ctx = trace.set_span_in_context(
|
341
|
+
trace.NonRecordingSpan(span_context), ctx
|
342
|
+
)
|
343
|
+
else:
|
344
|
+
cls.__logger.warning(
|
345
|
+
"trace_id provided to `Laminar.start_as_current_span`"
|
346
|
+
" is not a valid UUID"
|
347
|
+
)
|
321
348
|
ctx_token = attach(ctx)
|
322
349
|
with tracer.start_as_current_span(
|
323
350
|
name,
|
324
351
|
context=ctx,
|
325
|
-
attributes={SPAN_PATH: span_path},
|
352
|
+
attributes={SPAN_PATH: span_path, SPAN_TYPE: span_type},
|
326
353
|
) as span:
|
354
|
+
if trace_id is not None and isinstance(trace_id, uuid.UUID):
|
355
|
+
span.set_attribute(OVERRIDE_PARENT_SPAN, True)
|
327
356
|
if input is not None:
|
328
357
|
span.set_attribute(
|
329
358
|
SPAN_INPUT,
|
330
359
|
json_dumps(input),
|
331
360
|
)
|
332
|
-
span.set_attribute(SPAN_TYPE, span_type)
|
333
361
|
yield span
|
334
362
|
|
335
|
-
# TODO: Figure out if this is necessary
|
363
|
+
# # TODO: Figure out if this is necessary
|
336
364
|
try:
|
337
365
|
detach(ctx_token)
|
338
366
|
except Exception:
|
339
367
|
pass
|
340
368
|
|
369
|
+
@classmethod
|
370
|
+
def start_span(
|
371
|
+
cls,
|
372
|
+
name: str,
|
373
|
+
input: Any = None,
|
374
|
+
span_type: Union[Literal["DEFAULT"], Literal["LLM"]] = "DEFAULT",
|
375
|
+
context: Optional[Context] = None,
|
376
|
+
trace_id: Optional[uuid.UUID] = None,
|
377
|
+
):
|
378
|
+
"""Start a new span. Useful for manual instrumentation.
|
379
|
+
If `span_type` is set to `"LLM"`, you should report usage and response
|
380
|
+
attributes manually. See `Laminar.set_span_attributes` for more
|
381
|
+
information.
|
382
|
+
|
383
|
+
Usage example:
|
384
|
+
```python
|
385
|
+
from src.lmnr import Laminar, use_span
|
386
|
+
def foo(span):
|
387
|
+
with use_span(span):
|
388
|
+
with Laminar.start_as_current_span("foo_inner"):
|
389
|
+
some_function()
|
390
|
+
|
391
|
+
def bar():
|
392
|
+
with use_span(span):
|
393
|
+
openai_client.chat.completions.create()
|
394
|
+
|
395
|
+
span = Laminar.start_span("outer")
|
396
|
+
foo(span)
|
397
|
+
bar(span)
|
398
|
+
# IMPORTANT: End the span manually
|
399
|
+
span.end()
|
400
|
+
|
401
|
+
# Results in:
|
402
|
+
# | outer
|
403
|
+
# | | foo
|
404
|
+
# | | | foo_inner
|
405
|
+
# | | bar
|
406
|
+
# | | | openai.chat
|
407
|
+
```
|
408
|
+
|
409
|
+
Args:
|
410
|
+
name (str): name of the span
|
411
|
+
input (Any, optional): input to the span. Will be sent as an\
|
412
|
+
attribute, so must be json serializable. Defaults to None.
|
413
|
+
span_type (Union[Literal["DEFAULT"], Literal["LLM"]], optional):\
|
414
|
+
type of the span. If you use `"LLM"`, you should report usage\
|
415
|
+
and response attributes manually. Defaults to "DEFAULT".
|
416
|
+
context (Optional[Context], optional): raw OpenTelemetry context\
|
417
|
+
to attach the span to. Defaults to None.
|
418
|
+
trace_id (Optional[uuid.UUID], optional): [EXPERIMENTAL] override\
|
419
|
+
the trace id for the span. If not provided, use the current\
|
420
|
+
trace id. Defaults to None.
|
421
|
+
"""
|
422
|
+
with get_tracer() as tracer:
|
423
|
+
span_path = get_span_path(name)
|
424
|
+
ctx = set_value("span_path", span_path, context)
|
425
|
+
if trace_id is not None:
|
426
|
+
if isinstance(trace_id, uuid.UUID):
|
427
|
+
span_context = trace.SpanContext(
|
428
|
+
trace_id=int(trace_id),
|
429
|
+
span_id=random.getrandbits(64),
|
430
|
+
is_remote=False,
|
431
|
+
trace_flags=trace.TraceFlags(trace.TraceFlags.SAMPLED),
|
432
|
+
)
|
433
|
+
ctx = trace.set_span_in_context(
|
434
|
+
trace.NonRecordingSpan(span_context), ctx
|
435
|
+
)
|
436
|
+
else:
|
437
|
+
cls.__logger.warning(
|
438
|
+
"trace_id provided to `Laminar.start_span`"
|
439
|
+
" is not a valid UUID"
|
440
|
+
)
|
441
|
+
span = tracer.start_span(
|
442
|
+
name,
|
443
|
+
context=ctx,
|
444
|
+
attributes={SPAN_PATH: span_path, SPAN_TYPE: span_type},
|
445
|
+
)
|
446
|
+
if trace_id is not None and isinstance(trace_id, uuid.UUID):
|
447
|
+
span.set_attribute(OVERRIDE_PARENT_SPAN, True)
|
448
|
+
if input is not None:
|
449
|
+
span.set_attribute(
|
450
|
+
SPAN_INPUT,
|
451
|
+
json_dumps(input),
|
452
|
+
)
|
453
|
+
return span
|
454
|
+
|
341
455
|
@classmethod
|
342
456
|
def set_span_output(cls, output: Any = None):
|
343
457
|
"""Set the output of the current span. Useful for manual
|
@@ -347,8 +461,8 @@ class Laminar:
|
|
347
461
|
output (Any, optional): output of the span. Will be sent as an\
|
348
462
|
attribute, so must be json serializable. Defaults to None.
|
349
463
|
"""
|
350
|
-
span = get_current_span()
|
351
|
-
if output is not None and span != INVALID_SPAN:
|
464
|
+
span = trace.get_current_span()
|
465
|
+
if output is not None and span != trace.INVALID_SPAN:
|
352
466
|
span.set_attribute(SPAN_OUTPUT, json_dumps(output))
|
353
467
|
|
354
468
|
@classmethod
|
@@ -378,8 +492,8 @@ class Laminar:
|
|
378
492
|
Args:
|
379
493
|
attributes (dict[ATTRIBUTES, Any]): attributes to set for the span
|
380
494
|
"""
|
381
|
-
span = get_current_span()
|
382
|
-
if span == INVALID_SPAN:
|
495
|
+
span = trace.get_current_span()
|
496
|
+
if span == trace.INVALID_SPAN:
|
383
497
|
return
|
384
498
|
|
385
499
|
for key, value in attributes.items():
|
lmnr/sdk/types.py
CHANGED
@@ -129,7 +129,7 @@ class EvaluationResultDatapoint(pydantic.BaseModel):
|
|
129
129
|
target: EvaluationDatapointTarget
|
130
130
|
executor_output: ExecutorFunctionReturnType
|
131
131
|
scores: dict[str, Numeric]
|
132
|
-
human_evaluators:
|
132
|
+
human_evaluators: list[HumanEvaluator] = pydantic.Field(default_factory=list)
|
133
133
|
trace_id: uuid.UUID
|
134
134
|
executor_span_id: uuid.UUID
|
135
135
|
|
@@ -6,6 +6,7 @@ SPAN_OUTPUT = "lmnr.span.output"
|
|
6
6
|
SPAN_TYPE = "lmnr.span.type"
|
7
7
|
SPAN_PATH = "lmnr.span.path"
|
8
8
|
SPAN_INSTRUMENTATION_SOURCE = "lmnr.span.instrumentation_source"
|
9
|
+
OVERRIDE_PARENT_SPAN = "lmnr.internal.override_parent_span"
|
9
10
|
|
10
11
|
ASSOCIATION_PROPERTIES = "lmnr.association.properties"
|
11
12
|
SESSION_ID = "session_id"
|
@@ -184,8 +184,6 @@ class TracerWrapper(object):
|
|
184
184
|
def set_association_properties(properties: dict) -> None:
|
185
185
|
attach(set_value("association_properties", properties))
|
186
186
|
|
187
|
-
# TODO: When called inside observe decorator, this actually sets the properties on the parent span, not the current one
|
188
|
-
# Then, processor's on_start will assign this to current span
|
189
187
|
span = trace.get_current_span()
|
190
188
|
_set_association_properties_attributes(span, properties)
|
191
189
|
|
@@ -197,8 +195,6 @@ def update_association_properties(properties: dict) -> None:
|
|
197
195
|
|
198
196
|
attach(set_value("association_properties", association_properties))
|
199
197
|
|
200
|
-
# TODO: When called inside observe decorator, this actually sets the properties on the parent span, not the current one
|
201
|
-
# Then, processor's on_start will assign this to current span
|
202
198
|
span = trace.get_current_span()
|
203
199
|
_set_association_properties_attributes(span, properties)
|
204
200
|
|
@@ -229,15 +225,6 @@ def set_managed_prompt_tracing_context(
|
|
229
225
|
attach(set_value("prompt_template_variables", template_variables))
|
230
226
|
|
231
227
|
|
232
|
-
def set_external_prompt_tracing_context(
|
233
|
-
template: str, variables: dict, version: int
|
234
|
-
) -> None:
|
235
|
-
attach(set_value("managed_prompt", False))
|
236
|
-
attach(set_value("prompt_version", version))
|
237
|
-
attach(set_value("prompt_template", template))
|
238
|
-
attach(set_value("prompt_template_variables", variables))
|
239
|
-
|
240
|
-
|
241
228
|
def init_spans_exporter(api_endpoint: str, headers: Dict[str, str]) -> SpanExporter:
|
242
229
|
if "http" in api_endpoint.lower() or "https" in api_endpoint.lower():
|
243
230
|
return HTTPExporter(endpoint=f"{api_endpoint}/v1/traces", headers=headers)
|
@@ -1,12 +1,12 @@
|
|
1
|
-
lmnr/__init__.py,sha256=
|
1
|
+
lmnr/__init__.py,sha256=bIkXw003GaigTxNfGE_gwVtTDGdSdAPUr6CS_nN51oA,430
|
2
2
|
lmnr/cli.py,sha256=Ptvm5dsNLKUY5lwnN8XkT5GtCYjzpRNi2WvefknB3OQ,1079
|
3
3
|
lmnr/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
lmnr/sdk/datasets.py,sha256=w8U9E6fvetAo65Cb2CbYzlfhY8CfXAR-VysrakG6-4I,1591
|
5
5
|
lmnr/sdk/decorators.py,sha256=ZSDaEZyjo-RUzRCltsNbe6x0t9SKl2xRQ2q4uaKvXtk,2250
|
6
6
|
lmnr/sdk/evaluations.py,sha256=5Vfyp0aIjuGpqfuM3cqsaaLpcoO7z6lcOOKxnyHCNHk,16264
|
7
|
-
lmnr/sdk/laminar.py,sha256=
|
7
|
+
lmnr/sdk/laminar.py,sha256=e5N3CuPN8MjdAxKr4YNaGQP9sWiumKMTvCzmw8kY_e0,23477
|
8
8
|
lmnr/sdk/log.py,sha256=cZBeUoSK39LMEV-X4-eEhTWOciULRfHaKfRK8YqIM8I,1532
|
9
|
-
lmnr/sdk/types.py,sha256=
|
9
|
+
lmnr/sdk/types.py,sha256=qGD1tkGszd-_sZJaZ_Zx9U_CdUYzoDkUeN2g-o48Gls,5588
|
10
10
|
lmnr/sdk/utils.py,sha256=Uk8y15x-sd5tP2ERONahElLDJVEy_3dA_1_5g9A6auY,3358
|
11
11
|
lmnr/traceloop_sdk/.flake8,sha256=bCxuDlGx3YQ55QHKPiGJkncHanh9qGjQJUujcFa3lAU,150
|
12
12
|
lmnr/traceloop_sdk/.python-version,sha256=9OLQBQVbD4zE4cJsPePhnAfV_snrPSoqEQw-PXgPMOs,6
|
@@ -36,17 +36,17 @@ lmnr/traceloop_sdk/tests/test_sdk_initialization.py,sha256=fRaf6lrxFzJIN94P1Tav_
|
|
36
36
|
lmnr/traceloop_sdk/tests/test_tasks.py,sha256=xlEx8BKp4yG83SCjK5WkPGfyC33JSrx4h8VyjVwGbgw,906
|
37
37
|
lmnr/traceloop_sdk/tests/test_workflows.py,sha256=RVcfY3WAFIDZC15-aSua21aoQyYeWE7KypDyUsm-2EM,9372
|
38
38
|
lmnr/traceloop_sdk/tracing/__init__.py,sha256=Ckq7zCM26VdJVB5tIZv0GTPyMZKyfso_KWD5yPHaqdo,66
|
39
|
-
lmnr/traceloop_sdk/tracing/attributes.py,sha256=
|
39
|
+
lmnr/traceloop_sdk/tracing/attributes.py,sha256=h970zmb7yTszzf2oHBfOY3cDYhE6O7LhkiHLqa_7x1k,1261
|
40
40
|
lmnr/traceloop_sdk/tracing/content_allow_list.py,sha256=3feztm6PBWNelc8pAZUcQyEGyeSpNiVKjOaDk65l2ps,846
|
41
41
|
lmnr/traceloop_sdk/tracing/context_manager.py,sha256=csVlB6kDmbgSPsROHwnddvGGblx55v6lJMRj0wsSMQM,304
|
42
|
-
lmnr/traceloop_sdk/tracing/tracing.py,sha256=
|
42
|
+
lmnr/traceloop_sdk/tracing/tracing.py,sha256=Wo3ooDmuUiiqIA7ULpDCjxP6Z5UFu7Ai5ViSFLwYV8Q,28741
|
43
43
|
lmnr/traceloop_sdk/utils/__init__.py,sha256=pNhf0G3vTd5ccoc03i1MXDbricSaiqCbi1DLWhSekK8,604
|
44
44
|
lmnr/traceloop_sdk/utils/in_memory_span_exporter.py,sha256=H_4TRaThMO1H6vUQ0OpQvzJk_fZH0OOsRAM1iZQXsR8,2112
|
45
45
|
lmnr/traceloop_sdk/utils/json_encoder.py,sha256=dK6b_axr70IYL7Vv-bu4wntvDDuyntoqsHaddqX7P58,463
|
46
46
|
lmnr/traceloop_sdk/utils/package_check.py,sha256=TZSngzJOpFhfUZLXIs38cpMxQiZSmp0D-sCrIyhz7BA,251
|
47
47
|
lmnr/traceloop_sdk/version.py,sha256=OlatFEFA4ttqSSIiV8jdE-sq3KG5zu2hnC4B4mzWF3s,23
|
48
|
-
lmnr-0.4.
|
49
|
-
lmnr-0.4.
|
50
|
-
lmnr-0.4.
|
51
|
-
lmnr-0.4.
|
52
|
-
lmnr-0.4.
|
48
|
+
lmnr-0.4.30.dist-info/LICENSE,sha256=67b_wJHVV1CBaWkrKFWU1wyqTPSdzH77Ls-59631COg,10411
|
49
|
+
lmnr-0.4.30.dist-info/METADATA,sha256=2IrMNi89yZnA1F4534jSQXD-YSOdHUUsJVeS3C_fRSY,10688
|
50
|
+
lmnr-0.4.30.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
51
|
+
lmnr-0.4.30.dist-info/entry_points.txt,sha256=K1jE20ww4jzHNZLnsfWBvU3YKDGBgbOiYG5Y7ivQcq4,37
|
52
|
+
lmnr-0.4.30.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|