lmnr 0.4.10__tar.gz → 0.4.12b1__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 (53) hide show
  1. {lmnr-0.4.10 → lmnr-0.4.12b1}/PKG-INFO +85 -46
  2. {lmnr-0.4.10 → lmnr-0.4.12b1}/README.md +82 -45
  3. {lmnr-0.4.10 → lmnr-0.4.12b1}/pyproject.toml +5 -6
  4. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/__init__.py +1 -1
  5. lmnr-0.4.12b1/src/lmnr/cli.py +39 -0
  6. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/sdk/decorators.py +4 -7
  7. lmnr-0.4.12b1/src/lmnr/sdk/evaluations.py +290 -0
  8. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/sdk/laminar.py +49 -34
  9. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/sdk/types.py +23 -19
  10. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/__init__.py +0 -13
  11. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/instruments.py +9 -4
  12. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tracing/tracing.py +6 -63
  13. lmnr-0.4.10/src/lmnr/sdk/evaluations.py +0 -178
  14. {lmnr-0.4.10 → lmnr-0.4.12b1}/LICENSE +0 -0
  15. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/sdk/__init__.py +0 -0
  16. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/sdk/log.py +0 -0
  17. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/sdk/utils.py +0 -0
  18. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/.flake8 +0 -0
  19. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/.python-version +0 -0
  20. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/config/__init__.py +0 -0
  21. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/decorators/__init__.py +0 -0
  22. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/decorators/base.py +0 -0
  23. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/metrics/__init__.py +0 -0
  24. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/metrics/metrics.py +0 -0
  25. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/__init__.py +0 -0
  26. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_and_external_association_properties.yaml +0 -0
  27. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_association_properties.yaml +0 -0
  28. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_manual/test_manual_report.yaml +0 -0
  29. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_manual/test_resource_attributes.yaml +0 -0
  30. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_privacy_no_prompts/test_simple_workflow.yaml +0 -0
  31. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_prompt_management/test_prompt_management.yaml +0 -0
  32. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_sdk_initialization/test_resource_attributes.yaml +0 -0
  33. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_tasks/test_task_io_serialization_with_langchain.yaml +0 -0
  34. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_aworkflow.yaml +0 -0
  35. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_workflow.yaml +0 -0
  36. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_streaming_workflow.yaml +0 -0
  37. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/conftest.py +0 -0
  38. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_association_properties.py +0 -0
  39. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_manual.py +0 -0
  40. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_nested_tasks.py +0 -0
  41. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_privacy_no_prompts.py +0 -0
  42. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_sdk_initialization.py +0 -0
  43. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_tasks.py +0 -0
  44. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tests/test_workflows.py +0 -0
  45. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tracing/__init__.py +0 -0
  46. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tracing/content_allow_list.py +0 -0
  47. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tracing/context_manager.py +0 -0
  48. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/tracing/manual.py +0 -0
  49. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/utils/__init__.py +0 -0
  50. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/utils/in_memory_span_exporter.py +0 -0
  51. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/utils/json_encoder.py +0 -0
  52. {lmnr-0.4.10 → lmnr-0.4.12b1}/src/lmnr/traceloop_sdk/utils/package_check.py +0 -0
  53. {lmnr-0.4.10 → lmnr-0.4.12b1}/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.10
3
+ Version: 0.4.12b1
4
4
  Summary: Python SDK for Laminar AI
5
5
  License: Apache-2.0
6
6
  Author: lmnr.ai
@@ -11,6 +11,7 @@ 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: argparse (>=1.0,<2.0)
14
15
  Requires-Dist: asyncio (>=3.0,<4.0)
15
16
  Requires-Dist: backoff (>=2.0,<3.0)
16
17
  Requires-Dist: colorama (>=0.4,<0.5)
@@ -54,6 +55,7 @@ Requires-Dist: pydantic (>=2.7,<3.0)
54
55
  Requires-Dist: python-dotenv (>=1.0,<2.0)
55
56
  Requires-Dist: requests (>=2.0,<3.0)
56
57
  Requires-Dist: tenacity (>=8.0,<9.0)
58
+ Requires-Dist: tqdm (>=4.0,<5.0)
57
59
  Description-Content-Type: text/markdown
58
60
 
59
61
  # Laminar Python
