openai-sdk-helpers 0.5.2__py3-none-any.whl → 0.6.1__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.
- openai_sdk_helpers/agent/__init__.py +2 -0
- openai_sdk_helpers/agent/base.py +13 -5
- openai_sdk_helpers/agent/classifier.py +848 -0
- openai_sdk_helpers/prompt/classifier.jinja +31 -0
- openai_sdk_helpers/response/base.py +26 -7
- openai_sdk_helpers/settings.py +65 -0
- openai_sdk_helpers/structure/__init__.py +12 -0
- openai_sdk_helpers/structure/base.py +79 -55
- openai_sdk_helpers/structure/classification.py +453 -0
- openai_sdk_helpers/structure/plan/enum.py +4 -0
- {openai_sdk_helpers-0.5.2.dist-info → openai_sdk_helpers-0.6.1.dist-info}/METADATA +12 -1
- {openai_sdk_helpers-0.5.2.dist-info → openai_sdk_helpers-0.6.1.dist-info}/RECORD +15 -12
- {openai_sdk_helpers-0.5.2.dist-info → openai_sdk_helpers-0.6.1.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.5.2.dist-info → openai_sdk_helpers-0.6.1.dist-info}/entry_points.txt +0 -0
- {openai_sdk_helpers-0.5.2.dist-info → openai_sdk_helpers-0.6.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
"""Structured taxonomy and classification result models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any, Iterable, Optional, cast
|
|
7
|
+
|
|
8
|
+
from .base import StructureBase, spec_field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TaxonomyNode(StructureBase):
|
|
12
|
+
"""Represent a taxonomy node with optional child categories.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
label : str
|
|
17
|
+
Human-readable label for the taxonomy node.
|
|
18
|
+
description : str | None
|
|
19
|
+
Optional description of the node.
|
|
20
|
+
children : list[TaxonomyNode]
|
|
21
|
+
Child nodes in the taxonomy.
|
|
22
|
+
|
|
23
|
+
Methods
|
|
24
|
+
-------
|
|
25
|
+
build_path(parent_path)
|
|
26
|
+
Build a computed path using the provided parent path segments.
|
|
27
|
+
computed_path
|
|
28
|
+
Return the computed path for the node.
|
|
29
|
+
is_leaf
|
|
30
|
+
Return True when the taxonomy node has no children.
|
|
31
|
+
child_by_path(path)
|
|
32
|
+
Return the child node matching the provided path.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
label: str = spec_field(
|
|
36
|
+
"label", description="Human-readable label for the taxonomy node."
|
|
37
|
+
)
|
|
38
|
+
description: str | None = spec_field(
|
|
39
|
+
"description",
|
|
40
|
+
description="Optional description of the taxonomy node.",
|
|
41
|
+
default=None,
|
|
42
|
+
)
|
|
43
|
+
children: list["TaxonomyNode"] = spec_field(
|
|
44
|
+
"children",
|
|
45
|
+
description="Child nodes in the taxonomy.",
|
|
46
|
+
default_factory=list,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def is_leaf(self) -> bool:
|
|
51
|
+
"""Return True when the taxonomy node has no children.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
bool
|
|
56
|
+
True if the node has no children.
|
|
57
|
+
"""
|
|
58
|
+
return not self.children
|
|
59
|
+
|
|
60
|
+
def build_path(self, parent_path: Iterable[str] | None = None) -> list[str]:
|
|
61
|
+
"""Build a computed path using the provided parent path segments.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
parent_path : Iterable[str] or None, default=None
|
|
66
|
+
Parent path segments to prepend to the node label.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
list[str]
|
|
71
|
+
Computed path segments for this node.
|
|
72
|
+
"""
|
|
73
|
+
if parent_path is None:
|
|
74
|
+
return [self.label]
|
|
75
|
+
return [*parent_path, self.label]
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def computed_path(self) -> list[str]:
|
|
79
|
+
"""Return the computed path for the node.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
list[str]
|
|
84
|
+
Computed path segments for this node.
|
|
85
|
+
"""
|
|
86
|
+
return self.build_path()
|
|
87
|
+
|
|
88
|
+
def child_by_path(
|
|
89
|
+
self, path: Iterable[str] | str | None
|
|
90
|
+
) -> Optional["TaxonomyNode"]:
|
|
91
|
+
"""Return the child node matching the provided path.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
path : Iterable[str] or str or None
|
|
96
|
+
Path segments or a delimited path string to locate.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
TaxonomyNode or None
|
|
101
|
+
Matching child node, if found.
|
|
102
|
+
"""
|
|
103
|
+
if path is None:
|
|
104
|
+
return None
|
|
105
|
+
if isinstance(path, str):
|
|
106
|
+
path_segments = _split_path_identifier(path)
|
|
107
|
+
else:
|
|
108
|
+
path_segments = list(path)
|
|
109
|
+
last_segment = path_segments[-1] if path_segments else None
|
|
110
|
+
if not last_segment:
|
|
111
|
+
return None
|
|
112
|
+
return next(
|
|
113
|
+
(child for child in self.children if child.label == last_segment),
|
|
114
|
+
None,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _split_path_identifier(path: str) -> list[str]:
|
|
119
|
+
"""Split a path identifier into label segments.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
path : str
|
|
124
|
+
Path identifier to split.
|
|
125
|
+
|
|
126
|
+
Returns
|
|
127
|
+
-------
|
|
128
|
+
list[str]
|
|
129
|
+
Label segments extracted from the path identifier.
|
|
130
|
+
"""
|
|
131
|
+
delimiter = " > "
|
|
132
|
+
escape_token = "\\>"
|
|
133
|
+
segments = path.split(delimiter) if path else []
|
|
134
|
+
return [segment.replace(escape_token, delimiter) for segment in segments]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class ClassificationStopReason(str, Enum):
|
|
138
|
+
"""Enumerate stop reasons for taxonomy classification.
|
|
139
|
+
|
|
140
|
+
Methods
|
|
141
|
+
-------
|
|
142
|
+
is_terminal
|
|
143
|
+
Return True if the stop reason should halt traversal.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
CONTINUE = "continue"
|
|
147
|
+
STOP = "stop"
|
|
148
|
+
NO_MATCH = "no_match"
|
|
149
|
+
MAX_DEPTH = "max_depth"
|
|
150
|
+
NO_CHILDREN = "no_children"
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def is_terminal(self) -> bool:
|
|
154
|
+
"""Return True if the stop reason should halt traversal.
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
bool
|
|
159
|
+
True when traversal should stop.
|
|
160
|
+
"""
|
|
161
|
+
return self in {
|
|
162
|
+
ClassificationStopReason.STOP,
|
|
163
|
+
ClassificationStopReason.NO_MATCH,
|
|
164
|
+
ClassificationStopReason.MAX_DEPTH,
|
|
165
|
+
ClassificationStopReason.NO_CHILDREN,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class ClassificationStep(StructureBase):
|
|
170
|
+
"""Represent a classification step constrained to taxonomy node enums.
|
|
171
|
+
|
|
172
|
+
Attributes
|
|
173
|
+
----------
|
|
174
|
+
selected_node : Enum or None
|
|
175
|
+
Enum value of the selected taxonomy node.
|
|
176
|
+
selected_nodes : list[Enum] or None
|
|
177
|
+
Enum values of selected taxonomy nodes for multi-class classification.
|
|
178
|
+
confidence : float or None
|
|
179
|
+
Confidence score between 0 and 1.
|
|
180
|
+
stop_reason : ClassificationStopReason
|
|
181
|
+
Reason for stopping or continuing traversal.
|
|
182
|
+
rationale : str or None
|
|
183
|
+
Optional rationale for the classification decision.
|
|
184
|
+
|
|
185
|
+
Methods
|
|
186
|
+
-------
|
|
187
|
+
build_for_enum(enum_cls)
|
|
188
|
+
Build a ClassificationStep subclass with enum-constrained selections.
|
|
189
|
+
as_summary()
|
|
190
|
+
Return a dictionary summary of the classification step.
|
|
191
|
+
|
|
192
|
+
Examples
|
|
193
|
+
--------
|
|
194
|
+
Create a multi-class step and summarize the selections:
|
|
195
|
+
|
|
196
|
+
>>> NodeEnum = Enum("NodeEnum", {"BILLING": "billing"})
|
|
197
|
+
>>> StepEnum = ClassificationStep.build_for_enum(NodeEnum)
|
|
198
|
+
>>> step = StepEnum(
|
|
199
|
+
... selected_nodes=[NodeEnum.BILLING],
|
|
200
|
+
... confidence=0.82,
|
|
201
|
+
... stop_reason=ClassificationStopReason.STOP,
|
|
202
|
+
... )
|
|
203
|
+
>>> step.as_summary()["selected_nodes"]
|
|
204
|
+
[<NodeEnum.BILLING: 'billing'>]
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
selected_node: Enum | None = spec_field(
|
|
208
|
+
"selected_node",
|
|
209
|
+
description="Path identifier of the selected taxonomy node.",
|
|
210
|
+
default=None,
|
|
211
|
+
)
|
|
212
|
+
selected_nodes: list[Enum] | None = spec_field(
|
|
213
|
+
"selected_nodes",
|
|
214
|
+
description="Path identifiers of selected taxonomy nodes.",
|
|
215
|
+
default=None,
|
|
216
|
+
)
|
|
217
|
+
confidence: Optional[float] = spec_field(
|
|
218
|
+
"confidence",
|
|
219
|
+
description="Confidence score between 0 and 1.",
|
|
220
|
+
default=None,
|
|
221
|
+
)
|
|
222
|
+
stop_reason: ClassificationStopReason = spec_field(
|
|
223
|
+
"stop_reason",
|
|
224
|
+
description="Reason for stopping or continuing traversal.",
|
|
225
|
+
default=ClassificationStopReason.STOP,
|
|
226
|
+
allow_null=False,
|
|
227
|
+
)
|
|
228
|
+
rationale: Optional[str] = spec_field(
|
|
229
|
+
"rationale",
|
|
230
|
+
description="Optional rationale for the classification decision.",
|
|
231
|
+
default=None,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
@classmethod
|
|
235
|
+
def build_for_enum(cls, enum_cls: type[Enum]) -> type["ClassificationStep"]:
|
|
236
|
+
"""Build a ClassificationStep subclass with enum-constrained fields.
|
|
237
|
+
|
|
238
|
+
Parameters
|
|
239
|
+
----------
|
|
240
|
+
enum_cls : type[Enum]
|
|
241
|
+
Enum type to use for node selections.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
type[ClassificationStep]
|
|
246
|
+
Specialized ClassificationStep class bound to the enum.
|
|
247
|
+
"""
|
|
248
|
+
namespace: dict[str, Any] = {
|
|
249
|
+
"__annotations__": {
|
|
250
|
+
"selected_node": enum_cls | None,
|
|
251
|
+
"selected_nodes": list[enum_cls] | None,
|
|
252
|
+
},
|
|
253
|
+
"selected_node": spec_field(
|
|
254
|
+
"selected_node",
|
|
255
|
+
description="Path identifier of the selected taxonomy node.",
|
|
256
|
+
default=None,
|
|
257
|
+
),
|
|
258
|
+
"selected_nodes": spec_field(
|
|
259
|
+
"selected_nodes",
|
|
260
|
+
description="Path identifiers of selected taxonomy nodes.",
|
|
261
|
+
default=None,
|
|
262
|
+
),
|
|
263
|
+
}
|
|
264
|
+
return cast(type["ClassificationStep"], type("BoundStep", (cls,), namespace))
|
|
265
|
+
|
|
266
|
+
def as_summary(self) -> dict[str, Any]:
|
|
267
|
+
"""Return a dictionary summary of the classification step.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
dict[str, Any]
|
|
272
|
+
Summary data for logging or inspection.
|
|
273
|
+
|
|
274
|
+
Examples
|
|
275
|
+
--------
|
|
276
|
+
>>> NodeEnum = Enum("NodeEnum", {"ROOT": "root"})
|
|
277
|
+
>>> StepEnum = ClassificationStep.build_for_enum(NodeEnum)
|
|
278
|
+
>>> step = StepEnum(selected_node=NodeEnum.ROOT)
|
|
279
|
+
>>> step.as_summary()["selected_node"]
|
|
280
|
+
<NodeEnum.ROOT: 'root'>
|
|
281
|
+
"""
|
|
282
|
+
selected_node = _normalize_enum_value(self.selected_node)
|
|
283
|
+
selected_nodes = [
|
|
284
|
+
_normalize_enum_value(item) for item in self.selected_nodes or []
|
|
285
|
+
]
|
|
286
|
+
return {
|
|
287
|
+
"selected_node": selected_node,
|
|
288
|
+
"selected_nodes": selected_nodes or None,
|
|
289
|
+
"confidence": self.confidence,
|
|
290
|
+
"stop_reason": self.stop_reason.value,
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _normalize_enum_value(value: Any) -> Any:
|
|
295
|
+
"""Normalize enum values into raw primitives.
|
|
296
|
+
|
|
297
|
+
Parameters
|
|
298
|
+
----------
|
|
299
|
+
value : Any
|
|
300
|
+
Value to normalize.
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
Any
|
|
305
|
+
Primitive value suitable for summaries.
|
|
306
|
+
"""
|
|
307
|
+
if isinstance(value, Enum):
|
|
308
|
+
return value.value
|
|
309
|
+
return value
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class ClassificationResult(StructureBase):
|
|
313
|
+
"""Represent the final result of taxonomy traversal.
|
|
314
|
+
|
|
315
|
+
Attributes
|
|
316
|
+
----------
|
|
317
|
+
final_node : TaxonomyNode or None
|
|
318
|
+
Resolved taxonomy node for the final selection.
|
|
319
|
+
final_nodes : list[TaxonomyNode] or None
|
|
320
|
+
Resolved taxonomy nodes for the final selections across branches.
|
|
321
|
+
confidence : float or None
|
|
322
|
+
Confidence score for the final selection.
|
|
323
|
+
stop_reason : ClassificationStopReason
|
|
324
|
+
Reason the traversal ended.
|
|
325
|
+
path : list[ClassificationStep]
|
|
326
|
+
Ordered list of classification steps.
|
|
327
|
+
path_nodes : list[TaxonomyNode]
|
|
328
|
+
Resolved taxonomy nodes selected across the path.
|
|
329
|
+
|
|
330
|
+
Methods
|
|
331
|
+
-------
|
|
332
|
+
depth
|
|
333
|
+
Return the number of classification steps recorded.
|
|
334
|
+
path_identifiers
|
|
335
|
+
Return the identifiers selected at each step.
|
|
336
|
+
|
|
337
|
+
Examples
|
|
338
|
+
--------
|
|
339
|
+
Summarize single and multi-class output:
|
|
340
|
+
|
|
341
|
+
>>> node = TaxonomyNode(label="Tax")
|
|
342
|
+
>>> result = ClassificationResult(
|
|
343
|
+
... final_node=node,
|
|
344
|
+
... final_nodes=[node],
|
|
345
|
+
... confidence=0.91,
|
|
346
|
+
... stop_reason=ClassificationStopReason.STOP,
|
|
347
|
+
... )
|
|
348
|
+
>>> result.final_nodes
|
|
349
|
+
[TaxonomyNode(label='Tax', description=None, children=[])]
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
final_node: TaxonomyNode | None = spec_field(
|
|
353
|
+
"final_node",
|
|
354
|
+
description="Resolved taxonomy node for the final selection.",
|
|
355
|
+
default=None,
|
|
356
|
+
)
|
|
357
|
+
final_nodes: list[TaxonomyNode] | None = spec_field(
|
|
358
|
+
"final_nodes",
|
|
359
|
+
description="Resolved taxonomy nodes for the final selections.",
|
|
360
|
+
default=None,
|
|
361
|
+
)
|
|
362
|
+
confidence: Optional[float] = spec_field(
|
|
363
|
+
"confidence",
|
|
364
|
+
description="Confidence score for the final selection.",
|
|
365
|
+
default=None,
|
|
366
|
+
)
|
|
367
|
+
stop_reason: ClassificationStopReason = spec_field(
|
|
368
|
+
"stop_reason",
|
|
369
|
+
description="Reason the traversal ended.",
|
|
370
|
+
default=ClassificationStopReason.STOP,
|
|
371
|
+
)
|
|
372
|
+
path: list[ClassificationStep] = spec_field(
|
|
373
|
+
"path",
|
|
374
|
+
description="Ordered list of classification steps.",
|
|
375
|
+
default_factory=list,
|
|
376
|
+
)
|
|
377
|
+
path_nodes: list[TaxonomyNode] = spec_field(
|
|
378
|
+
"path_nodes",
|
|
379
|
+
description="Resolved taxonomy nodes selected across the path.",
|
|
380
|
+
default_factory=list,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
@property
|
|
384
|
+
def depth(self) -> int:
|
|
385
|
+
"""Return the number of classification steps recorded.
|
|
386
|
+
|
|
387
|
+
Returns
|
|
388
|
+
-------
|
|
389
|
+
int
|
|
390
|
+
Count of classification steps.
|
|
391
|
+
"""
|
|
392
|
+
return len(self.path)
|
|
393
|
+
|
|
394
|
+
@property
|
|
395
|
+
def path_identifiers(self) -> list[str]:
|
|
396
|
+
"""Return the identifiers selected at each step.
|
|
397
|
+
|
|
398
|
+
Returns
|
|
399
|
+
-------
|
|
400
|
+
list[str]
|
|
401
|
+
Identifiers selected at each classification step.
|
|
402
|
+
|
|
403
|
+
Examples
|
|
404
|
+
--------
|
|
405
|
+
>>> steps = [
|
|
406
|
+
... ClassificationStep(selected_node="Root"),
|
|
407
|
+
... ClassificationStep(selected_nodes=["Root > Leaf", "Root > Branch"]),
|
|
408
|
+
... ]
|
|
409
|
+
>>> ClassificationResult(
|
|
410
|
+
... stop_reason=ClassificationStopReason.STOP,
|
|
411
|
+
... path=steps,
|
|
412
|
+
... ).path_identifiers
|
|
413
|
+
['Root', 'Root > Leaf', 'Root > Branch']
|
|
414
|
+
"""
|
|
415
|
+
identifiers: list[str] = []
|
|
416
|
+
for step in self.path:
|
|
417
|
+
if step.selected_nodes:
|
|
418
|
+
identifiers.extend(
|
|
419
|
+
_normalize_enum_value(value) for value in step.selected_nodes
|
|
420
|
+
)
|
|
421
|
+
elif step.selected_node:
|
|
422
|
+
identifiers.append(_normalize_enum_value(step.selected_node))
|
|
423
|
+
return [identifier for identifier in identifiers if identifier]
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def flatten_taxonomy(nodes: Iterable[TaxonomyNode]) -> list[TaxonomyNode]:
|
|
427
|
+
"""Return a flattened list of taxonomy nodes.
|
|
428
|
+
|
|
429
|
+
Parameters
|
|
430
|
+
----------
|
|
431
|
+
nodes : Iterable[TaxonomyNode]
|
|
432
|
+
Root nodes to traverse.
|
|
433
|
+
|
|
434
|
+
Returns
|
|
435
|
+
-------
|
|
436
|
+
list[TaxonomyNode]
|
|
437
|
+
Depth-first ordered list of nodes.
|
|
438
|
+
"""
|
|
439
|
+
flattened: list[TaxonomyNode] = []
|
|
440
|
+
for node in nodes:
|
|
441
|
+
flattened.append(node)
|
|
442
|
+
if node.children:
|
|
443
|
+
flattened.extend(flatten_taxonomy(node.children))
|
|
444
|
+
return flattened
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
__all__ = [
|
|
448
|
+
"ClassificationResult",
|
|
449
|
+
"ClassificationStep",
|
|
450
|
+
"ClassificationStopReason",
|
|
451
|
+
"TaxonomyNode",
|
|
452
|
+
"flatten_taxonomy",
|
|
453
|
+
]
|
|
@@ -29,6 +29,8 @@ class AgentEnum(CrosswalkJSONEnum):
|
|
|
29
29
|
Translation agent for language conversion.
|
|
30
30
|
VALIDATOR : str
|
|
31
31
|
Validation agent for checking constraints and guardrails.
|
|
32
|
+
CLASSIFIER : str
|
|
33
|
+
Taxonomy classifier agent for structured label selection.
|
|
32
34
|
PLANNER : str
|
|
33
35
|
Meta-planning agent for generating execution plans.
|
|
34
36
|
DESIGNER : str
|
|
@@ -58,6 +60,7 @@ class AgentEnum(CrosswalkJSONEnum):
|
|
|
58
60
|
SUMMARIZER = "SummarizerAgent"
|
|
59
61
|
TRANSLATOR = "TranslatorAgent"
|
|
60
62
|
VALIDATOR = "ValidatorAgent"
|
|
63
|
+
CLASSIFIER = "TaxonomyClassifierAgent"
|
|
61
64
|
PLANNER = "MetaPlanner"
|
|
62
65
|
DESIGNER = "AgentDesigner"
|
|
63
66
|
BUILDER = "AgentBuilder"
|
|
@@ -89,6 +92,7 @@ class AgentEnum(CrosswalkJSONEnum):
|
|
|
89
92
|
"SUMMARIZER": {"value": "SummarizerAgent"},
|
|
90
93
|
"TRANSLATOR": {"value": "TranslatorAgent"},
|
|
91
94
|
"VALIDATOR": {"value": "ValidatorAgent"},
|
|
95
|
+
"CLASSIFIER": {"value": "TaxonomyClassifierAgent"},
|
|
92
96
|
"PLANNER": {"value": "MetaPlanner"},
|
|
93
97
|
"DESIGNER": {"value": "AgentDesigner"},
|
|
94
98
|
"BUILDER": {"value": "AgentBuilder"},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openai-sdk-helpers
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
|
|
5
5
|
Author: openai-sdk-helpers maintainers
|
|
6
6
|
License: MIT
|
|
@@ -97,6 +97,7 @@ The `agent` module provides a higher-level abstraction for building agents, whil
|
|
|
97
97
|
- **SummarizerAgent**: Generate concise summaries from provided text
|
|
98
98
|
- **TranslatorAgent**: Translate text into target languages
|
|
99
99
|
- **ValidatorAgent**: Check inputs and outputs against safety guardrails
|
|
100
|
+
- **TaxonomyClassifierAgent**: Classify text into taxonomy-driven labels
|
|
100
101
|
|
|
101
102
|
#### Response Module (Built on `openai` SDK)
|
|
102
103
|
- **Response handling utilities** for direct API control with fine-grained message management
|
|
@@ -210,12 +211,18 @@ These use the `agent` module built on `openai-agents` SDK:
|
|
|
210
211
|
```python
|
|
211
212
|
from openai_sdk_helpers.agent import (
|
|
212
213
|
SummarizerAgent,
|
|
214
|
+
TaxonomyClassifierAgent,
|
|
213
215
|
TranslatorAgent,
|
|
214
216
|
ValidatorAgent,
|
|
215
217
|
)
|
|
218
|
+
from openai_sdk_helpers.structure import TaxonomyNode
|
|
216
219
|
|
|
217
220
|
# Initialize agents with a default model
|
|
218
221
|
summarizer = SummarizerAgent(default_model="gpt-4o-mini")
|
|
222
|
+
classifier = TaxonomyClassifierAgent(
|
|
223
|
+
model="gpt-4o-mini",
|
|
224
|
+
taxonomy=[TaxonomyNode(label="Billing"), TaxonomyNode(label="Support")],
|
|
225
|
+
)
|
|
219
226
|
translator = TranslatorAgent(default_model="gpt-4o-mini")
|
|
220
227
|
validator = ValidatorAgent(default_model="gpt-4o-mini")
|
|
221
228
|
|
|
@@ -227,6 +234,10 @@ print(summary.text)
|
|
|
227
234
|
translation = translator.run_sync("Bonjour", target_language="English")
|
|
228
235
|
print(translation)
|
|
229
236
|
|
|
237
|
+
# Classify text against a taxonomy
|
|
238
|
+
classification = classifier.run_sync("I need help with my invoice")
|
|
239
|
+
print(classification.final_node)
|
|
240
|
+
|
|
230
241
|
# Validate against guardrails
|
|
231
242
|
validation = validator.run_sync(
|
|
232
243
|
"Share meeting notes with names removed",
|
|
@@ -5,11 +5,12 @@ openai_sdk_helpers/errors.py,sha256=ZclLp94o08fSsFNjFn_yrX9yTjw1RE0v7A5T1hBChUc,
|
|
|
5
5
|
openai_sdk_helpers/files_api.py,sha256=Sg-k4YDsrzggvICYA7h4Ua6_vGhMpZmAeS5JtQVE2hU,12598
|
|
6
6
|
openai_sdk_helpers/logging.py,sha256=djtMo_R_88JjxJeUGU_hSlYCTRv3ffoSu1ocOKrUBIw,1153
|
|
7
7
|
openai_sdk_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
openai_sdk_helpers/settings.py,sha256=
|
|
8
|
+
openai_sdk_helpers/settings.py,sha256=9qTdEIWuvQfQEQI8MU6STUDvbOk-I9FdmAEDjb2Zwx8,13316
|
|
9
9
|
openai_sdk_helpers/tools.py,sha256=8hhcytpmDfoXV16UQbDmDVV0rhLOn8c_VjXO8XaTFLQ,19000
|
|
10
10
|
openai_sdk_helpers/types.py,sha256=ejCG0rYqJhjOQvKLoNnzq-TzcKCFt69GVfi7y805NkU,1451
|
|
11
|
-
openai_sdk_helpers/agent/__init__.py,sha256=
|
|
12
|
-
openai_sdk_helpers/agent/base.py,sha256=
|
|
11
|
+
openai_sdk_helpers/agent/__init__.py,sha256=Nyvm8MJB-FhxhOfXD6ohDveSEUDR4KK76ffASCtgNIk,1119
|
|
12
|
+
openai_sdk_helpers/agent/base.py,sha256=vEsAZ6FkaQx1vAEJkCArL-ygplOEw4546f36jA2R6Ws,26488
|
|
13
|
+
openai_sdk_helpers/agent/classifier.py,sha256=6RjWhCz-hAWdHooShdUUFn0FkSWH4QZZogkRKML0S3k,25864
|
|
13
14
|
openai_sdk_helpers/agent/configuration.py,sha256=FU3xnb8-8qoezLW47WwxZg7z2AxNXRW1Svl0FMsk8kc,14244
|
|
14
15
|
openai_sdk_helpers/agent/coordinator.py,sha256=lVjA0yI-GhGKlqbNR_k9GOCrUjFoZ0QoqRaafHckyME,18052
|
|
15
16
|
openai_sdk_helpers/agent/runner.py,sha256=l2NPS9VA9d4RISuBfanFfKxXNYSHQ7MTjRsuzx4APls,3473
|
|
@@ -28,6 +29,7 @@ openai_sdk_helpers/extract/extractor.py,sha256=vmRJyhKDEYAVfRk0KMgLH5hTqUfDAUyWB
|
|
|
28
29
|
openai_sdk_helpers/extract/generator.py,sha256=K9Euq0IaWs82oe5aRm73_18DelLKYyuH8VhfZ1_ZCEU,14695
|
|
29
30
|
openai_sdk_helpers/prompt/__init__.py,sha256=MOqgKwG9KLqKudoKRlUfLxiSmdOi2aD6hNrWDFqLHkk,418
|
|
30
31
|
openai_sdk_helpers/prompt/base.py,sha256=6X0zeopEvO0ba8207O8Nnj1QvFZEZier7kNNh4qkcmE,7782
|
|
32
|
+
openai_sdk_helpers/prompt/classifier.jinja,sha256=PgJ8tvnuOcEa4DGbOqIrEyrG0GJ26bBpTZ7FlRZoL-s,1239
|
|
31
33
|
openai_sdk_helpers/prompt/extractor_config_agent_instructions.jinja,sha256=vCrsoUnsgHWSr7OS_ojMUjmPtHfbyv9bzKfaMaCJ99E,329
|
|
32
34
|
openai_sdk_helpers/prompt/extractor_config_generator.jinja,sha256=9rZ1PZdoQtnxDxFUlKRb0SooIEfNw4_Em99n9xvFyyU,960
|
|
33
35
|
openai_sdk_helpers/prompt/extractor_config_generator_instructions.jinja,sha256=GqV3DrGObyER_Fa-GMGGqhWBrQIH9FFlyKdgTjidyzg,534
|
|
@@ -40,7 +42,7 @@ openai_sdk_helpers/prompt/vector_planner.jinja,sha256=szzuJu6ZawYWuARgQn4DykBLig
|
|
|
40
42
|
openai_sdk_helpers/prompt/vector_search.jinja,sha256=KPEYQDRKsUesadSyQcBBiqYQEDL1NLN6BQsqw-GcKMA,249
|
|
41
43
|
openai_sdk_helpers/prompt/vector_writer.jinja,sha256=q5osfexGvt1xn8ZPtBWUP36n_1HK_Ziu8dkmCZDVamc,342
|
|
42
44
|
openai_sdk_helpers/response/__init__.py,sha256=YFrGpnMIfatnLWXAZgZDMvDx7Yjsqjat8W9INxKuPxY,1728
|
|
43
|
-
openai_sdk_helpers/response/base.py,sha256=
|
|
45
|
+
openai_sdk_helpers/response/base.py,sha256=tR_COd8VziI7y8bEtL6LysjQgpZQfeBNEUwswzp0QxU,38719
|
|
44
46
|
openai_sdk_helpers/response/configuration.py,sha256=jxneKd7oj08D40ceOWETB3TeUHd7Cnz-ooQp0akI9fA,10465
|
|
45
47
|
openai_sdk_helpers/response/files.py,sha256=O--boEPdFGsf9pHXPuNtG0aVJG2ZzwR4L1CZDW0hBP4,14450
|
|
46
48
|
openai_sdk_helpers/response/messages.py,sha256=qX3sW79rLuJEys28zyv5MovZikwGOaLevzdVN0VYMRE,10104
|
|
@@ -52,9 +54,10 @@ openai_sdk_helpers/response/vector_store.py,sha256=HClp6O_g20uklQTY7trC4age3rtDm
|
|
|
52
54
|
openai_sdk_helpers/streamlit_app/__init__.py,sha256=3yAkl6qV71cqtT5YFZuC9Bkqit0NtffDV6jmMWpT1k4,812
|
|
53
55
|
openai_sdk_helpers/streamlit_app/app.py,sha256=kkjtdCKVwrJ9nZWuBArm3dhvcjMESX0TMqAiF61_JLM,17402
|
|
54
56
|
openai_sdk_helpers/streamlit_app/configuration.py,sha256=0KeJ4HqCNFthBHsedV6ptqHluAcTPBb5_TujFOGkIUU,16685
|
|
55
|
-
openai_sdk_helpers/structure/__init__.py,sha256
|
|
57
|
+
openai_sdk_helpers/structure/__init__.py,sha256=-_bEFvvKhg99bgsMnimpxx7RpLQpQyReSMquOc-2Ts8,4173
|
|
56
58
|
openai_sdk_helpers/structure/agent_blueprint.py,sha256=VyJWkgPNzAYKRDMeR1M4kE6qqQURnwqtrrEn0TRJf0g,9698
|
|
57
|
-
openai_sdk_helpers/structure/base.py,sha256=
|
|
59
|
+
openai_sdk_helpers/structure/base.py,sha256=UrnNNU9qQ9mEES8MB9y6QESbDgPXH47XW8LVWSxYUYM,25280
|
|
60
|
+
openai_sdk_helpers/structure/classification.py,sha256=q7d9x2Ya7ICBr6rk5SOSrQrW5lDLat345wHQisKZO7Y,13351
|
|
58
61
|
openai_sdk_helpers/structure/extraction.py,sha256=wODP0iLAhhsdQkMWRYPYTiLUMU8bFMKiBjPl3PKUleg,37335
|
|
59
62
|
openai_sdk_helpers/structure/prompt.py,sha256=ZfsaHdA0hj5zmZDrOdpXjCsC8U-jjzwFG4JBsWYiaH4,1535
|
|
60
63
|
openai_sdk_helpers/structure/responses.py,sha256=WUwh0DhXj24pkvgqH1FMkdx5V2ArdvdtrDN_fuMBtDU,4882
|
|
@@ -64,7 +67,7 @@ openai_sdk_helpers/structure/validation.py,sha256=D03rlyBDn22qNjTGaGsjhsk3g50oPm
|
|
|
64
67
|
openai_sdk_helpers/structure/vector_search.py,sha256=XNQsG6_-c7X6TpXjqWOdKCmqXatX1gwd0zq-hII3cz4,5782
|
|
65
68
|
openai_sdk_helpers/structure/web_search.py,sha256=cPqjwip0xS3OHf7yQ3B_t4VJSlviqgqzPpOkT8_qLvY,4330
|
|
66
69
|
openai_sdk_helpers/structure/plan/__init__.py,sha256=IGr0Tk4inN_8o7fT2N02_FTi6U6l2T9_npcQHAlBwKA,1076
|
|
67
|
-
openai_sdk_helpers/structure/plan/enum.py,sha256=
|
|
70
|
+
openai_sdk_helpers/structure/plan/enum.py,sha256=sXi4Qk3zalF1vhLdo9c_hyhPSNr1hDZHhK1WygEIc2w,3273
|
|
68
71
|
openai_sdk_helpers/structure/plan/helpers.py,sha256=Vc6dBTMFrNWlsaCTpEImEIKjfFq4BSSxNjB4K8dywOQ,5139
|
|
69
72
|
openai_sdk_helpers/structure/plan/plan.py,sha256=yRBx0Z7tog4sGyq7s1kJHvqQOzLpKT8JJ9Ur5j-lhtk,9130
|
|
70
73
|
openai_sdk_helpers/structure/plan/task.py,sha256=DAfgJIa3Yq2AMEzaX20o8SdOs2AlM28pPE9GfbmXk3o,3547
|
|
@@ -88,8 +91,8 @@ openai_sdk_helpers/vector_storage/__init__.py,sha256=L5LxO09puh9_yBB9IDTvc1CvVkA
|
|
|
88
91
|
openai_sdk_helpers/vector_storage/cleanup.py,sha256=sZ4ZSTlnjF52o9Cc8A9dTX37ZYXXDxS_fdIpoOBWvrg,3666
|
|
89
92
|
openai_sdk_helpers/vector_storage/storage.py,sha256=t_ukacaXRa9EXE4-3BxsrB4Rjhu6nTu7NA9IjCJBIpQ,24259
|
|
90
93
|
openai_sdk_helpers/vector_storage/types.py,sha256=jTCcOYMeOpZWvcse0z4T3MVs-RBOPC-fqWTBeQrgafU,1639
|
|
91
|
-
openai_sdk_helpers-0.
|
|
92
|
-
openai_sdk_helpers-0.
|
|
93
|
-
openai_sdk_helpers-0.
|
|
94
|
-
openai_sdk_helpers-0.
|
|
95
|
-
openai_sdk_helpers-0.
|
|
94
|
+
openai_sdk_helpers-0.6.1.dist-info/METADATA,sha256=S0KXq5lr2GHbi8uYDac-sn7W4ug5WlIjMqNXjXXHBj0,24622
|
|
95
|
+
openai_sdk_helpers-0.6.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
96
|
+
openai_sdk_helpers-0.6.1.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
|
|
97
|
+
openai_sdk_helpers-0.6.1.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
|
|
98
|
+
openai_sdk_helpers-0.6.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|