lmnr 0.4.8__tar.gz → 0.4.10__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.8 → lmnr-0.4.10}/PKG-INFO +44 -49
  2. {lmnr-0.4.8 → lmnr-0.4.10}/README.md +33 -38
  3. {lmnr-0.4.8 → lmnr-0.4.10}/pyproject.toml +12 -12
  4. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/__init__.py +1 -0
  5. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/decorators.py +3 -3
  6. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/laminar.py +12 -58
  7. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/types.py +1 -1
  8. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/__init__.py +7 -17
  9. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/decorators/base.py +6 -98
  10. lmnr-0.4.10/src/lmnr/traceloop_sdk/metrics/__init__.py +0 -0
  11. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/__init__.py +1 -0
  12. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/conftest.py +111 -0
  13. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_association_properties.py +229 -0
  14. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_manual.py +48 -0
  15. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_nested_tasks.py +47 -0
  16. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_privacy_no_prompts.py +50 -0
  17. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_sdk_initialization.py +57 -0
  18. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_tasks.py +32 -0
  19. lmnr-0.4.10/src/lmnr/traceloop_sdk/tests/test_workflows.py +262 -0
  20. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tracing/__init__.py +0 -1
  21. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tracing/tracing.py +19 -30
  22. lmnr-0.4.8/src/lmnr/traceloop_sdk/README.md +0 -16
  23. lmnr-0.4.8/src/lmnr/traceloop_sdk/decorators/__init__.py +0 -131
  24. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/__init__.py +0 -1
  25. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/conftest.py +0 -111
  26. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_association_properties.py +0 -229
  27. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_manual.py +0 -48
  28. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_nested_tasks.py +0 -47
  29. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_privacy_no_prompts.py +0 -50
  30. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_sdk_initialization.py +0 -57
  31. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_tasks.py +0 -32
  32. lmnr-0.4.8/src/lmnr/traceloop_sdk/tests/test_workflows.py +0 -261
  33. {lmnr-0.4.8 → lmnr-0.4.10}/LICENSE +0 -0
  34. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/__init__.py +0 -0
  35. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/evaluations.py +0 -0
  36. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/log.py +0 -0
  37. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/sdk/utils.py +0 -0
  38. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/.flake8 +0 -0
  39. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/.python-version +0 -0
  40. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/config/__init__.py +0 -0
  41. {lmnr-0.4.8/src/lmnr/traceloop_sdk/metrics → lmnr-0.4.10/src/lmnr/traceloop_sdk/decorators}/__init__.py +0 -0
  42. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/instruments.py +0 -0
  43. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/metrics/metrics.py +0 -0
  44. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_and_external_association_properties.yaml +0 -0
  45. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_association_properties.yaml +0 -0
  46. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_manual/test_manual_report.yaml +0 -0
  47. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_manual/test_resource_attributes.yaml +0 -0
  48. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_privacy_no_prompts/test_simple_workflow.yaml +0 -0
  49. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_prompt_management/test_prompt_management.yaml +0 -0
  50. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_sdk_initialization/test_resource_attributes.yaml +0 -0
  51. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_tasks/test_task_io_serialization_with_langchain.yaml +0 -0
  52. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_aworkflow.yaml +0 -0
  53. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_workflow.yaml +0 -0
  54. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_streaming_workflow.yaml +0 -0
  55. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tracing/content_allow_list.py +0 -0
  56. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tracing/context_manager.py +0 -0
  57. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/tracing/manual.py +0 -0
  58. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/utils/__init__.py +0 -0
  59. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/utils/in_memory_span_exporter.py +0 -0
  60. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/utils/json_encoder.py +0 -0
  61. {lmnr-0.4.8 → lmnr-0.4.10}/src/lmnr/traceloop_sdk/utils/package_check.py +0 -0
  62. {lmnr-0.4.8 → lmnr-0.4.10}/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.8
3
+ Version: 0.4.10
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
@@ -77,16 +77,19 @@ pip install lmnr
77
77
  And the in your main Python file
78
78
 
