lmnr 0.4.7__tar.gz → 0.4.9__tar.gz

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 (62) hide show
  1. {lmnr-0.4.7 → lmnr-0.4.9}/PKG-INFO +20 -18
  2. {lmnr-0.4.7 → lmnr-0.4.9}/README.md +9 -7
  3. {lmnr-0.4.7 → lmnr-0.4.9}/pyproject.toml +12 -12
  4. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/decorators.py +3 -3
  5. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/evaluations.py +4 -4
  6. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/laminar.py +12 -58
  7. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/types.py +9 -9
  8. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/__init__.py +7 -17
  9. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/decorators/base.py +6 -98
  10. lmnr-0.4.9/src/lmnr/traceloop_sdk/metrics/__init__.py +0 -0
  11. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/__init__.py +1 -0
  12. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/conftest.py +111 -0
  13. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_association_properties.py +229 -0
  14. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_manual.py +48 -0
  15. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_nested_tasks.py +47 -0
  16. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_privacy_no_prompts.py +50 -0
  17. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_sdk_initialization.py +57 -0
  18. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_tasks.py +32 -0
  19. lmnr-0.4.9/src/lmnr/traceloop_sdk/tests/test_workflows.py +262 -0
  20. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tracing/__init__.py +0 -1
  21. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tracing/tracing.py +19 -30
  22. lmnr-0.4.7/src/lmnr/traceloop_sdk/README.md +0 -16
  23. lmnr-0.4.7/src/lmnr/traceloop_sdk/decorators/__init__.py +0 -131
  24. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/__init__.py +0 -1
  25. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/conftest.py +0 -111
  26. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_association_properties.py +0 -229
  27. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_manual.py +0 -48
  28. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_nested_tasks.py +0 -47
  29. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_privacy_no_prompts.py +0 -50
  30. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_sdk_initialization.py +0 -57
  31. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_tasks.py +0 -32
  32. lmnr-0.4.7/src/lmnr/traceloop_sdk/tests/test_workflows.py +0 -261
  33. {lmnr-0.4.7 → lmnr-0.4.9}/LICENSE +0 -0
  34. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/__init__.py +0 -0
  35. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/__init__.py +0 -0
  36. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/log.py +0 -0
  37. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/sdk/utils.py +0 -0
  38. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/.flake8 +0 -0
  39. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/.python-version +0 -0
  40. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/config/__init__.py +0 -0
  41. {lmnr-0.4.7/src/lmnr/traceloop_sdk/metrics → lmnr-0.4.9/src/lmnr/traceloop_sdk/decorators}/__init__.py +0 -0
  42. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/instruments.py +0 -0
  43. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/metrics/metrics.py +0 -0
  44. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_and_external_association_properties.yaml +0 -0
  45. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_association_properties.yaml +0 -0
  46. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_manual/test_manual_report.yaml +0 -0
  47. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_manual/test_resource_attributes.yaml +0 -0
  48. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_privacy_no_prompts/test_simple_workflow.yaml +0 -0
  49. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_prompt_management/test_prompt_management.yaml +0 -0
  50. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_sdk_initialization/test_resource_attributes.yaml +0 -0
  51. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_tasks/test_task_io_serialization_with_langchain.yaml +0 -0
  52. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_aworkflow.yaml +0 -0
  53. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_workflow.yaml +0 -0
  54. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_streaming_workflow.yaml +0 -0
  55. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tracing/content_allow_list.py +0 -0
  56. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tracing/context_manager.py +0 -0
  57. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/tracing/manual.py +0 -0
  58. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/utils/__init__.py +0 -0
  59. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/utils/in_memory_span_exporter.py +0 -0
  60. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/utils/json_encoder.py +0 -0
  61. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/utils/package_check.py +0 -0
  62. {lmnr-0.4.7 → lmnr-0.4.9}/src/lmnr/traceloop_sdk/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lmnr
