braintrust 0.5.0__py3-none-any.whl → 0.5.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.
Files changed (42) hide show
  1. braintrust/__init__.py +14 -0
  2. braintrust/_generated_types.py +56 -3
  3. braintrust/auto.py +179 -0
  4. braintrust/conftest.py +23 -4
  5. braintrust/db_fields.py +10 -0
  6. braintrust/framework.py +18 -5
  7. braintrust/generated_types.py +3 -1
  8. braintrust/logger.py +369 -134
  9. braintrust/merge_row_batch.py +49 -109
  10. braintrust/oai.py +51 -0
  11. braintrust/test_bt_json.py +0 -5
  12. braintrust/test_context.py +1264 -0
  13. braintrust/test_framework.py +37 -0
  14. braintrust/test_http.py +444 -0
  15. braintrust/test_logger.py +179 -5
  16. braintrust/test_merge_row_batch.py +160 -0
  17. braintrust/test_util.py +58 -1
  18. braintrust/util.py +20 -0
  19. braintrust/version.py +2 -2
  20. braintrust/wrappers/agno/__init__.py +2 -3
  21. braintrust/wrappers/anthropic.py +64 -0
  22. braintrust/wrappers/claude_agent_sdk/__init__.py +2 -3
  23. braintrust/wrappers/claude_agent_sdk/test_wrapper.py +9 -0
  24. braintrust/wrappers/dspy.py +52 -1
  25. braintrust/wrappers/google_genai/__init__.py +9 -6
  26. braintrust/wrappers/litellm.py +6 -43
  27. braintrust/wrappers/pydantic_ai.py +2 -3
  28. braintrust/wrappers/test_agno.py +9 -0
  29. braintrust/wrappers/test_anthropic.py +156 -0
  30. braintrust/wrappers/test_dspy.py +117 -0
  31. braintrust/wrappers/test_google_genai.py +9 -0
  32. braintrust/wrappers/test_litellm.py +57 -55
  33. braintrust/wrappers/test_openai.py +253 -1
  34. braintrust/wrappers/test_pydantic_ai_integration.py +9 -0
  35. braintrust/wrappers/test_utils.py +79 -0
  36. braintrust/wrappers/threads.py +114 -0
  37. {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/METADATA +1 -1
  38. {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/RECORD +41 -37
  39. {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/WHEEL +1 -1
  40. braintrust/graph_util.py +0 -147
  41. {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/entry_points.txt +0 -0
  42. {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/top_level.txt +0 -0
braintrust/graph_util.py DELETED
@@ -1,147 +0,0 @@
1
- # Generic graph algorithms.
2
-
3
- import dataclasses
4
- from typing import Protocol
5
-
6
-
7
- # An UndirectedGraph consists of a set of vertex labels and a set of edges
8
- # between vertices.
9
- @dataclasses.dataclass
10
- class UndirectedGraph:
11
- vertices: set[int]
12
- edges: set[tuple[int, int]]
13
-
14
-
15
- # An AdjacencyListGraph is a mapping from vertex label to the list of vertices
16
- # where there is a directed edge from the key to the value.
17
- AdjacencyListGraph = dict[int, set[int]]
18
-
19
-
20
- class FirstVisitF(Protocol):
21
- def __call__(self, vertex: int, *, parent_vertex: int | None, **kwargs) -> None:
22
- """Extras:
23
- - parent_vertex: the vertex which spawned the current vertex as its
24
- child during the depth-first search. `parent_vertex` is guaranteed
25
- to have been visited before the current one.
26
- """
27
- ...
28
-
29
-
30
- class LastVisitF(Protocol):
31
- def __call__(self, vertex: int) -> None: ...
32
-
33
-
34
- def depth_first_search(
35
- graph: AdjacencyListGraph,
36
- first_visit_f: FirstVisitF | None = None,
37
- last_visit_f: LastVisitF | None = None,
38
- visitation_order: list[int] | None = None,
39
- ) -> None:
40
- """A general depth-first search algorithm over a directed graph. As it
41
- traverses the graph, it invokes user-provided hooks when a vertex is *first*
42
- visited (before visiting its children) and when it is *last* visited (after
43
- visiting all its children).
44
-
45
- The first_visit_f and last_visit_f functions may be passed additional
46
- information beyond the vertex being visited as kwargs. See their type
47
- signatures for more details. For future proofing, you will likely want to
48
- capture **kwargs as a catchall in your functions.
49
-
50
- An optional `visitation_order` can be specified, which controls the order in
51
- which vertices will be first visited (outside of visiting them through a
52
- different vertex). It can also be used to limit the set of starting vertices
53
- considered. Otherwise, the DFS will visit all vertices in an unspecfied
54
- order.
55
- """
56
-
57
- # Check the validity of the graph.
58
- for vs in graph.values():
59
- for v in vs:
60
- assert v in graph
61
-
62
- first_visited_vertices = set()
63
- visitation_order = visitation_order if visitation_order is not None else graph.keys()
64
- events = list(reversed([("first", x, dict(parent_vertex=None)) for x in visitation_order]))
65
- while events:
66
- event_type, vertex, extras = events.pop()
67
-
68
- if event_type == "last":
69
- if last_visit_f:
70
- last_visit_f(vertex)
71
- continue
72
-
73
- # First visit of a node. If we've already visited it, skip.
74
- if vertex in first_visited_vertices:
75
- continue
76
- first_visited_vertices.add(vertex)
77
- if first_visit_f:
78
- first_visit_f(vertex, parent_vertex=extras["parent_vertex"])
79
-
80
- # Add 'first' visitation events for all the children of the vertex to
81
- # the stack. But before this, add a 'last' visitation event for this
82
- # vertex, so that once we've completed all the children, we get the last
83
- # visitation event for this one.
84
- events.append(("last", vertex, dict()))
85
- for child in graph[vertex]:
86
- events.append(("first", child, dict(parent_vertex=vertex)))
87
-
88
-
89
- def undirected_connected_components(graph: UndirectedGraph) -> list[list[int]]:
90
- """Group together all the connected components of an undirected graph.
91
- Return each group as a list of vertices.
92
- """
93
-
94
- # Perhaps the most performant way to implement this is via union find. But
95
- # in lieu of that, we can use a depth-first search over a direct-ified
96
- # version of the graph. Upon the first visit of each vertex, we assign it a
97
- # label equal to the label of the parent vertex. If there is no parent
98
- # vertex, we assign a new label. At the end, we can group together all the
99
- # vertices with the same label.
100
-
101
- directed_graph = {v: set() for v in graph.vertices}
102
- for i, j in graph.edges:
103
- directed_graph[i].add(j)
104
- directed_graph[j].add(i)
105
-
106
- label_counter = 0
107
- vertex_labels = {}
108
-
109
- def first_visit_f(vertex, parent_vertex, **kwargs):
110
- if parent_vertex is not None:
111
- label = vertex_labels[parent_vertex]
112
- else:
113
- nonlocal label_counter
114
- # pylint: disable=used-before-assignment
115
- label = label_counter
116
- label_counter += 1
117
- vertex_labels[vertex] = label
118
-
119
- depth_first_search(directed_graph, first_visit_f=first_visit_f)
120
- output = [[] for _ in range(label_counter)]
121
- for vertex, label in vertex_labels.items():
122
- output[label].append(vertex)
123
-
124
- return output
125
-
126
-
127
- def topological_sort(graph: AdjacencyListGraph, visitation_order: list[int] | None = None) -> list[int]:
128
- """The topological_sort function accepts a graph as input, with edges from
129
- parents to children. It returns an ordering where parents are guaranteed to
130
- come before their children.
131
-
132
- The `visitation_order` is forwarded directly to `depth_first_search`.
133
-
134
- Ordering with respect to cycles is unspecified. It is the caller's
135
- responsibility to check for cycles if it matters.
136
- """
137
-
138
- # We use DFS, where upon the 'last' visitation of a node, we append it to
139
- # the final ordering. Then we reverse the list at the end.
140
- reverse_ordering = []
141
-
142
- def last_visit_f(vertex, **kwargs):
143
- reverse_ordering.append(vertex)
144
-
145
- depth_first_search(graph, last_visit_f=last_visit_f, visitation_order=visitation_order)
146
- reverse_ordering.reverse()
147
- return reverse_ordering