braintrust 0.4.2__py3-none-any.whl → 0.4.3__py3-none-any.whl
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.
- braintrust/_generated_types.py +224 -122
- braintrust/cli/install/api.py +1 -1
- braintrust/conftest.py +24 -0
- braintrust/devserver/test_server_integration.py +0 -11
- braintrust/functions/invoke.py +1 -8
- braintrust/generated_types.py +7 -7
- braintrust/logger.py +30 -35
- braintrust/prompt_cache/test_disk_cache.py +3 -3
- braintrust/span_types.py +3 -0
- braintrust/test_bt_json.py +23 -19
- braintrust/version.py +2 -2
- braintrust/wrappers/langsmith_wrapper.py +517 -0
- braintrust/wrappers/test_agno.py +0 -12
- braintrust/wrappers/test_anthropic.py +1 -11
- braintrust/wrappers/test_dspy.py +0 -11
- braintrust/wrappers/test_google_genai.py +6 -1
- braintrust/wrappers/test_langsmith_wrapper.py +338 -0
- braintrust/wrappers/test_litellm.py +0 -10
- braintrust/wrappers/test_oai_attachments.py +0 -10
- braintrust/wrappers/test_openai.py +3 -12
- braintrust/wrappers/test_openrouter.py +0 -9
- braintrust/wrappers/test_pydantic_ai_integration.py +0 -11
- braintrust/wrappers/test_pydantic_ai_wrap_openai.py +2 -0
- {braintrust-0.4.2.dist-info → braintrust-0.4.3.dist-info}/METADATA +1 -1
- {braintrust-0.4.2.dist-info → braintrust-0.4.3.dist-info}/RECORD +28 -26
- {braintrust-0.4.2.dist-info → braintrust-0.4.3.dist-info}/WHEEL +0 -0
- {braintrust-0.4.2.dist-info → braintrust-0.4.3.dist-info}/entry_points.txt +0 -0
- {braintrust-0.4.2.dist-info → braintrust-0.4.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# pyright: reportPrivateUsage=false
|
|
2
|
+
# pyright: reportMissingParameterType=false
|
|
3
|
+
# pyright: reportUnknownParameterType=false
|
|
4
|
+
# pyright: reportUnknownArgumentType=false
|
|
5
|
+
# pyright: reportUnknownMemberType=false
|
|
6
|
+
# pylint: disable=protected-access
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
Tests for the LangSmith wrapper to ensure compatibility with LangSmith's API.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
from braintrust.wrappers.langsmith_wrapper import (
|
|
14
|
+
_convert_langsmith_data,
|
|
15
|
+
_is_patched,
|
|
16
|
+
_make_braintrust_scorer,
|
|
17
|
+
_make_braintrust_task,
|
|
18
|
+
wrap_aevaluate,
|
|
19
|
+
wrap_client,
|
|
20
|
+
wrap_traceable,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_is_patched_false():
|
|
25
|
+
"""Test that _is_patched returns False for unpatched objects."""
|
|
26
|
+
|
|
27
|
+
def unpatched():
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
assert _is_patched(unpatched) is False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_is_patched_true():
|
|
34
|
+
"""Test that _is_patched returns True for patched objects."""
|
|
35
|
+
|
|
36
|
+
def patched():
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
patched._braintrust_patched = True # type: ignore
|
|
40
|
+
|
|
41
|
+
assert _is_patched(patched) is True
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_make_braintrust_scorer_dict_result():
|
|
45
|
+
"""Test converting a LangSmith evaluator that returns a dict."""
|
|
46
|
+
|
|
47
|
+
def langsmith_evaluator(inputs, outputs, reference_outputs):
|
|
48
|
+
return {"key": "accuracy", "score": 0.9, "metadata": {"note": "good"}}
|
|
49
|
+
|
|
50
|
+
converted = _make_braintrust_scorer(langsmith_evaluator)
|
|
51
|
+
|
|
52
|
+
# Create a mock Example object
|
|
53
|
+
class MockExample:
|
|
54
|
+
outputs = {"y": 2}
|
|
55
|
+
|
|
56
|
+
result = converted(input={"x": 1}, output={"y": 2}, expected=MockExample())
|
|
57
|
+
|
|
58
|
+
assert result.name == "accuracy"
|
|
59
|
+
assert result.score == 0.9
|
|
60
|
+
assert result.metadata == {"note": "good"}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_make_braintrust_scorer_numeric_result():
|
|
64
|
+
"""Test converting a LangSmith evaluator that returns a numeric score in a dict."""
|
|
65
|
+
|
|
66
|
+
def langsmith_evaluator(inputs, outputs, reference_outputs):
|
|
67
|
+
return {"score": 1.0 if outputs == reference_outputs else 0.0}
|
|
68
|
+
|
|
69
|
+
converted = _make_braintrust_scorer(langsmith_evaluator)
|
|
70
|
+
|
|
71
|
+
class MockExample:
|
|
72
|
+
outputs = {"y": 2}
|
|
73
|
+
|
|
74
|
+
result = converted(input={"x": 1}, output={"y": 2}, expected=MockExample())
|
|
75
|
+
|
|
76
|
+
assert result.name == "langsmith_evaluator"
|
|
77
|
+
assert result.score == 1.0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_make_braintrust_scorer_with_plain_dict_expected():
|
|
81
|
+
"""Test converting a LangSmith evaluator with plain dict as expected."""
|
|
82
|
+
|
|
83
|
+
def langsmith_evaluator(inputs, outputs, reference_outputs):
|
|
84
|
+
return {"score": 1.0 if outputs == reference_outputs else 0.0}
|
|
85
|
+
|
|
86
|
+
converted = _make_braintrust_scorer(langsmith_evaluator)
|
|
87
|
+
result = converted(input={"x": 1}, output={"y": 2}, expected={"y": 2})
|
|
88
|
+
|
|
89
|
+
assert result.name == "langsmith_evaluator"
|
|
90
|
+
assert result.score == 1.0
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_convert_langsmith_data_from_list():
|
|
94
|
+
"""Test converting LangSmith data from a list of dicts."""
|
|
95
|
+
data = [
|
|
96
|
+
{"inputs": {"x": 1}, "outputs": {"y": 2}},
|
|
97
|
+
{"inputs": {"x": 2}, "outputs": {"y": 4}},
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
data_fn = _convert_langsmith_data(data)
|
|
101
|
+
result = list(data_fn())
|
|
102
|
+
|
|
103
|
+
assert len(result) == 2
|
|
104
|
+
assert result[0].input == {"x": 1}
|
|
105
|
+
# The whole item is passed as expected
|
|
106
|
+
assert result[0].expected == {"inputs": {"x": 1}, "outputs": {"y": 2}}
|
|
107
|
+
assert result[1].input == {"x": 2}
|
|
108
|
+
assert result[1].expected == {"inputs": {"x": 2}, "outputs": {"y": 4}}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_convert_langsmith_data_from_callable():
|
|
112
|
+
"""Test converting LangSmith data from a callable."""
|
|
113
|
+
|
|
114
|
+
def data_generator():
|
|
115
|
+
yield {"inputs": {"x": 1}, "outputs": {"y": 2}}
|
|
116
|
+
yield {"inputs": {"x": 2}, "outputs": {"y": 4}}
|
|
117
|
+
|
|
118
|
+
data_fn = _convert_langsmith_data(data_generator)
|
|
119
|
+
result = list(data_fn())
|
|
120
|
+
|
|
121
|
+
assert len(result) == 2
|
|
122
|
+
assert result[0].input == {"x": 1}
|
|
123
|
+
# The whole item is passed as expected
|
|
124
|
+
assert result[0].expected == {"inputs": {"x": 1}, "outputs": {"y": 2}}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_convert_langsmith_data_with_example_objects():
|
|
128
|
+
"""Test converting LangSmith data with Example-like objects."""
|
|
129
|
+
|
|
130
|
+
class MockExample:
|
|
131
|
+
def __init__(self, inputs, outputs):
|
|
132
|
+
self.inputs = inputs
|
|
133
|
+
self.outputs = outputs
|
|
134
|
+
|
|
135
|
+
data = [
|
|
136
|
+
MockExample(inputs={"x": 1}, outputs={"y": 2}),
|
|
137
|
+
MockExample(inputs={"x": 2}, outputs={"y": 4}),
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
data_fn = _convert_langsmith_data(data)
|
|
141
|
+
result = list(data_fn())
|
|
142
|
+
|
|
143
|
+
assert len(result) == 2
|
|
144
|
+
assert result[0].input == {"x": 1}
|
|
145
|
+
# The whole Example object is passed as expected
|
|
146
|
+
assert result[0].expected.inputs == {"x": 1}
|
|
147
|
+
assert result[0].expected.outputs == {"y": 2}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_make_braintrust_task_with_dict_input():
|
|
151
|
+
"""Test that task function handles dict inputs correctly."""
|
|
152
|
+
|
|
153
|
+
def target_fn(inputs):
|
|
154
|
+
return inputs["x"] * 2
|
|
155
|
+
|
|
156
|
+
task = _make_braintrust_task(target_fn)
|
|
157
|
+
result = task({"x": 5}, None)
|
|
158
|
+
|
|
159
|
+
assert result == 10
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_make_braintrust_task_with_kwargs_expansion():
|
|
163
|
+
"""Test that task function expands dict kwargs when signature matches."""
|
|
164
|
+
|
|
165
|
+
def target_fn(x, y):
|
|
166
|
+
return x + y
|
|
167
|
+
|
|
168
|
+
task = _make_braintrust_task(target_fn)
|
|
169
|
+
result = task({"x": 2, "y": 3}, None)
|
|
170
|
+
|
|
171
|
+
assert result == 5
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_make_braintrust_task_simple_input():
|
|
175
|
+
"""Test that task function handles simple inputs."""
|
|
176
|
+
|
|
177
|
+
def target_fn(inp):
|
|
178
|
+
return inp * 2
|
|
179
|
+
|
|
180
|
+
task = _make_braintrust_task(target_fn)
|
|
181
|
+
result = task(5, None)
|
|
182
|
+
|
|
183
|
+
assert result == 10
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class TestWrapTraceable:
|
|
187
|
+
"""Tests for wrap_traceable functionality."""
|
|
188
|
+
|
|
189
|
+
def test_wrap_traceable_returns_wrapper(self):
|
|
190
|
+
"""Test that wrap_traceable returns a wrapped version."""
|
|
191
|
+
|
|
192
|
+
def mock_traceable(func, **kwargs):
|
|
193
|
+
return func
|
|
194
|
+
|
|
195
|
+
wrapped = wrap_traceable(mock_traceable, standalone=False)
|
|
196
|
+
assert callable(wrapped)
|
|
197
|
+
assert _is_patched(wrapped)
|
|
198
|
+
|
|
199
|
+
def test_wrap_traceable_standalone_mode(self):
|
|
200
|
+
"""Test that wrap_traceable works in standalone mode."""
|
|
201
|
+
|
|
202
|
+
def mock_traceable(func, **kwargs):
|
|
203
|
+
return func
|
|
204
|
+
|
|
205
|
+
wrapped = wrap_traceable(mock_traceable, standalone=True)
|
|
206
|
+
assert callable(wrapped)
|
|
207
|
+
assert _is_patched(wrapped)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class TestWrapFunctions:
|
|
211
|
+
"""Tests for the wrap_* functions."""
|
|
212
|
+
|
|
213
|
+
def test_wrap_functions_exist(self):
|
|
214
|
+
"""Test that wrap functions are callable."""
|
|
215
|
+
assert callable(wrap_traceable)
|
|
216
|
+
assert callable(wrap_client)
|
|
217
|
+
assert callable(wrap_aevaluate)
|
|
218
|
+
|
|
219
|
+
def test_wrap_traceable_returns_patched_function(self):
|
|
220
|
+
"""Test that wrap_traceable returns a patched function."""
|
|
221
|
+
|
|
222
|
+
def mock_traceable(func, **kwargs):
|
|
223
|
+
return func
|
|
224
|
+
|
|
225
|
+
wrapped = wrap_traceable(mock_traceable)
|
|
226
|
+
assert _is_patched(wrapped)
|
|
227
|
+
|
|
228
|
+
def test_wrap_traceable_skips_if_already_patched(self):
|
|
229
|
+
"""Test that wrap_traceable skips if already patched."""
|
|
230
|
+
|
|
231
|
+
def mock_traceable(func, **kwargs):
|
|
232
|
+
return func
|
|
233
|
+
|
|
234
|
+
mock_traceable._braintrust_patched = True # type: ignore
|
|
235
|
+
|
|
236
|
+
result = wrap_traceable(mock_traceable)
|
|
237
|
+
# Should return the same function
|
|
238
|
+
assert result is mock_traceable
|
|
239
|
+
|
|
240
|
+
def test_wrap_client_sets_flag(self):
|
|
241
|
+
"""Test that wrap_client sets the patched flag."""
|
|
242
|
+
|
|
243
|
+
class MockClient:
|
|
244
|
+
def evaluate(self, *args, **kwargs):
|
|
245
|
+
return "original"
|
|
246
|
+
|
|
247
|
+
wrap_client(MockClient)
|
|
248
|
+
assert _is_patched(MockClient.evaluate)
|
|
249
|
+
|
|
250
|
+
def test_wrap_aevaluate_returns_patched_function(self):
|
|
251
|
+
"""Test that wrap_aevaluate returns a patched function."""
|
|
252
|
+
|
|
253
|
+
async def mock_aevaluate(*args, **kwargs):
|
|
254
|
+
pass
|
|
255
|
+
|
|
256
|
+
wrapped = wrap_aevaluate(mock_aevaluate)
|
|
257
|
+
assert _is_patched(wrapped)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class TestTandemModeIntegration:
|
|
261
|
+
"""Integration tests for tandem mode (LangSmith + Braintrust together)."""
|
|
262
|
+
|
|
263
|
+
def test_make_braintrust_task_with_inputs_parameter(self):
|
|
264
|
+
"""Test that task handles LangSmith's required 'inputs' parameter name."""
|
|
265
|
+
|
|
266
|
+
def target_fn(inputs: dict) -> dict:
|
|
267
|
+
return {"result": inputs["x"] * 2}
|
|
268
|
+
|
|
269
|
+
task = _make_braintrust_task(target_fn)
|
|
270
|
+
result = task({"x": 5}, None)
|
|
271
|
+
|
|
272
|
+
assert result == {"result": 10}
|
|
273
|
+
|
|
274
|
+
def test_convert_langsmith_data_handles_different_output_types(self):
|
|
275
|
+
"""Test that data conversion handles various output types."""
|
|
276
|
+
data = [
|
|
277
|
+
{"inputs": {"x": 1}, "outputs": 2}, # outputs is int, not dict
|
|
278
|
+
{"inputs": {"x": 2}, "outputs": {"result": 4}}, # outputs is already dict
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
data_fn = _convert_langsmith_data(data)
|
|
282
|
+
result = list(data_fn())
|
|
283
|
+
|
|
284
|
+
# Both should work - Braintrust's EvalCase accepts any type for expected
|
|
285
|
+
assert len(result) == 2
|
|
286
|
+
assert result[0].input == {"x": 1}
|
|
287
|
+
assert result[1].input == {"x": 2}
|
|
288
|
+
|
|
289
|
+
def test_make_braintrust_scorer_handles_wrapped_outputs(self):
|
|
290
|
+
"""Test that scorers handle output wrapping correctly."""
|
|
291
|
+
|
|
292
|
+
def langsmith_evaluator(inputs, outputs, reference_outputs):
|
|
293
|
+
# outputs will be wrapped as {"output": value} for non-dict results
|
|
294
|
+
actual = outputs.get("output", outputs)
|
|
295
|
+
expected = reference_outputs.get("output", reference_outputs) if isinstance(reference_outputs, dict) else reference_outputs
|
|
296
|
+
return {"key": "match", "score": 1.0 if actual == expected else 0.0}
|
|
297
|
+
|
|
298
|
+
converted = _make_braintrust_scorer(langsmith_evaluator)
|
|
299
|
+
|
|
300
|
+
class MockExample:
|
|
301
|
+
outputs = {"output": 42}
|
|
302
|
+
|
|
303
|
+
# Test with wrapped output
|
|
304
|
+
result = converted(input={"x": 1}, output=42, expected=MockExample())
|
|
305
|
+
assert result.name == "match"
|
|
306
|
+
assert result.score == 1.0
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class TestDataConversion:
|
|
310
|
+
"""Tests for data conversion utilities."""
|
|
311
|
+
|
|
312
|
+
def test_convert_data_with_braintrust_format(self):
|
|
313
|
+
"""Test that Braintrust format is properly handled."""
|
|
314
|
+
data = [
|
|
315
|
+
{"input": {"x": 1}, "expected": {"y": 2}},
|
|
316
|
+
{"input": {"x": 2}, "expected": {"y": 4}},
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
data_fn = _convert_langsmith_data(data)
|
|
320
|
+
result = list(data_fn())
|
|
321
|
+
|
|
322
|
+
assert len(result) == 2
|
|
323
|
+
assert result[0].input == {"x": 1}
|
|
324
|
+
assert result[0].expected == {"y": 2}
|
|
325
|
+
assert result[1].input == {"x": 2}
|
|
326
|
+
assert result[1].expected == {"y": 4}
|
|
327
|
+
|
|
328
|
+
def test_convert_data_with_simple_items(self):
|
|
329
|
+
"""Test that simple items (not dicts) are handled."""
|
|
330
|
+
data = [1, 2, 3]
|
|
331
|
+
|
|
332
|
+
data_fn = _convert_langsmith_data(data)
|
|
333
|
+
result = list(data_fn())
|
|
334
|
+
|
|
335
|
+
assert len(result) == 3
|
|
336
|
+
assert result[0].input == 1
|
|
337
|
+
assert result[1].input == 2
|
|
338
|
+
assert result[2].input == 3
|
|
@@ -15,16 +15,6 @@ TEST_PROMPT = "What's 12 + 12?"
|
|
|
15
15
|
TEST_SYSTEM_PROMPT = "You are a helpful assistant that only responds with numbers."
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
@pytest.fixture(scope="module")
|
|
19
|
-
def vcr_config():
|
|
20
|
-
return {
|
|
21
|
-
"filter_headers": [
|
|
22
|
-
"authorization",
|
|
23
|
-
"openai-organization",
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
18
|
@pytest.fixture
|
|
29
19
|
def memory_logger():
|
|
30
20
|
init_test_logger(PROJECT_NAME)
|
|
@@ -11,16 +11,6 @@ PROJECT_NAME = "test-project-openai-attachment-processing"
|
|
|
11
11
|
TEST_MODEL = "gpt-4o-mini"
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
@pytest.fixture(scope="module")
|
|
15
|
-
def vcr_config():
|
|
16
|
-
return {
|
|
17
|
-
"filter_headers": [
|
|
18
|
-
"authorization",
|
|
19
|
-
"openai-organization",
|
|
20
|
-
]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
14
|
@pytest.fixture
|
|
25
15
|
def memory_logger():
|
|
26
16
|
init_test_logger(PROJECT_NAME)
|
|
@@ -18,16 +18,6 @@ TEST_PROMPT = "What's 12 + 12?"
|
|
|
18
18
|
TEST_SYSTEM_PROMPT = "You are a helpful assistant that only responds with numbers."
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
@pytest.fixture(scope="module")
|
|
22
|
-
def vcr_config():
|
|
23
|
-
return {
|
|
24
|
-
"filter_headers": [
|
|
25
|
-
"authorization",
|
|
26
|
-
"openai-organization",
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
21
|
@pytest.fixture
|
|
32
22
|
def memory_logger():
|
|
33
23
|
init_test_logger(PROJECT_NAME)
|
|
@@ -943,8 +933,6 @@ async def test_openai_streaming_with_break(memory_logger):
|
|
|
943
933
|
model=TEST_MODEL, messages=[{"role": "user", "content": TEST_PROMPT}], stream=True
|
|
944
934
|
)
|
|
945
935
|
|
|
946
|
-
time.sleep(0.2) # time to first token sleep
|
|
947
|
-
|
|
948
936
|
# Only process the first few chunks
|
|
949
937
|
counter = 0
|
|
950
938
|
async for chunk in stream:
|
|
@@ -1331,6 +1319,7 @@ def _is_wrapped(client):
|
|
|
1331
1319
|
|
|
1332
1320
|
|
|
1333
1321
|
@pytest.mark.asyncio
|
|
1322
|
+
@pytest.mark.vcr
|
|
1334
1323
|
async def test_braintrust_tracing_processor_current_span_detection(memory_logger):
|
|
1335
1324
|
"""Test that BraintrustTracingProcessor currentSpan() detection works with OpenAI Agents SDK."""
|
|
1336
1325
|
pytest.importorskip("agents", reason="agents package not available")
|
|
@@ -1440,6 +1429,7 @@ async def test_braintrust_tracing_processor_current_span_detection(memory_logger
|
|
|
1440
1429
|
|
|
1441
1430
|
|
|
1442
1431
|
@pytest.mark.asyncio
|
|
1432
|
+
@pytest.mark.vcr
|
|
1443
1433
|
async def test_braintrust_tracing_processor_concurrency_bug(memory_logger):
|
|
1444
1434
|
"""Test that reproduces the concurrency bug where overlapping traces mix up first_input/last_output."""
|
|
1445
1435
|
pytest.importorskip("agents", reason="agents package not available")
|
|
@@ -1546,6 +1536,7 @@ async def test_braintrust_tracing_processor_concurrency_bug(memory_logger):
|
|
|
1546
1536
|
|
|
1547
1537
|
|
|
1548
1538
|
@pytest.mark.asyncio
|
|
1539
|
+
@pytest.mark.vcr
|
|
1549
1540
|
async def test_agents_tool_openai_nested_spans(memory_logger):
|
|
1550
1541
|
"""Test that OpenAI calls inside agent tools are properly nested under the tool span."""
|
|
1551
1542
|
pytest.importorskip("agents", reason="agents package not available")
|
|
@@ -19,15 +19,6 @@ PROJECT_NAME = "test-openrouter"
|
|
|
19
19
|
TEST_MODEL = "openai/gpt-4o-mini"
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
@pytest.fixture(scope="module")
|
|
23
|
-
def vcr_config():
|
|
24
|
-
return {
|
|
25
|
-
"filter_headers": [
|
|
26
|
-
"authorization",
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
22
|
@pytest.fixture
|
|
32
23
|
def memory_logger():
|
|
33
24
|
init_test_logger(PROJECT_NAME)
|
|
@@ -32,17 +32,6 @@ def direct():
|
|
|
32
32
|
return direct_module
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
@pytest.fixture(scope="module")
|
|
36
|
-
def vcr_config():
|
|
37
|
-
return {
|
|
38
|
-
"filter_headers": [
|
|
39
|
-
"authorization",
|
|
40
|
-
"openai-organization",
|
|
41
|
-
"x-api-key",
|
|
42
|
-
]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
35
|
@pytest.fixture
|
|
47
36
|
def memory_logger():
|
|
48
37
|
init_test_logger(PROJECT_NAME)
|
|
@@ -66,6 +66,7 @@ def _assert_metrics_are_valid(metrics: Dict[str, Any]):
|
|
|
66
66
|
assert "time_to_first_token" in metrics
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
@pytest.mark.vcr
|
|
69
70
|
@pytest.mark.asyncio
|
|
70
71
|
async def test_pydantic_wrapped_stream(memory_logger):
|
|
71
72
|
"""Test that Pydantic AI streaming operations work with Braintrust wrapping."""
|
|
@@ -108,6 +109,7 @@ async def test_pydantic_wrapped_stream(memory_logger):
|
|
|
108
109
|
assert span["root_span_id"]
|
|
109
110
|
|
|
110
111
|
|
|
112
|
+
@pytest.mark.vcr
|
|
111
113
|
@pytest.mark.asyncio
|
|
112
114
|
async def test_pydantic_wrapped_completion(memory_logger):
|
|
113
115
|
"""Test that Pydantic AI completion operations work with Braintrust wrapping."""
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
braintrust/__init__.py,sha256=sw6dLIINeyUVP4IbF49wqXv2cyAWEoO3SGSIvCb_b2o,2238
|
|
2
|
-
braintrust/_generated_types.py,sha256=
|
|
2
|
+
braintrust/_generated_types.py,sha256=kZs5K7dglu5S-NYztq0RO-uM5Z-Ng-8qHzebYNzStVg,96835
|
|
3
3
|
braintrust/audit.py,sha256=3GQKzuTcFquYdrJtABM-k3xMlOIqgVkfG6UyeQ8_028,461
|
|
4
4
|
braintrust/aws.py,sha256=OBz_SRyopgpCDSNvETLypzGwTXk-bNLn-Eisevnjfwo,377
|
|
5
5
|
braintrust/bt_json.py,sha256=VNunedFUEfbvVEBuACHLRsjDr8lLD3_nFwB54MXtcbY,9385
|
|
6
|
-
braintrust/conftest.py,sha256=
|
|
6
|
+
braintrust/conftest.py,sha256=cmuwhK0BvqZ6yGqD_3x_JJmWkCtaSOwfSKz6n8ZT5Ug,2339
|
|
7
7
|
braintrust/context.py,sha256=bOo1Li29lUsi2DOOllIDar0oRuQNbkLNzJ7cYq5JTbo,4126
|
|
8
8
|
braintrust/db_fields.py,sha256=vjVEyDxl2d13lvvTcVwT5paHvaT-1kgI-4Lg-gihRIw,476
|
|
9
9
|
braintrust/framework.py,sha256=U2ubFkX6LS-3iArMT4sRG17oZa0ClM4GVpC0O8xotxQ,57593
|
|
10
10
|
braintrust/framework2.py,sha256=o0igz4vXbmn0jHJPhDYvx14rFnI3ntV8H6VJfyJYRtM,16542
|
|
11
|
-
braintrust/generated_types.py,sha256=
|
|
11
|
+
braintrust/generated_types.py,sha256=rzGVd_yajhEXZ-MME3ZWB7UCRvdVx2oANvxDcjKoZA4,4849
|
|
12
12
|
braintrust/git_fields.py,sha256=au5ayyuvt7y_ojE9LC98ypTZd3RgFdjhRc8eFxcjnto,1434
|
|
13
13
|
braintrust/gitutil.py,sha256=RsW7cawJMgaAaTw6WeB1sShyfflkPb7yH2x7yuRv10c,5642
|
|
14
14
|
braintrust/graph_util.py,sha256=Z2Uy8RaOq5iMe5mShhQqRDDIpXVitE-biVxDiFB-0Ds,5545
|
|
15
15
|
braintrust/http_headers.py,sha256=9ZsDcsAKG04SGowsgchZktD6rG_oSTKWa8QyGUPA4xE,154
|
|
16
16
|
braintrust/id_gen.py,sha256=4UWLWRhksf76IkYi4cKACSaQ3yNgausrMRlhiurhy74,1590
|
|
17
|
-
braintrust/logger.py,sha256=
|
|
17
|
+
braintrust/logger.py,sha256=_kpQni3_TTjnz1bcGJphwe_0xPcAuwxQDsccur6G5Z0,205378
|
|
18
18
|
braintrust/merge_row_batch.py,sha256=tvuz3qdsa7HZBrzzAzoQqAXU7pKsHUebC7sw6RybbmA,9881
|
|
19
19
|
braintrust/oai.py,sha256=AjHeD0uNYO-ECVUh9RbPBxyKMps06A3dvHAWa41prMc,36259
|
|
20
20
|
braintrust/object.py,sha256=vYLyYWncsqLD00zffZUJwGTSkcJF9IIXmgIzrx3Np5c,632
|
|
@@ -29,8 +29,8 @@ braintrust/span_identifier_v1.py,sha256=eR-dHda0MurdOlghv7-CLSh7eVpNQigbDSQxPpLC
|
|
|
29
29
|
braintrust/span_identifier_v2.py,sha256=2dLc-Vz8iWLISmL_-ebCyWnY-ysA7sMnBsQtKqzMHYY,8981
|
|
30
30
|
braintrust/span_identifier_v3.py,sha256=l_W8amV0u89X-cHqIhWQdjLZcoeWhwJoAEdYWgCN1nM,9720
|
|
31
31
|
braintrust/span_identifier_v4.py,sha256=uFT-OdzySo4uCeAaJC3VqH55Oy433xZGBdK2hiEsm2w,10044
|
|
32
|
-
braintrust/span_types.py,sha256=
|
|
33
|
-
braintrust/test_bt_json.py,sha256=
|
|
32
|
+
braintrust/span_types.py,sha256=cpTzCwUj4yBPbPLnzR23-VXIU2E9nl_dsVCSVMvtSkc,376
|
|
33
|
+
braintrust/test_bt_json.py,sha256=p4r5DlMkH2rRQbYT9X1ASPbKVEMku5bFUUa7hVAO-ZY,25259
|
|
34
34
|
braintrust/test_framework.py,sha256=7spRLovwNjZLula8mNW_KspyWuWgpqSfHV6sZqub-ME,17664
|
|
35
35
|
braintrust/test_framework2.py,sha256=pSEEmBIyszAiYnpEVvDZgJqIe3lQ3T807LmIuBqV98w,7235
|
|
36
36
|
braintrust/test_helpers.py,sha256=VSelzjkR2IHyy5QD6sYB_79VIXq-wEDslDwyx9H11kI,13528
|
|
@@ -44,14 +44,14 @@ braintrust/test_span_components.py,sha256=6w0oDnDLuVbHygNienujk4JDqtSRR5A49AI-S8
|
|
|
44
44
|
braintrust/test_util.py,sha256=xMN84ERVzZYUTAOp0IkFK-ktWOLK4rr6OdhaNeq7Fg0,6382
|
|
45
45
|
braintrust/test_version.py,sha256=hk5JKjEFbNJ_ONc1VEkqHquflzre34RpFhCEYLTK8iA,1051
|
|
46
46
|
braintrust/util.py,sha256=-q73F17BkaUaDCGtNBTtacqIPwWiXcgWYpzHqFTQdhc,8361
|
|
47
|
-
braintrust/version.py,sha256=
|
|
47
|
+
braintrust/version.py,sha256=xijckaJ6-1Mn0R0hTRi55lSGRv3JudT78ygiljJCeaU,117
|
|
48
48
|
braintrust/xact_ids.py,sha256=bdyp88HjlyIkglgLSqYlCYscdSH6EWVyE14sR90Xl1s,658
|
|
49
49
|
braintrust/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
50
|
braintrust/cli/__main__.py,sha256=wCBKHGVmn3IT_yMXk5qfDwyI2SV2gf1tLr0NTxm9T8k,1519
|
|
51
51
|
braintrust/cli/eval.py,sha256=ymnCVkZ6mefDBDHO1wqd0IPtBjib-vW_4OTZRWh8sbE,13246
|
|
52
52
|
braintrust/cli/push.py,sha256=vUbKirxpiaCDYkFx3mskexaFWhczS4eIXKUDZPo5P9s,12423
|
|
53
53
|
braintrust/cli/install/__init__.py,sha256=scF_YM4dZJ47kT6VlM2CgM9jrEzqEHqPxS88nyVAsfk,1331
|
|
54
|
-
braintrust/cli/install/api.py,sha256
|
|
54
|
+
braintrust/cli/install/api.py,sha256=--wjZ0kV9s6TD_OYqljNGYYuLo1u17zRnG7vZ5I-WuE,18528
|
|
55
55
|
braintrust/cli/install/bump_versions.py,sha256=Wcn6tAXTVz6RcCUg87xxxA-VUeUE8MTSQpOdjQJSz6k,1691
|
|
56
56
|
braintrust/cli/install/logs.py,sha256=XROIpFp-KS1as1sqZBYwbCF4HogoPV2-m9yBooUjGFI,3740
|
|
57
57
|
braintrust/cli/install/redshift.py,sha256=MsjN4MW_us_KTWy_YMRK3G5-2Gxd65L2SgI3uO7g-uw,6857
|
|
@@ -69,10 +69,10 @@ braintrust/devserver/schemas.py,sha256=Nwms8IzGyo60G5Az0IqZnCbqPmHUzublZvwT3IwcG
|
|
|
69
69
|
braintrust/devserver/server.py,sha256=352s7kWxMljs2BcQoCu8rRuBFKek68uHdV5XHt87x2c,12626
|
|
70
70
|
braintrust/devserver/test_cached_login.py,sha256=-khNsDAuHrO7N-Rt1orIAE_kxTBjfmIGTVyXmw2p6IU,3741
|
|
71
71
|
braintrust/devserver/test_lru_cache.py,sha256=5YYJ5uFj7k4Z4PQQ-UOV7bLP5zBYVo-5jV5_hpthtgM,4164
|
|
72
|
-
braintrust/devserver/test_server_integration.py,sha256=
|
|
72
|
+
braintrust/devserver/test_server_integration.py,sha256=7QhanUNsx7MYdhEL9AOr_ZrQJdSVIN1IorZ_JvIJq5Y,6485
|
|
73
73
|
braintrust/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
74
|
braintrust/functions/constants.py,sha256=g_EDiSrfCltHr5QaQMQzJ3qy3D29X-11LanDqlicqB0,23
|
|
75
|
-
braintrust/functions/invoke.py,sha256=
|
|
75
|
+
braintrust/functions/invoke.py,sha256=5lmCUZ4_FPAVOelHuvMmIMQTQXYaqxYeaymptEs69n8,9731
|
|
76
76
|
braintrust/functions/stream.py,sha256=zH3okhkbUBE3-iYD6edLqjDdewc1Zj1MjVx5A3Xwe9Y,6103
|
|
77
77
|
braintrust/otel/__init__.py,sha256=sZxGs2khKfL9uFJtB118VJJ7O5QOZJSG3vuKUFB0fiE,24350
|
|
78
78
|
braintrust/otel/context.py,sha256=EpGk3B1UeAfBeqDe-yYy4LNNCFBKU6aU-0tfVOMrkcs,4611
|
|
@@ -82,7 +82,7 @@ braintrust/prompt_cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
|
82
82
|
braintrust/prompt_cache/disk_cache.py,sha256=RH20RwKR1lkGMYtMs6oVht6EdBHT0vokq3Z8iOd4jgk,5643
|
|
83
83
|
braintrust/prompt_cache/lru_cache.py,sha256=us4jyznEeScEUDLXfDyaYY6gSUmUba55Kg-P6fBrtm8,2509
|
|
84
84
|
braintrust/prompt_cache/prompt_cache.py,sha256=2eA5lc5_5gYJEccA8fFGJD8a4Y10oBZ12NFIt-D0H9g,4834
|
|
85
|
-
braintrust/prompt_cache/test_disk_cache.py,sha256=
|
|
85
|
+
braintrust/prompt_cache/test_disk_cache.py,sha256=szmHQnIa5Rn2CouP9t5CmI6-D48BiX3Dktm6X2WRuWY,7522
|
|
86
86
|
braintrust/prompt_cache/test_lru_cache.py,sha256=4NNIXSfYBtOma7KYum74UdeM83eYmcXSOeiNpuKYpwI,2342
|
|
87
87
|
braintrust/prompt_cache/test_prompt_cache.py,sha256=x17Ru9eaix8jt6yMhRgEljD2vVe7ieA8uKhk3bszgSM,8447
|
|
88
88
|
braintrust/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -90,19 +90,21 @@ braintrust/wrappers/_anthropic_utils.py,sha256=tOj_rv5NVRXpCij0F3NPxOZg0XGAAXo8Y
|
|
|
90
90
|
braintrust/wrappers/anthropic.py,sha256=sh0UbSWDarU5glic4HIUXNZmMcfn3Odau2K8HzaOIWY,11785
|
|
91
91
|
braintrust/wrappers/dspy.py,sha256=ckPcMHpbVZP6k4R60ZbgegWz82lsK3lu2u9nvN0EIss,13516
|
|
92
92
|
braintrust/wrappers/langchain.py,sha256=0aY5LuVA7BPkgWA0N6CwPG9EaPqRmVVfEPaM1kN4XZY,5028
|
|
93
|
+
braintrust/wrappers/langsmith_wrapper.py,sha256=mWhBnY6KypOlSQw4NrCwzif0Oe6SHV6LYGGiwiz-EJQ,17956
|
|
93
94
|
braintrust/wrappers/litellm.py,sha256=ZE63C8OE5Z0N3mArwOWZusDXBW1MElPOCjODOF-tmB0,26616
|
|
94
95
|
braintrust/wrappers/openai.py,sha256=SZuT4ouJd8FRNXxy9zM_OGb2HNL9XGsFnwkHCk3LDAM,10563
|
|
95
96
|
braintrust/wrappers/pydantic_ai.py,sha256=AgMZS4F7c5Um-P98p13A0uapMFGuYf5YyXuDw1nwPHs,48534
|
|
96
|
-
braintrust/wrappers/test_agno.py,sha256=
|
|
97
|
-
braintrust/wrappers/test_anthropic.py,sha256=
|
|
98
|
-
braintrust/wrappers/test_dspy.py,sha256=
|
|
99
|
-
braintrust/wrappers/test_google_genai.py,sha256=
|
|
100
|
-
braintrust/wrappers/
|
|
101
|
-
braintrust/wrappers/
|
|
102
|
-
braintrust/wrappers/
|
|
103
|
-
braintrust/wrappers/
|
|
104
|
-
braintrust/wrappers/
|
|
105
|
-
braintrust/wrappers/
|
|
97
|
+
braintrust/wrappers/test_agno.py,sha256=IyxhKOy8kfMbLR_fA__MK7aDvmsJpV-oh-7eez9hrw8,3452
|
|
98
|
+
braintrust/wrappers/test_anthropic.py,sha256=DcLrYhFUhBFiYcP_Su3FcEW6-Ubt21JzjY8Hxwzpcbw,15495
|
|
99
|
+
braintrust/wrappers/test_dspy.py,sha256=peWwbBBi8mpDhp2brs4ozd5cWz_CjYoyQTp7hjvt97U,1759
|
|
100
|
+
braintrust/wrappers/test_google_genai.py,sha256=dY5ZXeTscvrz_8HfSbMr2Qbb_0W-FzUvQSzpG6EZXnU,20204
|
|
101
|
+
braintrust/wrappers/test_langsmith_wrapper.py,sha256=wEbPNy4o7VVvcuHcsCJ-sy2EATvBxhUXTYFBQNkKCjs,10449
|
|
102
|
+
braintrust/wrappers/test_litellm.py,sha256=BAdksj_yzoY0LoHpnDHVgUpOaSxkI_I9Nk5ZZEVuaAU,23604
|
|
103
|
+
braintrust/wrappers/test_oai_attachments.py,sha256=_EtNXjQxPgqXmj6UYMZn9GF4GDZf8m_1_TrwiEk7HWQ,11100
|
|
104
|
+
braintrust/wrappers/test_openai.py,sha256=8gQqJigWmEe3_Nxc5vvPndLIuhIeBY2B2oHLU_vuUkk,60065
|
|
105
|
+
braintrust/wrappers/test_openrouter.py,sha256=8HUfILPugOMqcvttpq76KQrynFb0xZpazvta7TTSF6A,3849
|
|
106
|
+
braintrust/wrappers/test_pydantic_ai_integration.py,sha256=oK26oEI56feg3SwbA-fxkGtVMS8eAC9j-gJsOUudmzw,104106
|
|
107
|
+
braintrust/wrappers/test_pydantic_ai_wrap_openai.py,sha256=OO5NrbothkMr4v2sZ-EZLH7-yLj3k6TfdLG4uzXAsQk,5090
|
|
106
108
|
braintrust/wrappers/test_utils.py,sha256=Qz7LYG5V0DK2KuTJ_YLGpO_Zr_LJFfJgZX_Ps8tlM_c,505
|
|
107
109
|
braintrust/wrappers/agno/__init__.py,sha256=0ehV_7L_ILsMfZ1bKHnzcR_CvFM98KMbGFN9UiE94vI,2379
|
|
108
110
|
braintrust/wrappers/agno/agent.py,sha256=m3HCxQNotJviJswGYMxxsOnMilF-DNGqeFZFJa2Zhs4,6473
|
|
@@ -114,8 +116,8 @@ braintrust/wrappers/claude_agent_sdk/__init__.py,sha256=dcBP61ijW2B4g902-09ZfIOk
|
|
|
114
116
|
braintrust/wrappers/claude_agent_sdk/_wrapper.py,sha256=K6iWfnYSgRq0ETGQ7CCh4rF4JJ0CR-G-VkCUfeKEQ-c,15645
|
|
115
117
|
braintrust/wrappers/claude_agent_sdk/test_wrapper.py,sha256=0NmohdECudFvWtc-5PbANtTXzexkkwIJhGbujydDrT8,6826
|
|
116
118
|
braintrust/wrappers/google_genai/__init__.py,sha256=Yv4hBOUc6TjUpYH3bEW8UaYiZ-sm3TpdVfqUw50NwQU,15826
|
|
117
|
-
braintrust-0.4.
|
|
118
|
-
braintrust-0.4.
|
|
119
|
-
braintrust-0.4.
|
|
120
|
-
braintrust-0.4.
|
|
121
|
-
braintrust-0.4.
|
|
119
|
+
braintrust-0.4.3.dist-info/METADATA,sha256=XPLnFVJXuBT2YvH3tVwcTR1L8M8gMSCvtpsHWH8AA30,3753
|
|
120
|
+
braintrust-0.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
121
|
+
braintrust-0.4.3.dist-info/entry_points.txt,sha256=Zpc0_09g5xm8as5jHqqFq7fhwO0xHSNct_TrEMONS7Q,60
|
|
122
|
+
braintrust-0.4.3.dist-info/top_level.txt,sha256=hw1-y-UFMf60RzAr8x_eM7SThbIuWfQsQIbVvqSF83A,11
|
|
123
|
+
braintrust-0.4.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|