3
- Version: 0.4.7
3
+ Version: 0.4.9
4
4
  Summary: Python SDK for Laminar AI
5
5
  License: Apache-2.0
6
6
  Author: lmnr.ai
@@ -11,11 +11,11 @@ Classifier: Programming Language :: Python :: 3.9
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
- Requires-Dist: asyncio (>=3.4.3,<4.0.0)
15
- Requires-Dist: backoff (>=2.2.1,<3.0.0)
16
- Requires-Dist: colorama (>=0.4.6,<0.5.0)
17
- Requires-Dist: deprecated (>=1.2.14,<2.0.0)
18
- Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
14
+ Requires-Dist: asyncio (>=3.0,<4.0)
15
+ Requires-Dist: backoff (>=2.0,<3.0)
16
+ Requires-Dist: colorama (>=0.4,<0.5)
17
+ Requires-Dist: deprecated (>=1.0,<2.0)
18
+ Requires-Dist: jinja2 (>=3.0,<4.0)
19
19
  Requires-Dist: opentelemetry-api (>=1.27.0,<2.0.0)
20
20
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (>=1.26.0,<2.0.0)
21
21
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.26.0,<2.0.0)
@@ -49,11 +49,11 @@ Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.30.0,<0.31.0)
49
49
  Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.30.0,<0.31.0)
50
50
  Requires-Dist: opentelemetry-sdk (>=1.27.0,<2.0.0)
51
51
  Requires-Dist: opentelemetry-semantic-conventions-ai (==0.4.1)
52
- Requires-Dist: posthog (>3.0.2,<4)
53
- Requires-Dist: pydantic (>=2.7.4,<3.0.0)
54
- Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
55
- Requires-Dist: requests (>=2.32.3,<3.0.0)
56
- Requires-Dist: tenacity (>=8.2.3,<9.0.0)
52
+ Requires-Dist: posthog (>=3.0,<4.0)
53
+ Requires-Dist: pydantic (>=2.7,<3.0)
54
+ Requires-Dist: python-dotenv (>=1.0,<2.0)
55
+ Requires-Dist: requests (>=2.0,<3.0)
56
+ Requires-Dist: tenacity (>=8.0,<9.0)
57
57
  Description-Content-Type: text/markdown
58
58
 
59
59
  # Laminar Python
@@ -79,11 +79,13 @@ And the in your main Python file
79
79
  ```python
80
80
  from lmnr import Laminar as L
81
81
 
82
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
82
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments=set())
83
83
  ```
84
84
 
85
- This will automatically instrument most of the LLM, Vector DB, and related
86
- calls with OpenTelemetry-compatible instrumentation.
85
+ If you want to automatically instrument particular LLM, Vector DB, and related
86
+ calls with OpenTelemetry-compatible instrumentation, then pass the appropriate instruments to `.initialize()`.
87
+
88
+ Also if you want to automatically instrument all supported libraries, then pass `instruments=None` or don't pass `instruments` at all.
87
89
 
88
90
  We rely on the amazing [OpenLLMetry](https://github.com/traceloop/openllmetry), open-source package
89
91
  by TraceLoop, to achieve that.
@@ -106,7 +108,7 @@ from openai import OpenAI
106
108
 
107
109
 
108
110
  from lmnr import observe, Laminar as L
109
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
111
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments=set())
110
112
 
111
113
  client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
112
114
 
@@ -135,7 +137,7 @@ just call `L.start_span`, and OpenTelemetry will handle the context management
135
137
 
136
138
  ```python
137
139
  from lmnr import observe, Laminar as L
138
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
140
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments=set())
139
141
 
140
142
  def poem_writer(topic="turbulence"):
141
143
 
@@ -155,7 +157,7 @@ def poem_writer(topic="turbulence"):
155
157
  # while within the span, you can attach laminar events to it
156
158
  L.event("event_name", "event_value")
157
159
 
158
- L.set_span_output(span, poem) # set an output
160
+ L.set_span_output(poem) # set an output
159
161
 
160
162
  # IMPORTANT: don't forget to end all the spans (usually in `finally` blocks)
161
163
  # Otherwise, the trace may not be sent/displayed correctly
@@ -204,7 +206,7 @@ Example use:
204
206
  ```python
