lmnr 0.6.1__tar.gz → 0.6.3__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.
- {lmnr-0.6.1 → lmnr-0.6.3}/PKG-INFO +1 -1
- {lmnr-0.6.1 → lmnr-0.6.3}/pyproject.toml +1 -1
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/cli.py +18 -10
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/decorators/__init__.py +16 -1
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/browser_use_otel.py +5 -4
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/asynchronous/resources/evals.py +4 -3
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/synchronous/resources/evals.py +4 -3
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/decorators.py +24 -6
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/eval_control.py +1 -1
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/evaluations.py +26 -6
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/laminar.py +10 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/types.py +4 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/version.py +1 -1
- {lmnr-0.6.1 → lmnr-0.6.3}/LICENSE +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/README.md +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/.flake8 +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/config.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/attributes.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/context_properties.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/exporter.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/instruments.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/processor.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/tracing/tracer.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/utils/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/utils/json_encoder.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/opentelemetry_lib/utils/package_check.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/py.typed +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/patchright_otel.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/playwright_otel.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/pw_utils.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/rrweb/rrweb.umd.min.cjs +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/browser/utils.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/asynchronous/async_client.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/asynchronous/resources/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/asynchronous/resources/agent.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/asynchronous/resources/base.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/asynchronous/resources/browser_events.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/synchronous/resources/__init__.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/synchronous/resources/agent.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/synchronous/resources/base.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/synchronous/resources/browser_events.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/client/synchronous/sync_client.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/datasets.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/log.py +0 -0
- {lmnr-0.6.1 → lmnr-0.6.3}/src/lmnr/sdk/utils.py +0 -0
@@ -8,7 +8,7 @@ from typing import Optional
|
|
8
8
|
|
9
9
|
from lmnr.sdk.evaluations import Evaluation
|
10
10
|
|
11
|
-
from .sdk.eval_control import PREPARE_ONLY,
|
11
|
+
from .sdk.eval_control import PREPARE_ONLY, EVALUATION_INSTANCES
|
12
12
|
from .sdk.log import get_default_logger
|
13
13
|
|
14
14
|
LOG = get_default_logger(__name__)
|
@@ -38,10 +38,10 @@ async def run_evaluation(args):
|
|
38
38
|
else:
|
39
39
|
files = [args.file]
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
prep_token = PREPARE_ONLY.set(True)
|
42
|
+
try:
|
43
|
+
for file in files:
|
44
|
+
LOG.info(f"Running evaluation from {file}")
|
45
45
|
file = os.path.abspath(file)
|
46
46
|
name = "user_module" + file
|
47
47
|
|
@@ -55,16 +55,24 @@ async def run_evaluation(args):
|
|
55
55
|
sys.modules[name] = mod
|
56
56
|
|
57
57
|
spec.loader.exec_module(mod)
|
58
|
-
|
59
|
-
if
|
58
|
+
evaluations: Optional[list[Evaluation]] = EVALUATION_INSTANCES.get()
|
59
|
+
if evaluations is None:
|
60
60
|
LOG.warning("Evaluation instance not found")
|
61
61
|
if args.fail_on_error:
|
62
62
|
return
|
63
63
|
continue
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
LOG.info(f"Loaded {len(evaluations)} evaluations from {file}")
|
66
|
+
|
67
|
+
for evaluation in evaluations:
|
68
|
+
try:
|
69
|
+
await evaluation.run()
|
70
|
+
except Exception as e:
|
71
|
+
LOG.error(f"Error running evaluation: {e}")
|
72
|
+
if args.fail_on_error:
|
73
|
+
raise
|
74
|
+
finally:
|
75
|
+
PREPARE_ONLY.reset(prep_token)
|
68
76
|
|
69
77
|
|
70
78
|
def cli():
|
@@ -9,6 +9,10 @@ from opentelemetry import trace
|
|
9
9
|
from opentelemetry import context as context_api
|
10
10
|
from opentelemetry.trace import Span
|
11
11
|
|
12
|
+
from lmnr.opentelemetry_lib.tracing.context_properties import (
|
13
|
+
remove_association_properties,
|
14
|
+
update_association_properties,
|
15
|
+
)
|
12
16
|
from lmnr.sdk.utils import get_input_from_func_args, is_method
|
13
17
|
from lmnr.opentelemetry_lib import MAX_MANUAL_SPAN_PAYLOAD_SIZE
|
14
18
|
from lmnr.opentelemetry_lib.tracing.tracer import get_tracer
|
@@ -42,6 +46,7 @@ def entity_method(
|
|
42
46
|
ignore_inputs: Optional[list[str]] = None,
|
43
47
|
ignore_output: bool = False,
|
44
48
|
span_type: Union[Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]] = "DEFAULT",
|
49
|
+
association_properties: Optional[dict[str, Any]] = None,
|
45
50
|
):
|
46
51
|
def decorate(fn):
|
47
52
|
@wraps(fn)
|
@@ -51,6 +56,9 @@ def entity_method(
|
|
51
56
|
|
52
57
|
span_name = name or fn.__name__
|
53
58
|
|
59
|
+
if association_properties is not None:
|
60
|
+
update_association_properties(association_properties)
|
61
|
+
|
54
62
|
with get_tracer() as tracer:
|
55
63
|
span = tracer.start_span(span_name, attributes={SPAN_TYPE: span_type})
|
56
64
|
|
@@ -111,7 +119,8 @@ def entity_method(
|
|
111
119
|
|
112
120
|
span.end()
|
113
121
|
context_api.detach(ctx_token)
|
114
|
-
|
122
|
+
if association_properties is not None:
|
123
|
+
remove_association_properties(association_properties)
|
115
124
|
return res
|
116
125
|
|
117
126
|
return wrap
|
@@ -126,6 +135,7 @@ def aentity_method(
|
|
126
135
|
ignore_inputs: Optional[list[str]] = None,
|
127
136
|
ignore_output: bool = False,
|
128
137
|
span_type: Union[Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]] = "DEFAULT",
|
138
|
+
association_properties: Optional[dict[str, Any]] = None,
|
129
139
|
):
|
130
140
|
def decorate(fn):
|
131
141
|
@wraps(fn)
|
@@ -135,6 +145,9 @@ def aentity_method(
|
|
135
145
|
|
136
146
|
span_name = name or fn.__name__
|
137
147
|
|
148
|
+
if association_properties is not None:
|
149
|
+
update_association_properties(association_properties)
|
150
|
+
|
138
151
|
with get_tracer() as tracer:
|
139
152
|
span = tracer.start_span(span_name, attributes={SPAN_TYPE: span_type})
|
140
153
|
|
@@ -187,6 +200,8 @@ def aentity_method(
|
|
187
200
|
pass
|
188
201
|
|
189
202
|
span.end()
|
203
|
+
if association_properties is not None:
|
204
|
+
remove_association_properties(association_properties)
|
190
205
|
context_api.detach(ctx_token)
|
191
206
|
|
192
207
|
return res
|
@@ -83,12 +83,13 @@ async def _wrap(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
83
83
|
span.set_attributes(attributes)
|
84
84
|
result = await wrapped(*args, **kwargs)
|
85
85
|
if not to_wrap.get("ignore_output"):
|
86
|
+
to_serialize = result
|
86
87
|
if isinstance(result, AgentHistoryList):
|
87
|
-
|
88
|
+
to_serialize = result.final_result()
|
88
89
|
serialized = (
|
89
|
-
|
90
|
-
if isinstance(
|
91
|
-
else json_dumps(
|
90
|
+
to_serialize.model_dump_json()
|
91
|
+
if isinstance(to_serialize, pydantic.BaseModel)
|
92
|
+
else json_dumps(to_serialize)
|
92
93
|
)
|
93
94
|
span.set_attribute("lmnr.span.output", serialized)
|
94
95
|
return result
|
@@ -1,12 +1,13 @@
|
|
1
1
|
"""Evals resource for interacting with Laminar evaluations API."""
|
2
2
|
|
3
3
|
import uuid
|
4
|
-
from typing import Optional
|
4
|
+
from typing import Optional, Union
|
5
5
|
|
6
6
|
from lmnr.sdk.client.asynchronous.resources.base import BaseAsyncResource
|
7
7
|
from lmnr.sdk.types import (
|
8
8
|
InitEvaluationResponse,
|
9
9
|
EvaluationResultDatapoint,
|
10
|
+
PartialEvaluationDatapoint,
|
10
11
|
)
|
11
12
|
|
12
13
|
|
@@ -39,14 +40,14 @@ class AsyncEvals(BaseAsyncResource):
|
|
39
40
|
async def save_datapoints(
|
40
41
|
self,
|
41
42
|
eval_id: uuid.UUID,
|
42
|
-
datapoints: list[EvaluationResultDatapoint],
|
43
|
+
datapoints: list[Union[EvaluationResultDatapoint, PartialEvaluationDatapoint]],
|
43
44
|
group_name: Optional[str] = None,
|
44
45
|
):
|
45
46
|
"""Save evaluation datapoints.
|
46
47
|
|
47
48
|
Args:
|
48
49
|
eval_id (uuid.UUID): The evaluation ID.
|
49
|
-
datapoints (list[EvaluationResultDatapoint]): The datapoints to save.
|
50
|
+
datapoints (list[Union[EvaluationResultDatapoint, PartialEvaluationDatapoint]]): The datapoints to save.
|
50
51
|
group_name (Optional[str], optional): Group name for the datapoints. Defaults to None.
|
51
52
|
|
52
53
|
Raises:
|
@@ -2,12 +2,13 @@
|
|
2
2
|
|
3
3
|
import uuid
|
4
4
|
import urllib.parse
|
5
|
-
from typing import Optional
|
5
|
+
from typing import Optional, Union
|
6
6
|
|
7
7
|
from lmnr.sdk.client.synchronous.resources.base import BaseResource
|
8
8
|
from lmnr.sdk.types import (
|
9
9
|
InitEvaluationResponse,
|
10
10
|
EvaluationResultDatapoint,
|
11
|
+
PartialEvaluationDatapoint,
|
11
12
|
GetDatapointsResponse,
|
12
13
|
)
|
13
14
|
|
@@ -41,14 +42,14 @@ class Evals(BaseResource):
|
|
41
42
|
def save_datapoints(
|
42
43
|
self,
|
43
44
|
eval_id: uuid.UUID,
|
44
|
-
datapoints: list[EvaluationResultDatapoint],
|
45
|
+
datapoints: list[Union[EvaluationResultDatapoint, PartialEvaluationDatapoint]],
|
45
46
|
group_name: Optional[str] = None,
|
46
47
|
):
|
47
48
|
"""Save evaluation datapoints.
|
48
49
|
|
49
50
|
Args:
|
50
51
|
eval_id (uuid.UUID): The evaluation ID.
|
51
|
-
datapoints (list[EvaluationResultDatapoint]): The datapoints to save.
|
52
|
+
datapoints (list[Union[EvaluationResultDatapoint, PartialEvaluationDatapoint]]): The datapoints to save.
|
52
53
|
group_name (Optional[str], optional): Group name for the datapoints. Defaults to None.
|
53
54
|
|
54
55
|
Raises:
|
@@ -1,16 +1,14 @@
|
|
1
1
|
from lmnr.opentelemetry_lib.decorators import (
|
2
2
|
entity_method,
|
3
3
|
aentity_method,
|
4
|
+
json_dumps,
|
4
5
|
)
|
5
6
|
from opentelemetry.trace import INVALID_SPAN, get_current_span
|
6
7
|
|
7
|
-
from typing import Callable, Literal, Optional, TypeVar, Union, cast
|
8
|
+
from typing import Any, Callable, Literal, Optional, TypeVar, Union, cast
|
8
9
|
from typing_extensions import ParamSpec
|
9
10
|
|
10
11
|
from lmnr.opentelemetry_lib.tracing.attributes import SESSION_ID
|
11
|
-
from lmnr.opentelemetry_lib.tracing.context_properties import (
|
12
|
-
update_association_properties,
|
13
|
-
)
|
14
12
|
|
15
13
|
from .utils import is_async
|
16
14
|
|
@@ -23,10 +21,12 @@ def observe(
|
|
23
21
|
*,
|
24
22
|
name: Optional[str] = None,
|
25
23
|
session_id: Optional[str] = None,
|
24
|
+
user_id: Optional[str] = None,
|
26
25
|
ignore_input: bool = False,
|
27
26
|
ignore_output: bool = False,
|
28
27
|
span_type: Union[Literal["DEFAULT"], Literal["LLM"], Literal["TOOL"]] = "DEFAULT",
|
29
28
|
ignore_inputs: Optional[list[str]] = None,
|
29
|
+
metadata: Optional[dict[str, Any]] = None,
|
30
30
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
31
31
|
"""The main decorator entrypoint for Laminar. This is used to wrap
|
32
32
|
functions and methods to create spans.
|
@@ -37,6 +37,9 @@ def observe(
|
|
37
37
|
Defaults to None.
|
38
38
|
session_id (Optional[str], optional): Session ID to associate with the\
|
39
39
|
span and the following context. Defaults to None.
|
40
|
+
user_id (Optional[str], optional): User ID to associate with the\
|
41
|
+
span and the following context. This is different from \
|
42
|
+
ID of a Laminar user. Defaults to None.
|
40
43
|
ignore_input (bool, optional): Whether to ignore ALL input of the\
|
41
44
|
wrapped function. Defaults to False.
|
42
45
|
ignore_output (bool, optional): Whether to ignore ALL output of the\
|
@@ -49,6 +52,8 @@ def observe(
|
|
49
52
|
`sensitive_data` argument, you can pass ["sensitive_data"] to\
|
50
53
|
this argument.
|
51
54
|
Defaults to None.
|
55
|
+
metadata (Optional[dict[str, Any]], optional): Metadata to associate with the\
|
56
|
+
trace. Must be JSON serializable. Defaults to None.
|
52
57
|
Raises:
|
53
58
|
Exception: re-raises the exception if the wrapped function raises
|
54
59
|
an exception
|
@@ -65,14 +70,25 @@ def observe(
|
|
65
70
|
association_properties = {}
|
66
71
|
if session_id is not None:
|
67
72
|
association_properties["session_id"] = session_id
|
68
|
-
|
69
|
-
|
73
|
+
if user_id is not None:
|
74
|
+
association_properties["user_id"] = user_id
|
75
|
+
if metadata is not None:
|
76
|
+
association_properties.update(
|
77
|
+
{
|
78
|
+
f"metadata.{k}": (
|
79
|
+
v if isinstance(v, (str, int, float, bool)) else json_dumps(v)
|
80
|
+
)
|
81
|
+
for k, v in metadata.items()
|
82
|
+
}
|
83
|
+
)
|
84
|
+
result = (
|
70
85
|
aentity_method(
|
71
86
|
name=name,
|
72
87
|
ignore_input=ignore_input,
|
73
88
|
ignore_output=ignore_output,
|
74
89
|
span_type=span_type,
|
75
90
|
ignore_inputs=ignore_inputs,
|
91
|
+
association_properties=association_properties,
|
76
92
|
)(func)
|
77
93
|
if is_async(func)
|
78
94
|
else entity_method(
|
@@ -81,7 +97,9 @@ def observe(
|
|
81
97
|
ignore_output=ignore_output,
|
82
98
|
span_type=span_type,
|
83
99
|
ignore_inputs=ignore_inputs,
|
100
|
+
association_properties=association_properties,
|
84
101
|
)(func)
|
85
102
|
)
|
103
|
+
return result
|
86
104
|
|
87
105
|
return cast(Callable, decorator)
|
@@ -11,7 +11,7 @@ from lmnr.opentelemetry_lib.tracing.attributes import SPAN_TYPE
|
|
11
11
|
from lmnr.sdk.client.asynchronous.async_client import AsyncLaminarClient
|
12
12
|
from lmnr.sdk.client.synchronous.sync_client import LaminarClient
|
13
13
|
from lmnr.sdk.datasets import EvaluationDataset, LaminarDataset
|
14
|
-
from lmnr.sdk.eval_control import
|
14
|
+
from lmnr.sdk.eval_control import EVALUATION_INSTANCES, PREPARE_ONLY
|
15
15
|
from lmnr.sdk.laminar import Laminar as L
|
16
16
|
from lmnr.sdk.log import get_default_logger
|
17
17
|
from lmnr.sdk.types import (
|
@@ -204,6 +204,18 @@ class Evaluation:
|
|
204
204
|
)
|
205
205
|
self.project_api_key = api_key
|
206
206
|
|
207
|
+
if L.is_initialized():
|
208
|
+
self.client = AsyncLaminarClient(
|
209
|
+
base_url=L.get_base_http_url(),
|
210
|
+
project_api_key=L.get_project_api_key(),
|
211
|
+
)
|
212
|
+
if project_api_key and project_api_key != L.get_project_api_key():
|
213
|
+
self._logger.warning(
|
214
|
+
"Project API key is different from the one used to initialize"
|
215
|
+
" Laminar. Ignoring the project API key passed to the evaluation."
|
216
|
+
)
|
217
|
+
return
|
218
|
+
|
207
219
|
self.client = AsyncLaminarClient(
|
208
220
|
base_url=self.base_http_url,
|
209
221
|
project_api_key=self.project_api_key,
|
@@ -312,6 +324,7 @@ class Evaluation:
|
|
312
324
|
index=index,
|
313
325
|
trace_id=trace_id,
|
314
326
|
executor_span_id=executor_span_id,
|
327
|
+
metadata=datapoint.metadata,
|
315
328
|
)
|
316
329
|
# First, create datapoint with trace_id so that we can show the dp in the UI
|
317
330
|
await self.client._evals.save_datapoints(
|
@@ -367,6 +380,7 @@ class Evaluation:
|
|
367
380
|
human_evaluators=self.human_evaluators,
|
368
381
|
executor_span_id=executor_span_id,
|
369
382
|
index=index,
|
383
|
+
metadata=datapoint.metadata,
|
370
384
|
)
|
371
385
|
|
372
386
|
# Create background upload task without awaiting it
|
@@ -470,10 +484,16 @@ def evaluate(
|
|
470
484
|
)
|
471
485
|
|
472
486
|
if PREPARE_ONLY.get():
|
473
|
-
|
487
|
+
existing_evaluations = EVALUATION_INSTANCES.get([])
|
488
|
+
new_evaluations = (existing_evaluations or []) + [evaluation]
|
489
|
+
EVALUATION_INSTANCES.set(new_evaluations)
|
490
|
+
return None
|
474
491
|
else:
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
492
|
+
try:
|
493
|
+
loop = asyncio.get_event_loop()
|
494
|
+
if loop.is_running():
|
495
|
+
return evaluation.run()
|
496
|
+
else:
|
497
|
+
return asyncio.run(evaluation.run())
|
498
|
+
except RuntimeError:
|
479
499
|
return asyncio.run(evaluation.run())
|
@@ -50,6 +50,7 @@ from .types import (
|
|
50
50
|
class Laminar:
|
51
51
|
__project_api_key: Optional[str] = None
|
52
52
|
__initialized: bool = False
|
53
|
+
__base_http_url: Optional[str] = None
|
53
54
|
|
54
55
|
@classmethod
|
55
56
|
def initialize(
|
@@ -133,6 +134,7 @@ class Laminar:
|
|
133
134
|
cls.__logger.info(f"Using HTTP port passed as an argument: {http_port}")
|
134
135
|
|
135
136
|
cls.__initialized = True
|
137
|
+
cls.__base_http_url = f"{url}:{http_port or 443}"
|
136
138
|
|
137
139
|
if not os.getenv("OTEL_ATTRIBUTE_COUNT_LIMIT"):
|
138
140
|
# each message is at least 2 attributes: role and content,
|
@@ -700,6 +702,14 @@ class Laminar:
|
|
700
702
|
props.pop("user_id", None)
|
701
703
|
set_association_properties(props)
|
702
704
|
|
705
|
+
@classmethod
|
706
|
+
def get_base_http_url(cls):
|
707
|
+
return cls.__base_http_url
|
708
|
+
|
709
|
+
@classmethod
|
710
|
+
def get_project_api_key(cls):
|
711
|
+
return cls.__project_api_key
|
712
|
+
|
703
713
|
@classmethod
|
704
714
|
def _headers(cls):
|
705
715
|
assert cls.__project_api_key is not None, "Project API key is not set"
|
@@ -66,6 +66,7 @@ class PartialEvaluationDatapoint(pydantic.BaseModel):
|
|
66
66
|
index: int
|
67
67
|
trace_id: uuid.UUID
|
68
68
|
executor_span_id: uuid.UUID
|
69
|
+
metadata: EvaluationDatapointMetadata = pydantic.Field(default=None)
|
69
70
|
|
70
71
|
# uuid is not serializable by default, so we need to convert it to a string
|
71
72
|
def to_dict(self):
|
@@ -77,6 +78,7 @@ class PartialEvaluationDatapoint(pydantic.BaseModel):
|
|
77
78
|
"index": self.index,
|
78
79
|
"traceId": str(self.trace_id),
|
79
80
|
"executorSpanId": str(self.executor_span_id),
|
81
|
+
"metadata": serialize(self.metadata) if self.metadata is not None else None,
|
80
82
|
}
|
81
83
|
except Exception as e:
|
82
84
|
raise ValueError(f"Error serializing PartialEvaluationDatapoint: {e}")
|
@@ -92,6 +94,7 @@ class EvaluationResultDatapoint(pydantic.BaseModel):
|
|
92
94
|
human_evaluators: list[HumanEvaluator] = pydantic.Field(default_factory=list)
|
93
95
|
trace_id: uuid.UUID
|
94
96
|
executor_span_id: uuid.UUID
|
97
|
+
metadata: EvaluationDatapointMetadata = pydantic.Field(default=None)
|
95
98
|
|
96
99
|
# uuid is not serializable by default, so we need to convert it to a string
|
97
100
|
def to_dict(self):
|
@@ -115,6 +118,7 @@ class EvaluationResultDatapoint(pydantic.BaseModel):
|
|
115
118
|
],
|
116
119
|
"executorSpanId": str(self.executor_span_id),
|
117
120
|
"index": self.index,
|
121
|
+
"metadata": serialize(self.metadata) if self.metadata is not None else None,
|
118
122
|
}
|
119
123
|
except Exception as e:
|
120
124
|
raise ValueError(f"Error serializing EvaluationResultDatapoint: {e}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|