Skip to content

Commit 1413f43

Browse files
authored
Update _record_feedback (#997)
1 parent f906b1d commit 1413f43

File tree

2 files changed

+55
-34
lines changed

2 files changed

+55
-34
lines changed

logfire/experimental/annotations.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,39 +44,38 @@ def raw_annotate_span(traceparent: str, span_name: str, message: str, attributes
4444
)
4545

4646

47-
def _record_feedback( # type: ignore
47+
def record_feedback(
4848
traceparent: str,
4949
name: str,
5050
value: int | float | bool | str,
5151
comment: str | None = None,
52-
extra_attributes: dict[str, Any] | None = None,
53-
) -> None: # pragma: no cover # TODO
54-
"""VERY WIP, DO NOT USE.
52+
extra: dict[str, Any] | None = None,
53+
) -> None:
54+
"""Attach feedback to a span.
5555
56-
Evaluate a span with a given value and reason.
56+
This is a more structured version of `raw_annotate_span`
57+
with special attributes recognized by the Logfire UI.
5758
5859
Args:
5960
traceparent: The traceparent string.
6061
name: The name of the evaluation.
6162
value: The value of the evaluation.
6263
Numbers are interpreted as scores, strings as labels, and booleans as assertions.
6364
comment: An optional reason for the evaluation.
64-
extra_attributes: Optional additional attributes to include in the span.
65+
extra: Optional additional attributes to include in the span.
6566
"""
66-
attributes: dict[str, Any] = {'feedback.name': name}
67+
attributes: dict[str, Any] = {'logfire.feedback.name': name, name: value}
6768

68-
if isinstance(value, bool):
69-
attributes['feedback.assertion'] = value
70-
elif isinstance(value, (int, float)):
71-
attributes['feedback.score'] = value
72-
else:
73-
assert isinstance(value, str), f'Value must be a string, int, float, or bool, not {type(value)}'
74-
attributes['feedback.label'] = value
69+
if extra:
70+
assert name not in extra # TODO check better
71+
attributes.update(extra)
7572

7673
if comment:
77-
attributes['feedback.comment'] = comment
78-
79-
if extra_attributes:
80-
attributes.update(extra_attributes)
81-
82-
raw_annotate_span(traceparent, 'feedback', f'feedback: {name}={value}', attributes)
74+
attributes['logfire.feedback.comment'] = comment
75+
76+
raw_annotate_span(
77+
traceparent,
78+
f'feedback: {name}',
79+
f'feedback: {name} = {value!r}',
80+
attributes,
81+
)

tests/test_annotations.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33

44
import logfire
55
from logfire._internal.exporters.test import TestExporter
6-
from logfire.experimental.annotations import (
7-
_record_feedback, # type: ignore
8-
get_traceparent,
9-
raw_annotate_span,
10-
)
6+
from logfire.experimental.annotations import get_traceparent, raw_annotate_span, record_feedback
117

128

139
def test_get_traceparent(exporter: TestExporter):
@@ -21,12 +17,18 @@ def test_get_traceparent(exporter: TestExporter):
2117

2218
raw_annotate_span(traceparent, 'my_span_name', 'my_message', {'key': 'value'})
2319

24-
_record_feedback(
20+
record_feedback(
2521
traceparent,
2622
'factuality',
2723
0.1,
2824
comment='the mock agent lied',
29-
extra_attributes={'agent_name': 'mock'},
25+
extra={'agent_name': 'mock'},
26+
)
27+
28+
record_feedback(
29+
traceparent,
30+
'rudeness',
31+
'very',
3032
)
3133

3234
assert exporter.exported_spans_as_dict(_include_pending_spans=True) == snapshot(
@@ -82,25 +84,45 @@ def test_get_traceparent(exporter: TestExporter):
8284
},
8385
},
8486
{
85-
'name': 'feedback',
87+
'name': 'feedback: factuality',
8688
'context': {'trace_id': 1, 'span_id': 4, 'is_remote': False},
8789
'parent': {'trace_id': 1, 'span_id': 1, 'is_remote': True},
8890
'start_time': 4000000000,
8991
'end_time': 4000000000,
9092
'attributes': {
9193
'logfire.span_type': 'annotation',
9294
'logfire.level_num': 9,
93-
'logfire.msg_template': 'feedback',
94-
'logfire.msg': 'feedback: factuality=0.1',
95+
'logfire.msg_template': 'feedback: factuality',
96+
'logfire.msg': 'feedback: factuality = 0.1',
9597
'code.filepath': 'test_annotations.py',
9698
'code.function': 'test_get_traceparent',
9799
'code.lineno': 123,
98-
'feedback.name': 'factuality',
99-
'feedback.score': 0.1,
100-
'feedback.comment': 'the mock agent lied',
100+
'logfire.feedback.name': 'factuality',
101+
'factuality': 0.1,
102+
'logfire.feedback.comment': 'the mock agent lied',
101103
'agent_name': 'mock',
102104
'logfire.disable_console_log': True,
103-
'logfire.json_schema': '{"type":"object","properties":{"feedback.name":{},"feedback.score":{},"feedback.comment":{},"agent_name":{},"logfire.span_type":{},"logfire.disable_console_log":{}}}',
105+
'logfire.json_schema': '{"type":"object","properties":{"logfire.feedback.name":{},"factuality":{},"agent_name":{},"logfire.feedback.comment":{},"logfire.span_type":{},"logfire.disable_console_log":{}}}',
106+
},
107+
},
108+
{
109+
'name': 'feedback: rudeness',
110+
'context': {'trace_id': 1, 'span_id': 5, 'is_remote': False},
111+
'parent': {'trace_id': 1, 'span_id': 1, 'is_remote': True},
112+
'start_time': 5000000000,
113+
'end_time': 5000000000,
114+
'attributes': {
115+
'logfire.span_type': 'annotation',
116+
'logfire.level_num': 9,
117+
'logfire.msg_template': 'feedback: rudeness',
118+
'logfire.msg': "feedback: rudeness = 'very'",
119+
'code.filepath': 'test_annotations.py',
120+
'code.function': 'test_get_traceparent',
121+
'code.lineno': 123,
122+
'logfire.feedback.name': 'rudeness',
123+
'rudeness': 'very',
124+
'logfire.disable_console_log': True,
125+
'logfire.json_schema': '{"type":"object","properties":{"logfire.feedback.name":{},"rudeness":{},"logfire.span_type":{},"logfire.disable_console_log":{}}}',
104126
},
105127
},
106128
]

0 commit comments

Comments
 (0)