lmnr 0.7.3__py3-none-any.whl → 0.7.4__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.
@@ -56,8 +56,8 @@ from opentelemetry.trace import SpanKind, Tracer
56
56
  from opentelemetry.trace.status import Status, StatusCode
57
57
  from wrapt import ObjectProxy
58
58
 
59
- from openai.types.chat import ChatCompletionMessageToolCall
60
59
  from openai.types.chat.chat_completion_message import FunctionCall
60
+ import pydantic
61
61
 
62
62
  SPAN_NAME = "openai.chat"
63
63
  PROMPT_FILTER_KEY = "prompt_filter_results"
@@ -995,7 +995,7 @@ async def _abuild_from_streaming_response(
995
995
 
996
996
 
997
997
  def _parse_tool_calls(
998
- tool_calls: Optional[List[Union[dict, ChatCompletionMessageToolCall]]],
998
+ tool_calls: Optional[List[Union[dict, pydantic.BaseModel]]],
999
999
  ) -> Union[List[ToolCall], None]:
1000
1000
  """
1001
1001
  Util to correctly parse the tool calls data from the OpenAI API to this module's
@@ -74,7 +74,7 @@ class TracerWrapper(object):
74
74
  if not hasattr(cls, "instance"):
75
75
  cls._initialize_logger(cls)
76
76
  obj = super(TracerWrapper, cls).__new__(cls)
77
-
77
+
78
78
  # Store session recording options
79
79
  cls.session_recording_options = session_recording_options or {}
80
80
 
@@ -249,13 +249,13 @@ class TracerWrapper(object):
249
249
  self._logger.warning("TracerWrapper not fully initialized, cannot flush")
250
250
  return False
251
251
  return self._span_processor.force_flush()
252
-
252
+
253
253
  @classmethod
254
254
  def get_session_recording_options(cls) -> SessionRecordingOptions:
255
255
  """Get the session recording options set during initialization."""
256
256
  return cls.session_recording_options
257
257
 
258
- def get_tracer(self):
258
+ def get_tracer(self) -> trace.Tracer:
259
259
  if self._tracer_provider is None:
260
260
  return trace.get_tracer_provider().get_tracer(TRACER_NAME)
261
261
  return self._tracer_provider.get_tracer(TRACER_NAME)
@@ -14,6 +14,8 @@ SPAN_OUTPUT = "lmnr.span.output"
14
14
  SPAN_TYPE = "lmnr.span.type"
15
15
  SPAN_PATH = "lmnr.span.path"
16
16
  SPAN_IDS_PATH = "lmnr.span.ids_path"
17
+ PARENT_SPAN_PATH = "lmnr.span.parent_path"
18
+ PARENT_SPAN_IDS_PATH = "lmnr.span.parent_ids_path"
17
19
  SPAN_INSTRUMENTATION_SOURCE = "lmnr.span.instrumentation_source"
18
20
  SPAN_SDK_VERSION = "lmnr.span.sdk_version"
19
21
  SPAN_LANGUAGE_VERSION = "lmnr.span.language_version"
@@ -7,9 +7,11 @@ from opentelemetry.sdk.trace.export import (
7
7
  SimpleSpanProcessor,
8
8
  )
9
9
  from opentelemetry.sdk.trace import Span
10
- from opentelemetry.context import Context, get_value, get_current, set_value
10
+ from opentelemetry.context import Context, get_value
11
11
 
12
12
  from lmnr.opentelemetry_lib.tracing.attributes import (
13
+ PARENT_SPAN_IDS_PATH,
14
+ PARENT_SPAN_PATH,
13
15
  SPAN_IDS_PATH,
14
16
  SPAN_INSTRUMENTATION_SOURCE,
15
17
  SPAN_LANGUAGE_VERSION,
@@ -52,20 +54,18 @@ class LaminarSpanProcessor(SpanProcessor):
52
54
  )
53
55
 
54
56
  def on_start(self, span: Span, parent_context: Context | None = None):
55
- span_path_in_context = get_value("span_path", parent_context or get_current())
56
- parent_span_path = span_path_in_context or (
57
+ parent_span_path = list(span.attributes.get(PARENT_SPAN_PATH, tuple())) or (
57
58
  self.__span_id_to_path.get(span.parent.span_id) if span.parent else None
58
59
  )
59
- parent_span_ids_path = (
60
- self.__span_id_lists.get(span.parent.span_id, []) if span.parent else []
61
- )
60
+ parent_span_ids_path = list(
61
+ span.attributes.get(PARENT_SPAN_IDS_PATH, tuple())
62
+ ) or (self.__span_id_lists.get(span.parent.span_id, []) if span.parent else [])
62
63
  span_path = parent_span_path + [span.name] if parent_span_path else [span.name]
63
64
  span_ids_path = parent_span_ids_path + [
64
65
  str(uuid.UUID(int=span.get_span_context().span_id))
65
66
  ]
66
67
  span.set_attribute(SPAN_PATH, span_path)
67
68
  span.set_attribute(SPAN_IDS_PATH, span_ids_path)
68
- set_value("span_path", span_path, get_current())
69
69
  self.__span_id_to_path[span.get_span_context().span_id] = span_path
70
70
  self.__span_id_lists[span.get_span_context().span_id] = span_ids_path
71
71
 
lmnr/sdk/laminar.py CHANGED
@@ -13,6 +13,10 @@ from lmnr.opentelemetry_lib.tracing.instruments import Instruments
13
13
  from lmnr.opentelemetry_lib.tracing.tracer import get_tracer_with_context
14
14
  from lmnr.opentelemetry_lib.tracing.attributes import (
15
15
  ASSOCIATION_PROPERTIES,
16
+ PARENT_SPAN_IDS_PATH,
17
+ PARENT_SPAN_PATH,
18
+ SPAN_IDS_PATH,
19
+ SPAN_PATH,
16
20
  USER_ID,
17
21
  Attributes,
18
22
  SPAN_TYPE,
@@ -316,9 +320,29 @@ class Laminar:
316
320
 
317
321
  with get_tracer_with_context() as (tracer, isolated_context):
318
322
  ctx = context or isolated_context
323
+ path = []
324
+ span_ids_path = []
319
325
  if parent_span_context is not None:
326
+ if isinstance(parent_span_context, (dict, str)):
327
+ try:
328
+ laminar_span_context = LaminarSpanContext.deserialize(
329
+ parent_span_context
330
+ )
331
+ path = laminar_span_context.span_path
332
+ span_ids_path = laminar_span_context.span_ids_path
333
+ except Exception:
334
+ cls.__logger.warning(
335
+ f"`start_as_current_span` Could not deserialize parent_span_context: {parent_span_context}. "
336
+ "Will use it as is."
337
+ )
338
+ laminar_span_context = parent_span_context
339
+ else:
340
+ laminar_span_context = parent_span_context
341
+ if isinstance(laminar_span_context, LaminarSpanContext):
342
+ path = laminar_span_context.span_path
343
+ span_ids_path = laminar_span_context.span_ids_path
320
344
  span_context = LaminarSpanContext.try_to_otel_span_context(
321
- parent_span_context, cls.__logger
345
+ laminar_span_context, cls.__logger
322
346
  )
323
347
  ctx = trace.set_span_in_context(
324
348
  trace.NonRecordingSpan(span_context), ctx
@@ -352,6 +376,8 @@ class Laminar:
352
376
  context=ctx,
353
377
  attributes={
354
378
  SPAN_TYPE: span_type,
379
+ PARENT_SPAN_PATH: path,
380
+ PARENT_SPAN_IDS_PATH: span_ids_path,
355
381
  **(label_props),
356
382
  **(tag_props),
357
383
  },
@@ -454,9 +480,29 @@ class Laminar:
454
480
 
455
481
  with get_tracer_with_context() as (tracer, isolated_context):
456
482
  ctx = context or isolated_context
483
+ path = []
484
+ span_ids_path = []
457
485
  if parent_span_context is not None:
486
+ if isinstance(parent_span_context, (dict, str)):
487
+ try:
488
+ laminar_span_context = LaminarSpanContext.deserialize(
489
+ parent_span_context
490
+ )
491
+ path = laminar_span_context.span_path
492
+ span_ids_path = laminar_span_context.span_ids_path
493
+ except Exception:
494
+ cls.__logger.warning(
495
+ f"`start_span` Could not deserialize parent_span_context: {parent_span_context}. "
496
+ "Will use it as is."
497
+ )
498
+ laminar_span_context = parent_span_context
499
+ else:
500
+ laminar_span_context = parent_span_context
501
+ if isinstance(laminar_span_context, LaminarSpanContext):
502
+ path = laminar_span_context.span_path
503
+ span_ids_path = laminar_span_context.span_ids_path
458
504
  span_context = LaminarSpanContext.try_to_otel_span_context(
459
- parent_span_context, cls.__logger
505
+ laminar_span_context, cls.__logger
460
506
  )
461
507
  ctx = trace.set_span_in_context(
462
508
  trace.NonRecordingSpan(span_context), ctx
@@ -491,6 +537,8 @@ class Laminar:
491
537
  context=ctx,
492
538
  attributes={
493
539
  SPAN_TYPE: span_type,
540
+ PARENT_SPAN_PATH: path,
541
+ PARENT_SPAN_IDS_PATH: span_ids_path,
494
542
  **(label_props),
495
543
  **(tag_props),
496
544
  },
@@ -662,6 +710,8 @@ class Laminar:
662
710
  trace_id=uuid.UUID(int=span.get_span_context().trace_id),
663
711
  span_id=uuid.UUID(int=span.get_span_context().span_id),
664
712
  is_remote=span.get_span_context().is_remote,
713
+ span_path=span.attributes.get(SPAN_PATH, []),
714
+ span_ids_path=span.attributes.get(SPAN_IDS_PATH, []),
665
715
  )
666
716
 
667
717
  @classmethod
lmnr/sdk/types.py CHANGED
@@ -169,6 +169,8 @@ class LaminarSpanContext(pydantic.BaseModel):
169
169
  trace_id: uuid.UUID
170
170
  span_id: uuid.UUID
171
171
  is_remote: bool = pydantic.Field(default=False)
172
+ span_path: list[str] = pydantic.Field(default=[])
173
+ span_ids_path: list[str] = pydantic.Field(default=[]) # stringified UUIDs
172
174
 
173
175
  def __str__(self) -> str:
174
176
  return self.model_dump_json()
@@ -199,7 +201,7 @@ class LaminarSpanContext(pydantic.BaseModel):
199
201
  "Please use `LaminarSpanContext` instead."
200
202
  )
201
203
  return span_context
202
- elif isinstance(span_context, dict) or isinstance(span_context, str):
204
+ elif isinstance(span_context, (dict, str)):
203
205
  try:
204
206
  laminar_span_context = cls.deserialize(span_context)
205
207
  return SpanContext(
@@ -221,6 +223,9 @@ class LaminarSpanContext(pydantic.BaseModel):
221
223
  "trace_id": data.get("trace_id") or data.get("traceId"),
222
224
  "span_id": data.get("span_id") or data.get("spanId"),
223
225
  "is_remote": data.get("is_remote") or data.get("isRemote", False),
226
+ "span_path": data.get("span_path") or data.get("spanPath", []),
227
+ "span_ids_path": data.get("span_ids_path")
228
+ or data.get("spanIdsPath", []),
224
229
  }
225
230
  return cls.model_validate(converted_data)
226
231
  elif isinstance(data, str):
@@ -356,5 +361,6 @@ class MaskInputOptions(TypedDict):
356
361
  email: bool | None
357
362
  tel: bool | None
358
363
 
364
+
359
365
  class SessionRecordingOptions(TypedDict):
360
- mask_input_options: MaskInputOptions | None
366
+ mask_input_options: MaskInputOptions | None
lmnr/version.py CHANGED
@@ -3,7 +3,7 @@ import httpx
3
3
  from packaging import version
4
4
 
5
5
 
6
- __version__ = "0.7.3"
6
+ __version__ = "0.7.4"
7
7
  PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}"
8
8
 
9
9
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lmnr
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: Python SDK for Laminar
5
5
  Author: lmnr.ai
6
6
  Author-email: lmnr.ai <founders@lmnr.ai>
@@ -28,7 +28,7 @@ lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py,sha25
28
28
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/utils.py,sha256=9dff6c2595e79edb38818668aed1220efc188d8a982594c04f4ceeb6e3ff47a6,1512
29
29
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py,sha256=8b91dc16af927eee75b969c0980c606680b347a87f8533bc0f4a092e5ec6e5c9,2071
30
30
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py,sha256=9d182c8cef5ee1e205dc4c2f7c8e49d8403ee9fee66072c5cfdd29a0d54f61a2,15149
31
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=92aed53560c49e0ec3ef5e20ddb6c2096bb26078cc3e10b2f80a9dcef7a3e520,38937
31
+ lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=4a1e682cd455661dde3b9442c7c16d055958e77ba5fff24c6fe08ab967c30da2,38882
32
32
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py,sha256=3a45c07d9d0f37baf409a48e2a1b577f28041c623c41f59ada1c87b94285ae3b,9537
33
33
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py,sha256=8016e4af0291a77484ce88d7d1ca06146b1229ae0e0a0f46e042faf75b456a8f,507
34
34
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py,sha256=324eeeaf8dd862f49c15bb7290d414e77ad51cdf532c2cfd74358783cdf654a5,9330
@@ -45,13 +45,13 @@ lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py,sha256=4f
45
45
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py,sha256=1f86cdf738e2f68586b0a4569bb1e40edddd85c529f511ef49945ddb7b61fab5,2648
46
46
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py,sha256=764e4fe979fb08d7821419a3cc5c3ae89a6664b626ef928259f8f175c939eaea,6334
47
47
  lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py,sha256=90aa8558467d7e469fe1a6c75372c113da403557715f03b522b2fab94b287c40,6320
48
- lmnr/opentelemetry_lib/tracing/__init__.py,sha256=1019d25eab017547e914aa9703d4c4bc3fabb7ae0327f0dcb266c3d09f9a08e8,10207
48
+ lmnr/opentelemetry_lib/tracing/__init__.py,sha256=b96aee7590af1853fffc4c3d8ce9127a67e1ce589f695a99aabe6b37d70b0e48,10203
49
49
  lmnr/opentelemetry_lib/tracing/_instrument_initializers.py,sha256=a15a46a0515462319195a96f7cdb695e72a1559c3212964f5883ab824031bf70,15125
50
- lmnr/opentelemetry_lib/tracing/attributes.py,sha256=32fa30565b977c2a92202dc2bf1ded583a81d02a6bf5ba52958f75a8be08cbbe,1497
50
+ lmnr/opentelemetry_lib/tracing/attributes.py,sha256=88afbd1ad56bd423167f27010d86169e061ebca1f00549961da763eca51055db,1591
51
51
  lmnr/opentelemetry_lib/tracing/context.py,sha256=83f842be0fc29a96647cbf005c39ea761b0fb5913c4102f965411f47906a6135,4103
52
52
  lmnr/opentelemetry_lib/tracing/exporter.py,sha256=6af8e61fd873e8f5db315d9b9f1edbf46b860ba7e50140f0bdcc6864c6d35a03,2082
53
53
  lmnr/opentelemetry_lib/tracing/instruments.py,sha256=e3c12315bda301416d1f3bc8d354ad16d4da211e2ecfa019265f4b565307c118,5655
54
- lmnr/opentelemetry_lib/tracing/processor.py,sha256=fd11e4d48eb5932f47898b8f70b8b5880f7ee7e58478f1ef20caff20e1f34252,3381
54
+ lmnr/opentelemetry_lib/tracing/processor.py,sha256=cbc70f138e70c878ef57b02a2c46ef48dd7f694a522623a82dff1623b73d1e1c,3353
55
55
  lmnr/opentelemetry_lib/tracing/tracer.py,sha256=33769a9a97385f5697eb0e0a6b1813a57ed956c7a8379d7ac2523e700e7dd528,1362
56
56
  lmnr/opentelemetry_lib/utils/__init__.py,sha256=a4d85fd06def4dde5c728734de2d4c5c36eb89c49a8aa09b8b50cb5a149e90af,604
57
57
  lmnr/opentelemetry_lib/utils/json_encoder.py,sha256=74ae9bfdac6bef42182fb56ff9bbb8c27b6f0c3bb29eda2ab0769d76a5fb3f9f,463
@@ -85,12 +85,12 @@ lmnr/sdk/datasets.py,sha256=3fd851c5f97bf88eaa84b1451a053eaff23b4497cbb45eac2f9e
85
85
  lmnr/sdk/decorators.py,sha256=2ccf9ecd9616ad1d52301febd8af630288ba63db2d36302236f606a460fc08ca,6516
86
86
  lmnr/sdk/eval_control.py,sha256=291394ac385c653ae9b5167e871bebeb4fe8fc6b7ff2ed38e636f87015dcba86,184
87
87
  lmnr/sdk/evaluations.py,sha256=b41f7737b084dc5b64b2952659b729622e0918fd492bfcddde7177d1a1c690ae,22572
88
- lmnr/sdk/laminar.py,sha256=f9dbacc6549d19701db7a986cb29c82114b1a054900a282b1ae9dbe6a488129b,34974
88
+ lmnr/sdk/laminar.py,sha256=24d680407ce694f1a7ec0e9c0524eae3deb7d638ad5caff3a591ddf7963ad480,37533
89
89
  lmnr/sdk/log.py,sha256=9edfd83263f0d4845b1b2d1beeae2b4ed3f8628de941f371a893d72b79c348d4,2213
90
- lmnr/sdk/types.py,sha256=ded526d1289442672236265bd6cbb4381fc55d8ce0fce1d6e7b2541e54c758c4,12948
90
+ lmnr/sdk/types.py,sha256=49358ddd00a1f1e75ffc8cbba62aaf49f4d3031eebf52de86005715a54a846b7,13244
91
91
  lmnr/sdk/utils.py,sha256=4beb884ae6fbbc7d8cf639b036b726ea6a2a658f0a6386faf5735a13d706a2d8,5039
92
- lmnr/version.py,sha256=65bb6a01739adaee6189918df22c9e8df76cfc10339b704416f686014f066b2b,1321
93
- lmnr-0.7.3.dist-info/WHEEL,sha256=ab6157bc637547491fb4567cd7ddf26b04d63382916ca16c29a5c8e94c9c9ef7,79
94
- lmnr-0.7.3.dist-info/entry_points.txt,sha256=abdf3411b7dd2d7329a241f2da6669bab4e314a747a586ecdb9f888f3035003c,39
95
- lmnr-0.7.3.dist-info/METADATA,sha256=2952132a1ddd7d9e0f8c50fdd39e159174825b812b898bf48135c1c69ee7d5db,14196
96
- lmnr-0.7.3.dist-info/RECORD,,
92
+ lmnr/version.py,sha256=d1c12ee42adc0a3de888632fcfe36693a8dd749bbed2ad12dd1ab2783608bcd2,1321
93
+ lmnr-0.7.4.dist-info/WHEEL,sha256=ab6157bc637547491fb4567cd7ddf26b04d63382916ca16c29a5c8e94c9c9ef7,79
94
+ lmnr-0.7.4.dist-info/entry_points.txt,sha256=abdf3411b7dd2d7329a241f2da6669bab4e314a747a586ecdb9f888f3035003c,39
95
+ lmnr-0.7.4.dist-info/METADATA,sha256=91677f6dc8a33790ec9e9e3bc6e1e90561d335359f3a73590c563aed8fb90163,14196
96
+ lmnr-0.7.4.dist-info/RECORD,,
File without changes