205
207
  from lmnr import Laminar as L
206
208
 
207
- L.initialize('<YOUR_PROJECT_API_KEY>')
209
+ L.initialize('<YOUR_PROJECT_API_KEY>', instruments=set())
208
210
 
209
211
  result = l.run(
210
212
  pipeline = 'my_pipeline_name',
@@ -21,11 +21,13 @@ And the in your main Python file
21
21
  ```python
22
22
  from lmnr import Laminar as L
23
23
 
24
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
24
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments=set())
25
25
  ```
26
26
 
27
- This will automatically instrument most of the LLM, Vector DB, and related
28
- calls with OpenTelemetry-compatible instrumentation.
27
+ If you want to automatically instrument particular LLM, Vector DB, and related
28
+ calls with OpenTelemetry-compatible instrumentation, then pass the appropriate instruments to `.initialize()`.
29
+
30
+ Also if you want to automatically instrument all supported libraries, then pass `instruments=None` or don't pass `instruments` at all.
29
31
 
30
32
  We rely on the amazing [OpenLLMetry](https://github.com/traceloop/openllmetry), open-source package
31
33
  by TraceLoop, to achieve that.
@@ -48,7 +50,7 @@ from openai import OpenAI
48
50
 
49
51
 
50
52
  from lmnr import observe, Laminar as L
51
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
53
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments=set())
52
54
 
53
55
  client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
54
56
 
@@ -77,7 +79,7 @@ just call `L.start_span`, and OpenTelemetry will handle the context management
77
79
 
78
80
  ```python
79
81
  from lmnr import observe, Laminar as L
80
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
82
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments=set())
81
83
 
82
84
  def poem_writer(topic="turbulence"):
83
85
 
@@ -97,7 +99,7 @@ def poem_writer(topic="turbulence"):
97
99
  # while within the span, you can attach laminar events to it
98
100
  L.event("event_name", "event_value")
99
101
 
100
- L.set_span_output(span, poem) # set an output
102
+ L.set_span_output(poem) # set an output
101
103
 
102
104
  # IMPORTANT: don't forget to end all the spans (usually in `finally` blocks)
103
105
  # Otherwise, the trace may not be sent/displayed correctly
@@ -146,7 +148,7 @@ Example use:
146
148
  ```python
147
149
  from lmnr import Laminar as L
148
150
 
149
- L.initialize('<YOUR_PROJECT_API_KEY>')
151
+ L.initialize('<YOUR_PROJECT_API_KEY>', instruments=set())
150
152
 
151
153
  result = l.run(
152
154
  pipeline = 'my_pipeline_name',
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lmnr"
3
- version = "0.4.7"
3
+ version = "0.4.9"
4
4
  description = "Python SDK for Laminar AI"
5
5
  authors = [
6
6
  { name = "lmnr.ai", email = "founders@lmnr.ai" }
@@ -11,7 +11,7 @@ license = "Apache-2.0"
11
11
 
12
12
  [tool.poetry]
13
13
  name = "lmnr"
14
- version = "0.4.7"
14
+ version = "0.4.9"
15
15
  description = "Python SDK for Laminar AI"
16
16
  authors = ["lmnr.ai"]
17
17
  readme = "README.md"
@@ -19,11 +19,11 @@ license = "Apache-2.0"
19
19
 
20
20
  [tool.poetry.dependencies]
21
21
  python = ">=3.9,<4"
22
- pydantic = "^2.7.4"
23
- requests = "^2.32.3"
24
- python-dotenv = "^1.0.1"
25
- backoff = "^2.2.1"
26
- asyncio = "^3.4.3"
22
+ pydantic = "~=2.7"
23
+ requests = "~=2.0"
24
+ python-dotenv = "~=1.0"
25
+ backoff = "~=2.0"
26
+ asyncio = "~=3.0"
27
27
  opentelemetry-api = "^1.27.0"
28
28
  opentelemetry-sdk = "^1.27.0"
29
29
  opentelemetry-exporter-otlp-proto-http = "^1.26.0"
@@ -33,11 +33,11 @@ opentelemetry-instrumentation-sqlalchemy = "^0.48b0"
33
33
  opentelemetry-instrumentation-urllib3 = "^0.48b0"
34
34
  opentelemetry-instrumentation-threading = "^0.48b0"
35
35
  opentelemetry-semantic-conventions-ai = "0.4.1"
36
- colorama = "^0.4.6"
37
- tenacity = "^8.2.3"
38
- jinja2 = "^3.1.2"
39
- deprecated = "^1.2.14"
40
- posthog = ">3.0.2, <4"
36
+ colorama = "^0.4"
37
+ tenacity = "~=8.0"
38
+ jinja2 = "~=3.0"
39
+ deprecated = "~=1.0"
40
+ posthog = "~=3.0"
41
41
  opentelemetry-instrumentation-mistralai = "^0.30.0"
42
42
  opentelemetry-instrumentation-openai = "^0.30.0"
43
43
  opentelemetry-instrumentation-ollama = "^0.30.0"
@@ -3,11 +3,11 @@ from lmnr.traceloop_sdk.decorators.base import (
3
3
  aentity_method,
4
4
  )
5
5
  from opentelemetry.trace import INVALID_SPAN, get_current_span
6
- from lmnr.traceloop_sdk import Traceloop
7
6
 
8
7
  from typing import Callable, Optional, ParamSpec, TypeVar, cast
9
8
 
10
- from .laminar import Laminar as L
9
+ from lmnr.traceloop_sdk.tracing.tracing import update_association_properties
10
+
11
11
  from .utils import is_async
12
12
 
13
13
  P = ParamSpec("P")
@@ -57,7 +57,7 @@ def observe(
57
57
  association_properties["session_id"] = session_id
58
58
  if user_id is not None:
59
59
  association_properties["user_id"] = user_id
60
- Traceloop.set_association_properties(association_properties)
60
+ update_association_properties(association_properties)
61
61
  return (
62
62
  aentity_method(name=name)(func)
63
63
  if is_async(func)
@@ -1,6 +1,6 @@
1
- from typing import Union
1
+ from typing import Any, Union
2
2
 
3
- from .types import EvaluatorFunction, ExecutorFunction, EvaluationDatapoint
3
+ from .types import EvaluationDatapoint
4
4
  from .utils import is_async
5
5
  from .laminar import Laminar as L
6
6
  import asyncio
@@ -32,8 +32,8 @@ class Evaluation:
32
32
  self,
33
33
  name,
34
34
  data: Union[EvaluationDataset, list[Union[EvaluationDatapoint, dict]]],
35
- executor: ExecutorFunction,
36
- evaluators: list[EvaluatorFunction],
35
+ executor: Any,
36
+ evaluators: list[Any],
37
37
  batch_size: int = DEFAULT_BATCH_SIZE,
38
38
  project_api_key: str = "",
39
39
  base_url: str = "https://api.lmnr.ai",
@@ -1,9 +1,8 @@
1
+ from lmnr.traceloop_sdk.instruments import Instruments
1
2
  from opentelemetry import context
2
3
  from opentelemetry.trace import (
3
4
  INVALID_SPAN,
4
5
  get_current_span,
5
- set_span_in_context,
6
- Span,
7
6
  SpanKind,
8
7
  )
9
8
  from opentelemetry.semconv_ai import SpanAttributes
@@ -16,7 +15,7 @@ from contextlib import contextmanager
16
15
  from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
17
16
 
18
17
  from pydantic.alias_generators import to_snake
19
- from typing import Any, Optional, Union
18
+ from typing import Any, Optional, Set, Union
20
19
 
21
20
  import copy
22
21
  import datetime
@@ -27,6 +26,8 @@ import os
27
26
  import requests
28
27
  import uuid
29
28
 
29
+ from lmnr.traceloop_sdk.tracing.tracing import set_association_properties, update_association_properties
30
+
30
31
  from .log import VerboseColorfulFormatter
31
32
 
32
33
  from .types import (
@@ -51,6 +52,7 @@ class Laminar:
51
52
  project_api_key: Optional[str] = None,
52
53
  env: dict[str, str] = {},
53
54
  base_url: Optional[str] = None,
55
+ instruments: Optional[Set[Instruments]] = None,
54
56
  ):
55
57
  """Initialize Laminar context across the application.
56
58
  This method must be called before using any other Laminar methods or
@@ -104,6 +106,7 @@ class Laminar:
104
106
  endpoint=cls.__base_url,
105
107
  headers={"authorization": f"Bearer {cls.__project_api_key}"},
106
108
  ),
109
+ instruments=instruments,
107
110
  )
108
111
 
109
112
  @classmethod
@@ -354,50 +357,15 @@ class Laminar:
354
357
  yield span
355
358
 
356
359
  @classmethod
357
- def start_span(
358
- cls,
359
- name: str,
360
- input: Any = None,
361
- ) -> Span:
362
- """Start a new span with the given name. Useful for manual
363
- instrumentation.
364
-
365
- Args:
366
- name (str): name of the span
367
- input (Any, optional): input to the span. Will be sent as an
368
- attribute, so must be json serializable. Defaults to None.
369
-
370
- Returns:
371
- Tuple[Span, object]: Span - the started span, object -
372
- context token
373
- that must be passed to `end_span` to end the span.
374
-
375
- """
376
- tracer = get_tracer().__enter__()
377
- span = tracer.start_span(name)
378
- # apparently, detaching from this context is not mandatory.
379
- # According to traceloop, and the github issue in opentelemetry,
380
- # the context is collected by the garbage collector.
381
- # https://github.com/open-telemetry/opentelemetry-python/issues/2606#issuecomment-2106320379
382
- context.attach(set_span_in_context(span))
383
-
384
- if input is not None:
385
- span.set_attribute(
386
- SpanAttributes.TRACELOOP_ENTITY_INPUT, json.dumps({"input": input})
387
- )
388
-
389
- return span
390
-
391
- @classmethod
392
- def set_span_output(cls, span: Span, output: Any = None):
393
- """Set the output of the span. Useful for manual instrumentation.
360
+ def set_span_output(cls, output: Any = None):
361
+ """Set the output of the current span. Useful for manual instrumentation.
394
362
 
395
363
  Args:
396
- span (Span): the span to set the output for
397
364
  output (Any, optional): output of the span. Will be sent as an
398
365
  attribute, so must be json serializable. Defaults to None.
399
366
  """
400
- if output is not None:
367
+ span = get_current_span()
368
+ if output is not None and span != INVALID_SPAN:
401
369
  span.set_attribute(
402
370
  SpanAttributes.TRACELOOP_ENTITY_OUTPUT, json.dumps(output)
403
371
  )
@@ -421,26 +389,12 @@ class Laminar:
421
389
  Useful for grouping spans or traces by user.
422
390
  Defaults to None.
423
391
  """
424
- current_span = get_current_span()
425
- if current_span != INVALID_SPAN:
426
- cls.__logger.debug(
427
- "Laminar().set_session() called inside a span context. Setting"
428
- " it manually in the current span."
429
- )
430
- if session_id is not None:
431
- current_span.set_attribute(
432
- "traceloop.association.properties.session_id", session_id
433
- )
434
- if user_id is not None:
435
- current_span.set_attribute(
436
- "traceloop.association.properties.user_id", user_id
437
- )
438
392
  association_properties = {}
439
393
  if session_id is not None:
440
394
  association_properties["session_id"] = session_id
441
395
  if user_id is not None:
442
396
  association_properties["user_id"] = user_id
443
- Traceloop.set_association_properties(association_properties)
397
+ update_association_properties(association_properties)
444
398
 
445
399
  @classmethod
446
400
  def clear_session(cls):
@@ -448,7 +402,7 @@ class Laminar:
448
402
  props: dict = copy.copy(context.get_value("association_properties"))
449
403
  props.pop("session_id", None)
450
404
  props.pop("user_id", None)
451
- Traceloop.set_association_properties(props)
405
+ set_association_properties(props)
452
406
 
453
407
  @classmethod
454
408
  def create_evaluation(cls, name: str) -> CreateEvaluationResponse:
@@ -2,7 +2,7 @@ import datetime
2
2
  import requests
3
3
  import pydantic
4
4
  import uuid
5
- from typing import Any, Awaitable, Callable, Literal, Optional, TypeAlias, Union
5
+ from typing import Any, Literal, Optional, TypeAlias, Union
6
6
 
7
7
  from .utils import to_dict
8
8
 
@@ -90,19 +90,19 @@ class EvaluationDatapoint(pydantic.BaseModel):
90
90
  ExecutorFunctionReturnType: TypeAlias = Any
91
91
  EvaluatorFunctionReturnType: TypeAlias = Union[Numeric, dict[str, Numeric]]
92
92
 
93
- ExecutorFunction: TypeAlias = Callable[
94
- [EvaluationDatapointData, *tuple[Any, ...], dict[str, Any]],
95
- Union[ExecutorFunctionReturnType, Awaitable[ExecutorFunctionReturnType]],
96
- ]
93
+ # ExecutorFunction: TypeAlias = Callable[
94
+ # [EvaluationDatapointData, *tuple[Any, ...], dict[str, Any]],
95
+ # Union[ExecutorFunctionReturnType, Awaitable[ExecutorFunctionReturnType]],
96
+ # ]
97
97
 
98
98
  # EvaluatorFunction is a function that takes the output of the executor and the
99
99
  # target data, and returns a score. The score can be a single number or a
100
100
  # record of string keys and number values. The latter is useful for evaluating
101
101
  # multiple criteria in one go instead of running multiple evaluators.
102
- EvaluatorFunction: TypeAlias = Callable[
103
- [ExecutorFunctionReturnType, *tuple[Any, ...], dict[str, Any]],
104
- Union[EvaluatorFunctionReturnType, Awaitable[EvaluatorFunctionReturnType]],
105
- ]
102
+ # EvaluatorFunction: TypeAlias = Callable[
103
+ # [ExecutorFunctionReturnType, *tuple[Any, ...], dict[str, Any]],
104
+ # Union[EvaluatorFunctionReturnType, Awaitable[EvaluatorFunctionReturnType]],
105
+ # ]
106
106
 
107
107
  EvaluationStatus: TypeAlias = Literal["Started", "Finished", "Error"]
108
108
 
@@ -18,11 +18,7 @@ from lmnr.traceloop_sdk.config import (
18
18
  is_tracing_enabled,
19
19
  is_metrics_enabled,
20
20
  )
21
- from lmnr.traceloop_sdk.tracing.tracing import (
22
- TracerWrapper,
23
- set_association_properties,
24
- set_external_prompt_tracing_context,
25
- )
21
+ from lmnr.traceloop_sdk.tracing.tracing import TracerWrapper
26
22
  from typing import Dict
27
23
 
28
24
 
@@ -38,14 +34,14 @@ class Traceloop:
38
34
  def init(
39
35
  app_name: Optional[str] = sys.argv[0],
40
36
  api_endpoint: str = "https://api.lmnr.ai",
41
- api_key: str = None,
37
+ api_key: Optional[str] = None,
42
38
  headers: Dict[str, str] = {},
43
39
  disable_batch=False,
44
- exporter: SpanExporter = None,
45
- metrics_exporter: MetricExporter = None,
46
- metrics_headers: Dict[str, str] = None,
47
- processor: SpanProcessor = None,
48
- propagator: TextMapPropagator = None,
40
+ exporter: Optional[SpanExporter] = None,
41
+ metrics_exporter: Optional[MetricExporter] = None,
42
+ metrics_headers: Optional[Dict[str, str]] = None,
43
+ processor: Optional[SpanProcessor] = None,
44
+ propagator: Optional[TextMapPropagator] = None,
49
45
  should_enrich_metrics: bool = True,
50
46
  resource_attributes: dict = {},
51
47
  instruments: Optional[Set[Instruments]] = None,
@@ -130,9 +126,3 @@ class Traceloop:
130
126
  )
131
127
 
132
128
  Traceloop.__metrics_wrapper = MetricsWrapper(exporter=metrics_exporter)
133
-
134
- def set_association_properties(properties: dict) -> None:
135
- set_association_properties(properties)
136
-
137
- def set_prompt(template: str, variables: dict, version: int):
138
- set_external_prompt_tracing_context(template, variables, version)
@@ -7,15 +7,10 @@ import warnings
7
7
 
8
8
  from opentelemetry import trace
9
9
  from opentelemetry import context as context_api
10
- from opentelemetry.semconv_ai import SpanAttributes, TraceloopSpanKindValues
11
-
12
- from lmnr.traceloop_sdk.tracing import get_tracer, set_workflow_name
13
- from lmnr.traceloop_sdk.tracing.tracing import (
14
- TracerWrapper,
15
- set_entity_path,
16
- get_chained_entity_path,
17
- )
18
- from lmnr.traceloop_sdk.utils import camel_to_snake
10
+ from opentelemetry.semconv_ai import SpanAttributes
11
+
12
+ from lmnr.traceloop_sdk.tracing import get_tracer
13
+ from lmnr.traceloop_sdk.tracing.tracing import TracerWrapper
19
14
  from lmnr.traceloop_sdk.utils.json_encoder import JSONEncoder
20
15
 
21
16
 
@@ -40,8 +35,6 @@ def _json_dumps(data: dict) -> str:
40
35
 
41
36
  def entity_method(
42
37
  name: Optional[str] = None,
43
- version: Optional[int] = None,
44
- tlp_span_kind: Optional[TraceloopSpanKindValues] = TraceloopSpanKindValues.TASK,
45
38
  ):
46
39
  def decorate(fn):
47
40
  @wraps(fn)
@@ -49,33 +42,13 @@ def entity_method(
49
42
  if not TracerWrapper.verify_initialized():
50
43
  return fn(*args, **kwargs)
51
44
 
52
- entity_name = name or fn.__name__
53
- if tlp_span_kind in [
54
- TraceloopSpanKindValues.WORKFLOW,
55
- TraceloopSpanKindValues.AGENT,
56
- ]:
57
- set_workflow_name(entity_name)
58
- span_name = f"{entity_name}.{tlp_span_kind.value}"
45
+ span_name = name or fn.__name__
59
46
 
60
47
  with get_tracer() as tracer:
61
48
  span = tracer.start_span(span_name)
62
49
  ctx = trace.set_span_in_context(span)
63
50
  ctx_token = context_api.attach(ctx)
64
51
 
65
- if tlp_span_kind in [
66
- TraceloopSpanKindValues.TASK,
67
- TraceloopSpanKindValues.TOOL,
68
- ]:
69
- entity_path = get_chained_entity_path(entity_name)
70
- set_entity_path(entity_path)
71
-
72
- span.set_attribute(
73
- SpanAttributes.TRACELOOP_SPAN_KIND, tlp_span_kind.value
74
- )
75
- span.set_attribute(SpanAttributes.TRACELOOP_ENTITY_NAME, entity_name)
76
- if version:
77
- span.set_attribute(SpanAttributes.TRACELOOP_ENTITY_VERSION, version)
78
-
79
52
  try:
80
53
  if _should_send_prompts():
81
54
  span.set_attribute(
@@ -110,69 +83,25 @@ def entity_method(
110
83
  return decorate
111
84
 
112
85
 
113
- def entity_class(
114
- name: Optional[str],
115
- version: Optional[int],
116
- method_name: str,
117
- tlp_span_kind: Optional[TraceloopSpanKindValues] = TraceloopSpanKindValues.TASK,
118
- ):
119
- def decorator(cls):
120
- task_name = name if name else camel_to_snake(cls.__name__)
121
- method = getattr(cls, method_name)
122
- setattr(
123
- cls,
124
- method_name,
125
- entity_method(name=task_name, version=version, tlp_span_kind=tlp_span_kind)(
126
- method
127
- ),
128
- )
129
- return cls
130
-
131
- return decorator
132
-
133
-
134
86
  # Async Decorators
135
87
 
136
88
 
137
89
  def aentity_method(
138
90
  name: Optional[str] = None,
139
- version: Optional[int] = None,
140
- tlp_span_kind: Optional[TraceloopSpanKindValues] = TraceloopSpanKindValues.TASK,
141
91
  ):
142
92
  def decorate(fn):
143
93
  @wraps(fn)
144
94
  async def wrap(*args, **kwargs):
145
95
  if not TracerWrapper.verify_initialized():
146
- print("Tracer not initialized")
147
96
  return await fn(*args, **kwargs)
148
97
 
149
- entity_name = name or fn.__name__
150
- if tlp_span_kind in [
151
- TraceloopSpanKindValues.WORKFLOW,
152
- TraceloopSpanKindValues.AGENT,
153
- ]:
154
- set_workflow_name(entity_name)
155
- span_name = f"{entity_name}.{tlp_span_kind.value}"
98
+ span_name = name or fn.__name__
156
99
 
157
100
  with get_tracer() as tracer:
158
101
  span = tracer.start_span(span_name)
159
102
  ctx = trace.set_span_in_context(span)
160
103
  ctx_token = context_api.attach(ctx)
161
104
 
162
- if tlp_span_kind in [
163
- TraceloopSpanKindValues.TASK,
164
- TraceloopSpanKindValues.TOOL,
165
- ]:
166
- entity_path = get_chained_entity_path(entity_name)
167
- set_entity_path(entity_path)
168
-
169
- span.set_attribute(
170
- SpanAttributes.TRACELOOP_SPAN_KIND, tlp_span_kind.value
171
- )
172
- span.set_attribute(SpanAttributes.TRACELOOP_ENTITY_NAME, entity_name)
173
- if version:
174
- span.set_attribute(SpanAttributes.TRACELOOP_ENTITY_VERSION, version)
175
-
176
105
  try:
177
106
  if _should_send_prompts():
178
107
  span.set_attribute(
@@ -206,27 +135,6 @@ def aentity_method(
206
135
  return decorate
207
136
 
208
137
 
209
- def aentity_class(
210
- name: Optional[str],
211
- version: Optional[int],
212
- method_name: str,
213
- tlp_span_kind: Optional[TraceloopSpanKindValues] = TraceloopSpanKindValues.TASK,
214
- ):
215
- def decorator(cls):
216
- task_name = name if name else camel_to_snake(cls.__name__)
217
- method = getattr(cls, method_name)
218
- setattr(
219
- cls,
220
- method_name,
221
- aentity_method(
222
- name=task_name, version=version, tlp_span_kind=tlp_span_kind
223
- )(method),
224
- )
225
- return cls
226
-
227
- return decorator
228
-
229
-
230
138
  def _handle_generator(span, res):
231
139
  # for some reason the SPAN_KEY is not being set in the context of the generator, so we re-set it
232
140
  context_api.attach(trace.set_span_in_context(span))
File without changes
@@ -0,0 +1 @@
1
+ # """unit tests."""