79
79
  ```python
80
- from lmnr import Laminar as L
80
+ from lmnr import Laminar as L, Instruments
81
81
 
82
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
82
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI, Instruments.ANTHROPIC})
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
+ You can pass an empty set as `instruments=set()` to disable any kind of automatic instrumentation.
89
+ Also if you want to automatically instrument all supported libraries, then pass `instruments=None` or don't pass `instruments` at all.
87
90
 
88
- We rely on the amazing [OpenLLMetry](https://github.com/traceloop/openllmetry), open-source package
89
- by TraceLoop, to achieve that.
91
+ Our code is based on the [OpenLLMetry](https://github.com/traceloop/openllmetry), open-source package
92
+ by TraceLoop. Also, we are grateful to Traceloop for implementing autoinstrumentations for many libraries.
90
93
 
91
94
  ### Project API key
92
95
 
@@ -105,8 +108,8 @@ import os
105
108
  from openai import OpenAI
106
109
 
107
110
 
108
- from lmnr import observe, Laminar as L
109
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
111
+ from lmnr import observe, Laminar as L, Instruments
112
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
110
113
 
111
114
  client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
112
115
 
@@ -128,40 +131,32 @@ print(poem_writer(topic="laminar flow"))
128
131
 
129
132
  ### Manual instrumentation
130
133
 
131
- Our manual instrumentation is a very thin wrapper around OpenTelemetry's
132
- `trace.start_span`. Our wrapper sets the span into the active context.
133
- You don't have to explicitly pass the spans around, it is enough to
134
- just call `L.start_span`, and OpenTelemetry will handle the context management
134
+ Also, you can `Laminar.start_as_current_span` if you want to record a chunk of your code.
135
135
 
136
136
  ```python
137
- from lmnr import observe, Laminar as L
138
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
137
+ from lmnr import observe, Laminar as L, Instruments
138
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
139
139
 
140
140
  def poem_writer(topic="turbulence"):
141
-
142
- span = L.start_span("poem_writer", topic) # start a span
143
-
144
141
  prompt = f"write a poem about {topic}"
145
-
146
- # OpenAI calls are still automatically instrumented with OpenLLMetry
147
- response = client.chat.completions.create(
148
- model="gpt-4o",
149
- messages=[
150
- {"role": "system", "content": "You are a helpful assistant."},
151
- {"role": "user", "content": prompt},
152
- ],
153
- )
154
- poem = response.choices[0].message.content
155
- # while within the span, you can attach laminar events to it
156
- L.event("event_name", "event_value")
157
-
158
- L.set_span_output(span, poem) # set an output
159
-
160
- # IMPORTANT: don't forget to end all the spans (usually in `finally` blocks)
161
- # Otherwise, the trace may not be sent/displayed correctly
162
- span.end()
163
-
164
- return poem
142
+ messages = [
143
+ {"role": "system", "content": "You are a helpful assistant."},
144
+ {"role": "user", "content": prompt},
145
+ ]
146
+
147
+ with L.start_as_current_span(name="poem_writer", input=messages):
148
+ # OpenAI calls are still automatically instrumented with OpenLLMetry
149
+ response = client.chat.completions.create(
150
+ model="gpt-4o",
151
+ messages=messages,
152
+ )
153
+ poem = response.choices[0].message.content
154
+ # while within the span, you can attach laminar events to it
155
+ L.event("event_name", "event_value")
156
+
157
+ L.set_span_output(poem) # set an output
158
+
159
+ return poem
165
160
  ```
166
161
 
167
162
 
@@ -204,7 +199,7 @@ Example use:
204
199
  ```python
205
200
  from lmnr import Laminar as L
206
201
 
207
- L.initialize('<YOUR_PROJECT_API_KEY>')
202
+ L.initialize('<YOUR_PROJECT_API_KEY>', instruments=set())
208
203
 