@@ -67,6 +69,9 @@ OpenTelemetry log sender for [Laminar](https://github.com/lmnr-ai/lmnr) for Pyth
67
69
 
68
70
 
69
71
  ## Quickstart
72
+
73
+ First, install the package:
74
+
70
75
  ```sh
71
76
  python3 -m venv .myenv
72
77
  source .myenv/bin/activate # or use your favorite env management tool
@@ -74,22 +79,39 @@ source .myenv/bin/activate # or use your favorite env management tool
74
79
  pip install lmnr
75
80
  ```
76
81
 
77
- And the in your main Python file
82
+ Then, you can initialize Laminar in your main file and instrument your code.
78
83
 
79
84
  ```python
80
- from lmnr import Laminar as L, Instruments
85
+ import os
86
+ from openai import OpenAI
87
+ from lmnr import Laminar as L
81
88
 
82
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI, Instruments.ANTHROPIC})
83
- ```
89
+ L.initialize(
90
+ project_api_key=os.environ["LMNR_PROJECT_API_KEY"],
91
+ )
84
92
 
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()`.
93
+ client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
94
+
95
+ def poem_writer(topic: str):
96
+ prompt = f"write a poem about {topic}"
97
+
98
+ # OpenAI calls are automatically instrumented
99
+ response = client.chat.completions.create(
100
+ model="gpt-4o",
101
+ messages=[
102
+ {"role": "system", "content": "You are a helpful assistant."},
103
+ {"role": "user", "content": prompt},
104
+ ],
105
+ )
106
+ poem = response.choices[0].message.content
107
+ return poem
87
108
 
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.
109
+ if __name__ == "__main__":
110
+ print(poem_writer("laminar flow"))
111
+
112
+ ```
90
113
 
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.
114
+ Note that you need to only initialize Laminar once in your application.
93
115
 
94
116
  ### Project API key
95
117
 
@@ -98,67 +120,84 @@ You can either pass it to `.initialize()` or set it to `.env` at the root of you
98
120
 
99
121
  ## Instrumentation
100
122
 
101
- In addition to automatic instrumentation, we provide a simple `@observe()` decorator, if you want more fine-grained tracing
102
- or to trace other functions.
123
+ ### Manual instrumentation
103
124
 
104
- ### Example
125
+ To instrument any function in your code, we provide a simple `@observe()` decorator.
126
+ This can be useful if you want to trace a request handler or a function which combines multiple LLM calls.
105
127
 
106
128
  ```python
107
129
  import os
108
130
  from openai import OpenAI
131
+ from lmnr import Laminar as L, Instruments
109
132
 
110
-
111
- from lmnr import observe, Laminar as L, Instruments
112
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
133
+ L.initialize(project_api_key=os.environ["LMNR_PROJECT_API_KEY"])
113
134
 
114
135
  client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
115
136
 
116
- @observe() # annotate all functions you want to trace
117
- def poem_writer(topic="turbulence"):
137
+ def poem_writer(topic: str):
118
138
  prompt = f"write a poem about {topic}"
139
+ messages = [
140
+ {"role": "system", "content": "You are a helpful assistant."},
141
+ {"role": "user", "content": prompt},
142
+ ]
143
+
144
+ # OpenAI calls are still automatically instrumented
119
145
  response = client.chat.completions.create(
120
146
  model="gpt-4o",
121
- messages=[
122
- {"role": "system", "content": "You are a helpful assistant."},
123
- {"role": "user", "content": prompt},
124
- ],
147
+ messages=messages,
125
148
  )
126
149
  poem = response.choices[0].message.content
150
+
127
151
  return poem
128
152
 
129
- print(poem_writer(topic="laminar flow"))
153
+ @observe()
154
+ def generate_poems():
155
+ poem1 = poem_writer(topic="laminar flow")
156
+ L.event("is_poem_generated", True)
157
+ poem2 = poem_writer(topic="turbulence")
158
+ L.event("is_poem_generated", True)
159
+ poems = f"{poem1}\n\n---\n\n{poem2}"
160
+ return poems
130
161
  ```
131
162
 
132
- ### Manual instrumentation
133
-
134
- Also, you can `Laminar.start_as_current_span` if you want to record a chunk of your code.
163
+ Also, you can use `Laminar.start_as_current_span` if you want to record a chunk of your code using `with` statement.
135
164
 
136
165
  ```python
137
- from lmnr import observe, Laminar as L, Instruments
138
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
166
+ def handle_user_request(topic: str):
167
+ with L.start_as_current_span(name="poem_writer", input=topic):
168
+ ...
169
+
170
+ poem = poem_writer(topic=topic)
171
+
172
+ ...
173
+
174
+ # while within the span, you can attach laminar events to it
175
+ L.event("is_poem_generated", True)
139
176
 
140
- def poem_writer(topic="turbulence"):
141
- prompt = f"write a poem about {topic}"
142
- messages = [
143
- {"role": "system", "content": "You are a helpful assistant."},
144
- {"role": "user", "content": prompt},
145
- ]
177
+ # Use set_span_output to record the output of the span
178
+ L.set_span_output(poem)
179
+ ```
146
180
 
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")
181
+ ### Automatic instrumentation
156
182
 
157
- L.set_span_output(poem) # set an output
183
+ Laminar allows you to automatically instrument majority of the most popular LLM, Vector DB, database, requests, and other libraries.
158
184
 
159
- return poem
185
+ If you want to automatically instrument a default set of libraries, then simply do NOT pass `instruments` argument to `.initialize()`.
186
+ See the full list of available instrumentations in the [enum](/src/lmnr/traceloop_sdk/instruments.py).
187
+
188
+ If you want to automatically instrument only specific LLM, Vector DB, or other
189
+ calls with OpenTelemetry-compatible instrumentation, then pass the appropriate instruments to `.initialize()`.
190
+ For example, if you want to only instrument OpenAI and Anthropic, then do the following:
191
+
192
+ ```python
193
+ from lmnr import Laminar as L, Instruments
194
+
195
+ L.initialize(project_api_key=os.environ["LMNR_PROJECT_API_KEY"], instruments={Instruments.OPENAI, Instruments.ANTHROPIC})
160
196
  ```
161
197
 
198
+ If you want to fully disable any kind of autoinstrumentation, pass an empty set as `instruments=set()` to `.initialize()`.
199
+
200
+ Majority of the autoinstrumentations are provided by Traceloop's [OpenLLMetry](https://github.com/traceloop/openllmetry).
162
201
 
163
202
  ## Sending events
164
203
 
@@ -9,6 +9,9 @@ OpenTelemetry log sender for [Laminar](https://github.com/lmnr-ai/lmnr) for Pyth
9
9
 
10
10
 
11
11
  ## Quickstart
12
+
13
+ First, install the package:
14
+
12
15
  ```sh
13
16
  python3 -m venv .myenv
14
17
  source .myenv/bin/activate # or use your favorite env management tool
@@ -16,22 +19,39 @@ source .myenv/bin/activate # or use your favorite env management tool
16
19
  pip install lmnr
17
20
  ```
18
21
 
19
- And the in your main Python file
22
+ Then, you can initialize Laminar in your main file and instrument your code.
20
23
 
21
24
  ```python
22
- from lmnr import Laminar as L, Instruments
25
+ import os
26
+ from openai import OpenAI
27
+ from lmnr import Laminar as L
23
28
 
24
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI, Instruments.ANTHROPIC})
25
- ```
29
+ L.initialize(
30
+ project_api_key=os.environ["LMNR_PROJECT_API_KEY"],
31
+ )
26
32
 
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()`.
33
+ client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
34
+
35
+ def poem_writer(topic: str):
36
+ prompt = f"write a poem about {topic}"
37
+
38
+ # OpenAI calls are automatically instrumented
39
+ response = client.chat.completions.create(
40
+ model="gpt-4o",
41
+ messages=[
42
+ {"role": "system", "content": "You are a helpful assistant."},
43
+ {"role": "user", "content": prompt},
44
+ ],
45
+ )
46
+ poem = response.choices[0].message.content
47
+ return poem
29
48
 
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.
49
+ if __name__ == "__main__":
50
+ print(poem_writer("laminar flow"))
51
+
52
+ ```
32
53
 
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.
54
+ Note that you need to only initialize Laminar once in your application.
35
55
 
36
56
  ### Project API key
37
57
 
@@ -40,67 +60,84 @@ You can either pass it to `.initialize()` or set it to `.env` at the root of you
40
60
 
41
61
  ## Instrumentation
42
62
 
43
- In addition to automatic instrumentation, we provide a simple `@observe()` decorator, if you want more fine-grained tracing
44
- or to trace other functions.
63
+ ### Manual instrumentation
45
64
 
46
- ### Example
65
+ To instrument any function in your code, we provide a simple `@observe()` decorator.
66
+ This can be useful if you want to trace a request handler or a function which combines multiple LLM calls.
47
67
 
48
68
  ```python
49
69
  import os
50
70
  from openai import OpenAI
71
+ from lmnr import Laminar as L, Instruments
51
72
 
52
-
53
- from lmnr import observe, Laminar as L, Instruments
54
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
73
+ L.initialize(project_api_key=os.environ["LMNR_PROJECT_API_KEY"])
55
74
 
56
75
  client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
57
76
 
58
- @observe() # annotate all functions you want to trace
59
- def poem_writer(topic="turbulence"):
77
+ def poem_writer(topic: str):
60
78
  prompt = f"write a poem about {topic}"
79
+ messages = [
80
+ {"role": "system", "content": "You are a helpful assistant."},
81
+ {"role": "user", "content": prompt},
82
+ ]
83
+
84
+ # OpenAI calls are still automatically instrumented
61
85
  response = client.chat.completions.create(
62
86
  model="gpt-4o",
63
- messages=[
64
- {"role": "system", "content": "You are a helpful assistant."},
65
- {"role": "user", "content": prompt},
66
- ],
87
+ messages=messages,
67
88
  )
68
89
  poem = response.choices[0].message.content
90
+
69
91
  return poem
70
92
 
71
- print(poem_writer(topic="laminar flow"))
93
+ @observe()
94
+ def generate_poems():
95
+ poem1 = poem_writer(topic="laminar flow")
96
+ L.event("is_poem_generated", True)
97
+ poem2 = poem_writer(topic="turbulence")
98
+ L.event("is_poem_generated", True)
99
+ poems = f"{poem1}\n\n---\n\n{poem2}"
100
+ return poems
72
101
  ```
73
102
 
74
- ### Manual instrumentation
75
-
76
- Also, you can `Laminar.start_as_current_span` if you want to record a chunk of your code.
103
+ Also, you can use `Laminar.start_as_current_span` if you want to record a chunk of your code using `with` statement.
77
104
 
78
105
  ```python
79
- from lmnr import observe, Laminar as L, Instruments
80
- L.initialize(project_api_key="<LMNR_PROJECT_API_KEY>", instruments={Instruments.OPENAI})
106
+ def handle_user_request(topic: str):
107
+ with L.start_as_current_span(name="poem_writer", input=topic):
108
+ ...
109
+
110
+ poem = poem_writer(topic=topic)
111
+
112
+ ...
113
+
114
+ # while within the span, you can attach laminar events to it
115
+ L.event("is_poem_generated", True)
81
116
 
82
- def poem_writer(topic="turbulence"):
83
- prompt = f"write a poem about {topic}"
84
- messages = [
85
- {"role": "system", "content": "You are a helpful assistant."},
86
- {"role": "user", "content": prompt},
87
- ]
117
+ # Use set_span_output to record the output of the span
118
+ L.set_span_output(poem)
119
+ ```
88
120
 
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")
121
+ ### Automatic instrumentation
98
122
 
99
- L.set_span_output(poem) # set an output
123
+ Laminar allows you to automatically instrument majority of the most popular LLM, Vector DB, database, requests, and other libraries.
100
124
 
101
- return poem
125
+ If you want to automatically instrument a default set of libraries, then simply do NOT pass `instruments` argument to `.initialize()`.
126
+ See the full list of available instrumentations in the [enum](/src/lmnr/traceloop_sdk/instruments.py).
127
+
128
+ If you want to automatically instrument only specific LLM, Vector DB, or other
129
+ calls with OpenTelemetry-compatible instrumentation, then pass the appropriate instruments to `.initialize()`.
130
+ For example, if you want to only instrument OpenAI and Anthropic, then do the following:
131
+
132
+ ```python
133
+ from lmnr import Laminar as L, Instruments
134
+
135
+ L.initialize(project_api_key=os.environ["LMNR_PROJECT_API_KEY"], instruments={Instruments.OPENAI, Instruments.ANTHROPIC})
102
136
  ```
103
137
 
138
+ If you want to fully disable any kind of autoinstrumentation, pass an empty set as `instruments=set()` to `.initialize()`.
139
+
140
+ Majority of the autoinstrumentations are provided by Traceloop's [OpenLLMetry](https://github.com/traceloop/openllmetry).
104
141
 
105
142
  ## Sending events
106
143
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lmnr"
3
- version = "0.4.10"
3
+ version = "0.4.12b1"
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.10"
14
+ version = "0.4.12b1"
15
15
  description = "Python SDK for Laminar AI"
16
16
  authors = ["lmnr.ai"]
17
17
  readme = "README.md"
@@ -62,6 +62,8 @@ opentelemetry-instrumentation-weaviate = "^0.30.0"
62
62
  opentelemetry-instrumentation-alephalpha = "^0.30.0"
63
63
  opentelemetry-instrumentation-marqo = "^0.30.0"
64
64
  opentelemetry-instrumentation-groq = "^0.30.0"
65
+ tqdm = "~=4.0"
66
+ argparse = "~=1.0"
65
67
 
66
68
  [tool.poetry.group.dev.dependencies]
67
69
  autopep8 = "^2.2.0"
@@ -83,11 +85,8 @@ langchain-openai = "^0.1.15"
83
85
  requires = ["poetry-core"]
84
86
  build-backend = "poetry.core.masonry.api"
85
87
 
86
- [project.entry-points.console_scripts]
87
- lmnr = "lmnr.cli.cli:cli"
88
-
89
88
  [tool.poetry.scripts]
90
- lmnr = "lmnr.cli.cli:cli"
89
+ lmnr = "lmnr.cli:cli"
91
90
 
92
91
  [project.optional-dependencies]
93
92
  test = ["pytest"]
@@ -1,4 +1,4 @@
1
- from .sdk.evaluations import Evaluation
1
+ from .sdk.evaluations import evaluate
2
2
  from .sdk.laminar import Laminar
3
3
  from .sdk.types import ChatMessage, PipelineRunError, PipelineRunResponse, NodeInput
4
4
  from .sdk.decorators import observe
@@ -0,0 +1,39 @@
1
+ from argparse import ArgumentParser
2
+ import asyncio
3
+ import importlib
4
+ import os
5
+ import sys
6
+
7
+ from lmnr.sdk.evaluations import set_global_evaluation
8
+
9
+
10
+ # TODO: Refactor this code
11
+ async def run_evaluation(args):
12
+ sys.path.insert(0, os.getcwd())
13
+
14
+ with set_global_evaluation(True):
15
+ file = os.path.abspath(args.file)
16
+
17
+ spec = importlib.util.spec_from_file_location("run_eval", file)
18
+ mod = importlib.util.module_from_spec(spec)
19
+ spec.loader.exec_module(mod)
20
+
21
+ from lmnr.sdk.evaluations import _evaluation
22
+ evaluation = _evaluation
23
+ await evaluation.run()
24
+
25
+
26
+ def cli():
27
+ parser = ArgumentParser(
28
+ prog="lmnr",
29
+ description="CLI for Laminar",
30
+ )
31
+
32
+ subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
33
+
34
+ parser_eval = subparsers.add_parser("eval", description="Run an evaluation")
35
+ parser_eval.add_argument("file", help="A file containing the evaluation to run")
36
+ parser_eval.set_defaults(func=run_evaluation)
37
+
38
+ parsed = parser.parse_args()
39
+ asyncio.run(parsed.func(parsed))
@@ -4,22 +4,19 @@ from lmnr.traceloop_sdk.decorators.base import (
4
4
  )
5
5
  from opentelemetry.trace import INVALID_SPAN, get_current_span
6
6
 
7
- from typing import Callable, Optional, ParamSpec, TypeVar, cast
7
+ from typing import Callable, Optional, cast
8
8
 
9
9
  from lmnr.traceloop_sdk.tracing.tracing import update_association_properties
10
10
 
11
11
  from .utils import is_async
12
12
 
13
- P = ParamSpec("P")
14
- R = TypeVar("R")
15
-
16
13
 
17
14
  def observe(
18
15
  *,
19
16
  name: Optional[str] = None,
20
17
  user_id: Optional[str] = None,
21
18
  session_id: Optional[str] = None,
22
- ) -> Callable[[Callable[P, R]], Callable[P, R]]:
19
+ ) -> Callable[[Callable], Callable]:
23
20
  """The main decorator entrypoint for Laminar. This is used to wrap
24
21
  functions and methods to create spans.
25
22
 
@@ -41,7 +38,7 @@ def observe(
41
38
  R: Returns the result of the wrapped function
42
39
  """
43
40
 
44
- def decorator(func: Callable[P, R]) -> Callable[P, R]:
41
+ def decorator(func: Callable) -> Callable:
45
42
  current_span = get_current_span()
46
43
  if current_span != INVALID_SPAN:
47
44
  if session_id is not None:
@@ -64,4 +61,4 @@ def observe(
64
61
  else entity_method(name=name)(func)
65
62
  )
66
63
 
67
- return cast(Callable[P, R], decorator)
64
+ return cast(Callable, decorator)