209
204
  result = l.run(
210
205
  pipeline = 'my_pipeline_name',
@@ -19,16 +19,19 @@ pip install lmnr
19
19
  And the in your main Python file
20
20
 
21
21
  ```python
22
- from lmnr import Laminar as L
22
+ from lmnr import Laminar as L, Instruments
23
23
 
24
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
24
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI, Instruments.ANTHROPIC})
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
+ You can pass an empty set as `instruments=set()` to disable any kind of automatic instrumentation.
31
+ Also if you want to automatically instrument all supported libraries, then pass `instruments=None` or don't pass `instruments` at all.
29
32
 
30
- We rely on the amazing [OpenLLMetry](https://github.com/traceloop/openllmetry), open-source package
31
- by TraceLoop, to achieve that.
33
+ Our code is based on the [OpenLLMetry](https://github.com/traceloop/openllmetry), open-source package
34
+ by TraceLoop. Also, we are grateful to Traceloop for implementing autoinstrumentations for many libraries.
32
35
 
33
36
  ### Project API key
34
37
 
@@ -47,8 +50,8 @@ import os
47
50
  from openai import OpenAI
48
51
 
49
52
 
50
- from lmnr import observe, Laminar as L
51
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
53
+ from lmnr import observe, Laminar as L, Instruments
54
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
52
55
 
53
56
  client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
54
57
 
@@ -70,40 +73,32 @@ print(poem_writer(topic="laminar flow"))
70
73
 
71
74
  ### Manual instrumentation
72
75
 
73
- Our manual instrumentation is a very thin wrapper around OpenTelemetry's
74
- `trace.start_span`. Our wrapper sets the span into the active context.
75
- You don't have to explicitly pass the spans around, it is enough to
76
- just call `L.start_span`, and OpenTelemetry will handle the context management
76
+ Also, you can `Laminar.start_as_current_span` if you want to record a chunk of your code.
77
77
 
78
78
  ```python
79
- from lmnr import observe, Laminar as L
80
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>")
79
+ from lmnr import observe, Laminar as L, Instruments
80
+ L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
81
81
 
82
82
  def poem_writer(topic="turbulence"):
83
-
84
- span = L.start_span("poem_writer", topic) # start a span
85
-
86
83
  prompt = f"write a poem about {topic}"
87
-
88
- # OpenAI calls are still automatically instrumented with OpenLLMetry
89
- response = client.chat.completions.create(
90
- model="gpt-4o",
91
- messages=[
92
- {"role": "system", "content": "You are a helpful assistant."},
93
- {"role": "user", "content": prompt},
94
- ],
95
- )
96
- poem = response.choices[0].message.content
97
- # while within the span, you can attach laminar events to it
98
- L.event("event_name", "event_value")
99
-
100
- L.set_span_output(span, poem) # set an output
101
-
102
- # IMPORTANT: don't forget to end all the spans (usually in `finally` blocks)
103
- # Otherwise, the trace may not be sent/displayed correctly
104
- span.end()
105
-
106
- return poem
84
+ messages = [
85
+ {"role": "system", "content": "You are a helpful assistant."},
86
+ {"role": "user", "content": prompt},
87
+ ]
88
+
89
+ with L.start_as_current_span(name="poem_writer", input=messages):
90
+ # OpenAI calls are still automatically instrumented with OpenLLMetry
91
+ response = client.chat.completions.create(
92
+ model="gpt-4o",
93
+ messages=messages,
94
+ )
95
+ poem = response.choices[0].message.content
96
+ # while within the span, you can attach laminar events to it
97
+ L.event("event_name", "event_value")
98
+
99
+ L.set_span_output(poem) # set an output
100
+
101
+ return poem
107
102
  ```
108
103
 
109
104
 
@@ -146,7 +141,7 @@ Example use:
146
141
  ```python
147
142
  from lmnr import Laminar as L
148
143
 
149
- L.initialize('<YOUR_PROJECT_API_KEY>')
144
+ L.initialize('<YOUR_PROJECT_API_KEY>', instruments=set())
150
145
 
151
146
  result = l.run(
152
147
  pipeline = 'my_pipeline_name',
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lmnr"
3
- version = "0.4.8"
3
+ version = "0.4.10"
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.8"
14
+ version = "0.4.10"
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"
@@ -2,3 +2,4 @@ from .sdk.evaluations import Evaluation
2
2
  from .sdk.laminar import Laminar
3
3
  from .sdk.types import ChatMessage, PipelineRunError, PipelineRunResponse, NodeInput
4
4
  from .sdk.decorators import observe
5
+ from .traceloop_sdk import Instruments
@@ -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,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
 
@@ -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)