openai-sdk-helpers 0.6.1__py3-none-any.whl → 0.6.2__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.
@@ -14,6 +14,7 @@ from .validator import ValidatorAgent
14
14
  from .utils import run_coroutine_agent_sync
15
15
  from .search.vector import VectorAgentSearch
16
16
  from .search.web import WebAgentSearch
17
+ from .files import build_agent_input_messages
17
18
 
18
19
  __all__ = [
19
20
  "AgentBase",
@@ -34,4 +35,5 @@ __all__ = [
34
35
  "ValidatorAgent",
35
36
  "VectorAgentSearch",
36
37
  "WebAgentSearch",
38
+ "build_agent_input_messages",
37
39
  ]
@@ -6,7 +6,7 @@ import logging
6
6
  import traceback
7
7
  import uuid
8
8
  from pathlib import Path
9
- from typing import TYPE_CHECKING, Any, Dict, Optional, Protocol, cast
9
+ from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Protocol, cast
10
10
 
11
11
  from agents import Agent, Handoff, InputGuardrail, OutputGuardrail, Session
12
12
  from agents.model_settings import ModelSettings
@@ -33,6 +33,7 @@ from .runner import run_async, run_sync
33
33
  if TYPE_CHECKING:
34
34
  from ..settings import OpenAISettings
35
35
  from ..response.base import ResponseBase
36
+ from ..files_api import FilePurpose, FilesAPIManager
36
37
 
37
38
 
38
39
  class AgentConfigurationProtocol(Protocol):
@@ -184,6 +185,8 @@ class AgentBase(DataclassJSONSerializable):
184
185
  Return response tool handler and definition for Responses API use.
185
186
  build_response(openai_settings, data_path=None, tool_handlers=None, system_vector_store=None)
186
187
  Build a ResponseBase instance based on this agent.
188
+ build_input_messages(content, files=None, files_manager=None, file_purpose="user_data", image_detail="auto")
189
+ Build Agents SDK input messages with optional file attachments.
187
190
  save_error(exc)
188
191
  Persist error details to a file named with the agent UUID.
189
192
  close()
@@ -467,7 +470,7 @@ class AgentBase(DataclassJSONSerializable):
467
470
 
468
471
  async def run_async(
469
472
  self,
470
- input: str,
473
+ input: str | list[dict[str, Any]],
471
474
  *,
472
475
  context: Optional[Dict[str, Any]] = None,
473
476
  output_structure: Optional[type[StructureBase]] = None,
@@ -477,8 +480,8 @@ class AgentBase(DataclassJSONSerializable):
477
480
 
478
481
  Parameters
479
482
  ----------
480
- input : str
481
- Prompt or query for the agent.
483
+ input : str or list[dict[str, Any]]
484
+ Prompt text or structured input for the agent.
482
485
  context : dict or None, default=None
483
486
  Optional dictionary passed to the agent.
484
487
  output_structure : type[StructureBase] or None, default=None
@@ -522,7 +525,7 @@ class AgentBase(DataclassJSONSerializable):
522
525
 
523
526
  def run_sync(
524
527
  self,
525
- input: str,
528
+ input: str | list[dict[str, Any]],
526
529
  *,
527
530
  context: Optional[Dict[str, Any]] = None,
528
531
  output_structure: Optional[type[StructureBase]] = None,
@@ -532,8 +535,8 @@ class AgentBase(DataclassJSONSerializable):
532
535
 
533
536
  Parameters
534
537
  ----------
535
- input : str
536
- Prompt or query for the agent.
538
+ input : str or list[dict[str, Any]]
539
+ Prompt text or structured input for the agent.
537
540
  context : dict or None, default=None
538
541
  Optional dictionary passed to the agent.
539
542
  output_structure : type[StructureBase] or None, default=None
@@ -660,6 +663,71 @@ class AgentBase(DataclassJSONSerializable):
660
663
  openai_settings=openai_settings,
661
664
  )
662
665
 
666
+ @staticmethod
667
+ def build_input_messages(
668
+ content: str | list[str],
669
+ files: str | list[str] | None = None,
670
+ *,
671
+ files_manager: FilesAPIManager | None = None,
672
+ openai_settings: OpenAISettings | None = None,
673
+ file_purpose: FilePurpose = "user_data",
674
+ image_detail: Literal["low", "high", "auto"] = "auto",
675
+ ) -> list[dict[str, Any]]:
676
+ """Build Agents SDK input messages with file attachments.
677
+
678
+ Parameters
679
+ ----------
680
+ content : str or list[str]
681
+ Prompt text or list of prompt texts to send.
682
+ files : str, list[str], or None, default None
683
+ Optional file path or list of file paths. Image files are sent as
684
+ base64-encoded ``input_image`` entries. Document files are uploaded
685
+ using ``files_manager`` and sent as ``input_file`` entries.
686
+ files_manager : FilesAPIManager or None, default None
687
+ File upload helper used to create file IDs for document uploads.
688
+ Required when ``files`` contains non-image documents.
689
+ openai_settings : OpenAISettings or None, default None
690
+ Optional OpenAI settings used to build a FilesAPIManager when one is
691
+ not provided. When supplied, ``openai_settings.create_client()`` is
692
+ used to initialize the Files API manager.
693
+ file_purpose : FilePurpose, default "user_data"
694
+ Purpose passed to the Files API when uploading document files.
695
+ image_detail : {"low", "high", "auto"}, default "auto"
696
+ Detail hint passed along with base64-encoded image inputs.
697
+
698
+ Returns
699
+ -------
700
+ list[dict[str, Any]]
701
+ Agents SDK input messages that include text and optional file entries.
702
+
703
+ Raises
704
+ ------
705
+ ValueError
706
+ If document files are provided without a ``files_manager``.
707
+
708
+ Examples
709
+ --------
710
+ >>> from openai import OpenAI
711
+ >>> from openai_sdk_helpers.files_api import FilesAPIManager
712
+ >>> client = OpenAI()
713
+ >>> files_manager = FilesAPIManager(client)
714
+ >>> messages = AgentBase.build_input_messages(
715
+ ... "Summarize this document",
716
+ ... files="report.pdf",
717
+ ... files_manager=files_manager,
718
+ ... )
719
+ """
720
+ from .files import build_agent_input_messages
721
+
722
+ return build_agent_input_messages(
723
+ content=content,
724
+ files=files,
725
+ files_manager=files_manager,
726
+ openai_settings=openai_settings,
727
+ file_purpose=file_purpose,
728
+ image_detail=image_detail,
729
+ )
730
+
663
731
  def _build_response_parameters(self) -> dict[str, Any]:
664
732
  """Build the Responses API parameter schema for this agent tool.
665
733
 
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import threading
6
7
  import re
7
8
  from dataclasses import dataclass, field
8
9
  from enum import Enum
@@ -16,6 +17,7 @@ from ..structure import (
16
17
  StructureBase,
17
18
  TaxonomyNode,
18
19
  )
20
+ from ..utils import ensure_list
19
21
  from .base import AgentBase
20
22
  from .configuration import AgentConfiguration
21
23
 
@@ -32,8 +34,12 @@ class TaxonomyClassifierAgent(AgentBase):
32
34
 
33
35
  Methods
34
36
  -------
35
- run_agent(text, taxonomy, context, max_depth)
37
+ run_agent(text, taxonomy, context, max_depth, session)
36
38
  Classify text by recursively walking the taxonomy tree.
39
+ run_async(input, context, max_depth, confidence_threshold, single_class)
40
+ Classify text asynchronously using taxonomy traversal.
41
+ run_sync(input, context, max_depth, confidence_threshold, single_class)
42
+ Classify text synchronously using taxonomy traversal.
37
43
 
38
44
  Examples
39
45
  --------
@@ -93,9 +99,11 @@ class TaxonomyClassifierAgent(AgentBase):
93
99
  text: str,
94
100
  *,
95
101
  context: Optional[Dict[str, Any]] = None,
102
+ file_ids: str | Sequence[str] | None = None,
96
103
  max_depth: Optional[int] = None,
97
104
  confidence_threshold: float | None = None,
98
105
  single_class: bool = False,
106
+ session: Optional[Any] = None,
99
107
  ) -> ClassificationResult:
100
108
  """Classify ``text`` by recursively walking taxonomy levels.
101
109
 
@@ -105,12 +113,16 @@ class TaxonomyClassifierAgent(AgentBase):
105
113
  Source text to classify.
106
114
  context : dict or None, default=None
107
115
  Additional context values to merge into the prompt.
116
+ file_ids : str or Sequence[str] or None, default=None
117
+ Optional file IDs to attach to each classification step.
108
118
  max_depth : int or None, default=None
109
119
  Maximum depth to traverse before stopping.
110
120
  confidence_threshold : float or None, default=None
111
121
  Minimum confidence required to accept a classification step.
112
122
  single_class : bool, default=False
113
123
  Whether to keep only the highest-priority selection per step.
124
+ session : Session or None, default=None
125
+ Optional session for maintaining conversation history across runs.
114
126
 
115
127
  Returns
116
128
  -------
@@ -125,15 +137,18 @@ class TaxonomyClassifierAgent(AgentBase):
125
137
  True
126
138
  """
127
139
  state = _TraversalState()
140
+ input_payload = _build_input_payload(text, file_ids)
128
141
  await self._classify_nodes(
129
- text=text,
142
+ input_payload=input_payload,
130
143
  nodes=list(self._root_nodes),
131
144
  depth=0,
132
145
  parent_path=[],
133
146
  context=context,
147
+ file_ids=file_ids,
134
148
  max_depth=max_depth,
135
149
  confidence_threshold=confidence_threshold,
136
150
  single_class=single_class,
151
+ session=session,
137
152
  state=state,
138
153
  )
139
154
 
@@ -149,37 +164,210 @@ class TaxonomyClassifierAgent(AgentBase):
149
164
  path_nodes=state.path_nodes,
150
165
  )
151
166
 
167
+ async def run_async(
168
+ self,
169
+ input: str | list[dict[str, Any]],
170
+ *,
171
+ context: Optional[Dict[str, Any]] = None,
172
+ output_structure: Optional[type[StructureBase]] = None,
173
+ session: Optional[Any] = None,
174
+ file_ids: str | Sequence[str] | None = None,
175
+ max_depth: Optional[int] = None,
176
+ confidence_threshold: float | None = None,
177
+ single_class: bool = False,
178
+ ) -> ClassificationResult:
179
+ """Classify ``input`` asynchronously with taxonomy traversal.
180
+
181
+ Parameters
182
+ ----------
183
+ input : str or list[dict[str, Any]]
184
+ Source text to classify.
185
+ context : dict or None, default=None
186
+ Additional context values to merge into the prompt.
187
+ output_structure : type[StructureBase] or None, default=None
188
+ Unused in taxonomy traversal. Present for API compatibility.
189
+ session : Session or None, default=None
190
+ Optional session for maintaining conversation history across runs.
191
+ file_ids : str or Sequence[str] or None, default=None
192
+ Optional file IDs to attach to each classification step.
193
+ max_depth : int or None, default=None
194
+ Maximum depth to traverse before stopping.
195
+ confidence_threshold : float or None, default=None
196
+ Minimum confidence required to accept a classification step.
197
+ single_class : bool, default=False
198
+ Whether to keep only the highest-priority selection per step.
199
+
200
+ Returns
201
+ -------
202
+ ClassificationResult
203
+ Structured classification result describing the traversal.
204
+ """
205
+ _ = output_structure
206
+ if not isinstance(input, str):
207
+ msg = "TaxonomyClassifierAgent run_async requires text input."
208
+ raise TypeError(msg)
209
+ kwargs: Dict[str, Any] = {
210
+ "context": context,
211
+ "file_ids": file_ids,
212
+ "max_depth": max_depth,
213
+ "confidence_threshold": confidence_threshold,
214
+ "single_class": single_class,
215
+ }
216
+ if session is not None:
217
+ kwargs["session"] = session
218
+ return await self.run_agent(input, **kwargs)
219
+
220
+ def run_sync(
221
+ self,
222
+ input: str | list[dict[str, Any]],
223
+ *,
224
+ context: Optional[Dict[str, Any]] = None,
225
+ output_structure: Optional[type[StructureBase]] = None,
226
+ session: Optional[Any] = None,
227
+ file_ids: str | Sequence[str] | None = None,
228
+ max_depth: Optional[int] = None,
229
+ confidence_threshold: float | None = None,
230
+ single_class: bool = False,
231
+ ) -> ClassificationResult:
232
+ """Classify ``input`` synchronously with taxonomy traversal.
233
+
234
+ Parameters
235
+ ----------
236
+ input : str or list[dict[str, Any]]
237
+ Source text to classify.
238
+ context : dict or None, default=None
239
+ Additional context values to merge into the prompt.
240
+ output_structure : type[StructureBase] or None, default=None
241
+ Unused in taxonomy traversal. Present for API compatibility.
242
+ session : Session or None, default=None
243
+ Optional session for maintaining conversation history across runs.
244
+ file_ids : str or Sequence[str] or None, default=None
245
+ Optional file IDs to attach to each classification step.
246
+ max_depth : int or None, default=None
247
+ Maximum depth to traverse before stopping.
248
+ confidence_threshold : float or None, default=None
249
+ Minimum confidence required to accept a classification step.
250
+ single_class : bool, default=False
251
+ Whether to keep only the highest-priority selection per step.
252
+
253
+ Returns
254
+ -------
255
+ ClassificationResult
256
+ Structured classification result describing the traversal.
257
+ """
258
+ _ = output_structure
259
+ if not isinstance(input, str):
260
+ msg = "TaxonomyClassifierAgent run_sync requires text input."
261
+ raise TypeError(msg)
262
+ kwargs: Dict[str, Any] = {
263
+ "context": context,
264
+ "file_ids": file_ids,
265
+ "max_depth": max_depth,
266
+ "confidence_threshold": confidence_threshold,
267
+ "single_class": single_class,
268
+ }
269
+ if session is not None:
270
+ kwargs["session"] = session
271
+
272
+ async def runner() -> ClassificationResult:
273
+ return await self.run_agent(input, **kwargs)
274
+
275
+ try:
276
+ asyncio.get_running_loop()
277
+ except RuntimeError:
278
+ return asyncio.run(runner())
279
+
280
+ result: ClassificationResult | None = None
281
+ error: Exception | None = None
282
+
283
+ def _thread_func() -> None:
284
+ nonlocal error, result
285
+ try:
286
+ result = asyncio.run(runner())
287
+ except Exception as exc:
288
+ error = exc
289
+
290
+ thread = threading.Thread(target=_thread_func)
291
+ thread.start()
292
+ thread.join()
293
+
294
+ if error is not None:
295
+ raise error
296
+ if result is None:
297
+ msg = "Classification did not return a result"
298
+ raise RuntimeError(msg)
299
+ return result
300
+
301
+ async def _run_step_async(
302
+ self,
303
+ *,
304
+ input: str | list[dict[str, Any]],
305
+ context: Optional[Dict[str, Any]] = None,
306
+ output_structure: Optional[type[StructureBase]] = None,
307
+ session: Optional[Any] = None,
308
+ ) -> StructureBase:
309
+ """Execute a single classification step asynchronously.
310
+
311
+ Parameters
312
+ ----------
313
+ input : str or list[dict[str, Any]]
314
+ Prompt or structured input for the agent.
315
+ context : dict or None, default=None
316
+ Optional dictionary passed to the agent.
317
+ output_structure : type[StructureBase] or None, default=None
318
+ Optional type used to cast the final output.
319
+ session : Session or None, default=None
320
+ Optional session for maintaining conversation history across runs.
321
+
322
+ Returns
323
+ -------
324
+ StructureBase
325
+ Parsed result for the classification step.
326
+ """
327
+ return await super().run_async(
328
+ input=input,
329
+ context=context,
330
+ output_structure=output_structure,
331
+ session=session,
332
+ )
333
+
152
334
  async def _classify_nodes(
153
335
  self,
154
336
  *,
155
- text: str,
337
+ input_payload: str | list[dict[str, Any]],
156
338
  nodes: list[TaxonomyNode],
157
339
  depth: int,
158
340
  parent_path: list[str],
159
341
  context: Optional[Dict[str, Any]],
342
+ file_ids: str | Sequence[str] | None,
160
343
  max_depth: Optional[int],
161
344
  confidence_threshold: float | None,
162
345
  single_class: bool,
346
+ session: Optional[Any],
163
347
  state: "_TraversalState",
164
348
  ) -> None:
165
349
  """Classify a taxonomy level and recursively traverse children.
166
350
 
167
351
  Parameters
168
352
  ----------
169
- text : str
170
- Source text to classify.
353
+ input_payload : str or list[dict[str, Any]]
354
+ Input payload used to prompt the agent.
171
355
  nodes : list[TaxonomyNode]
172
356
  Candidate taxonomy nodes for the current level.
173
357
  depth : int
174
358
  Current traversal depth.
175
359
  context : dict or None
176
360
  Additional context values to merge into the prompt.
361
+ file_ids : str or Sequence[str] or None
362
+ Optional file IDs attached to each classification step.
177
363
  max_depth : int or None
178
364
  Maximum traversal depth before stopping.
179
365
  confidence_threshold : float or None
180
366
  Minimum confidence required to accept a classification step.
181
367
  single_class : bool
182
368
  Whether to keep only the highest-priority selection per step.
369
+ session : Session or None
370
+ Optional session for maintaining conversation history across runs.
183
371
  state : _TraversalState
184
372
  Aggregated traversal state.
185
373
  """
@@ -197,10 +385,11 @@ class TaxonomyClassifierAgent(AgentBase):
197
385
  context=context,
198
386
  )
199
387
  step_structure = _build_step_structure(list(node_paths.keys()))
200
- raw_step = await self.run_async(
201
- input=text,
388
+ raw_step = await self._run_step_async(
389
+ input=input_payload,
202
390
  context=template_context,
203
391
  output_structure=step_structure,
392
+ session=session,
204
393
  )
205
394
  step = _normalize_step_output(raw_step, step_structure)
206
395
  state.path.append(step)
@@ -242,14 +431,16 @@ class TaxonomyClassifierAgent(AgentBase):
242
431
  (
243
432
  self._classify_subtree(
244
433
  sub_agent=sub_agent,
245
- text=text,
434
+ input_payload=input_payload,
246
435
  nodes=list(node.children),
247
436
  depth=depth + 1,
248
437
  parent_path=[*parent_path, node.label],
249
438
  context=context,
439
+ file_ids=file_ids,
250
440
  max_depth=max_depth,
251
441
  confidence_threshold=confidence_threshold,
252
442
  single_class=single_class,
443
+ session=session,
253
444
  state=sub_state,
254
445
  ),
255
446
  base_final_nodes_len,
@@ -325,21 +516,23 @@ class TaxonomyClassifierAgent(AgentBase):
325
516
  model=self._model,
326
517
  taxonomy=list(nodes),
327
518
  )
328
- sub_agent.run_async = self.run_async
519
+ sub_agent._run_step_async = self._run_step_async
329
520
  return sub_agent
330
521
 
331
522
  async def _classify_subtree(
332
523
  self,
333
524
  *,
334
525
  sub_agent: "TaxonomyClassifierAgent",
335
- text: str,
526
+ input_payload: str | list[dict[str, Any]],
336
527
  nodes: list[TaxonomyNode],
337
528
  depth: int,
338
529
  parent_path: list[str],
339
530
  context: Optional[Dict[str, Any]],
531
+ file_ids: str | Sequence[str] | None,
340
532
  max_depth: Optional[int],
341
533
  confidence_threshold: float | None,
342
534
  single_class: bool,
535
+ session: Optional[Any],
343
536
  state: "_TraversalState",
344
537
  ) -> "_TraversalState":
345
538
  """Classify a taxonomy subtree and return the traversal state.
@@ -348,8 +541,8 @@ class TaxonomyClassifierAgent(AgentBase):
348
541
  ----------
349
542
  sub_agent : TaxonomyClassifierAgent
350
543
  Sub-agent configured for the subtree traversal.
351
- text : str
352
- Source text to classify.
544
+ input_payload : str or list[dict[str, Any]]
545
+ Input payload used to prompt the agent.
353
546
  nodes : list[TaxonomyNode]
354
547
  Candidate taxonomy nodes for the subtree.
355
548
  depth : int
@@ -358,12 +551,16 @@ class TaxonomyClassifierAgent(AgentBase):
358
551
  Path segments leading to the current subtree.
359
552
  context : dict or None
360
553
  Additional context values to merge into the prompt.
554
+ file_ids : str or Sequence[str] or None
555
+ Optional file IDs attached to each classification step.
361
556
  max_depth : int or None
362
557
  Maximum traversal depth before stopping.
363
558
  confidence_threshold : float or None
364
559
  Minimum confidence required to accept a classification step.
365
560
  single_class : bool
366
561
  Whether to keep only the highest-priority selection per step.
562
+ session : Session or None
563
+ Optional session for maintaining conversation history across runs.
367
564
  state : _TraversalState
368
565
  Traversal state to populate for the subtree.
369
566
 
@@ -373,14 +570,16 @@ class TaxonomyClassifierAgent(AgentBase):
373
570
  Populated traversal state for the subtree.
374
571
  """
375
572
  await sub_agent._classify_nodes(
376
- text=text,
573
+ input_payload=input_payload,
377
574
  nodes=nodes,
378
575
  depth=depth,
379
576
  parent_path=parent_path,
380
577
  context=context,
578
+ file_ids=file_ids,
381
579
  max_depth=max_depth,
382
580
  confidence_threshold=confidence_threshold,
383
581
  single_class=single_class,
582
+ session=session,
384
583
  state=state,
385
584
  )
386
585
  return state
@@ -716,6 +915,38 @@ def _normalize_step_output(
716
915
  return ClassificationStep.from_json(payload)
717
916
 
718
917
 
918
+ def _build_input_payload(
919
+ text: str,
920
+ file_ids: str | Sequence[str] | None,
921
+ ) -> str | list[dict[str, Any]]:
922
+ """Build input payloads with optional file attachments.
923
+
924
+ Parameters
925
+ ----------
926
+ text : str
927
+ Prompt text to send to the agent.
928
+ file_ids : str or Sequence[str] or None
929
+ Optional file IDs to include as ``input_file`` attachments.
930
+
931
+ Returns
932
+ -------
933
+ str or list[dict[str, Any]]
934
+ Input payload suitable for the Agents SDK.
935
+ """
936
+ normalized_file_ids = [file_id for file_id in ensure_list(file_ids) if file_id]
937
+ if not normalized_file_ids:
938
+ return text
939
+ attachments = [
940
+ {"type": "input_file", "file_id": file_id} for file_id in normalized_file_ids
941
+ ]
942
+ return [
943
+ {
944
+ "role": "user",
945
+ "content": [{"type": "input_text", "text": text}, *attachments],
946
+ }
947
+ ]
948
+
949
+
719
950
  def _extract_enum_fields(
720
951
  step_structure: type[StructureBase],
721
952
  ) -> dict[str, type[Enum]]:
@@ -13,6 +13,7 @@ from ..utils.json.data_class import DataclassJSONSerializable
13
13
  from ..utils.registry import RegistryBase
14
14
  from ..utils.instructions import resolve_instructions_from_path
15
15
  from ..structure.base import StructureBase
16
+ from ..settings import OpenAISettings
16
17
 
17
18
 
18
19
  class AgentRegistry(RegistryBase["AgentConfiguration"]):
@@ -152,6 +153,8 @@ class AgentConfiguration(DataclassJSONSerializable):
152
153
  Resolve the prompt template path for this configuration.
153
154
  gen_agent(run_context_wrapper)
154
155
  Create a AgentBase instance from this configuration.
156
+ to_openai_settings(dotenv_path=None, **overrides)
157
+ Build OpenAISettings using this configuration as defaults.
155
158
  replace(**changes)
156
159
  Create a new AgentConfiguration with specified fields replaced.
157
160
  to_json()
@@ -272,6 +275,45 @@ class AgentConfiguration(DataclassJSONSerializable):
272
275
  """Resolve instructions from string or file path."""
273
276
  return resolve_instructions_from_path(self.instructions)
274
277
 
278
+ def to_openai_settings(
279
+ self, *, dotenv_path: Path | None = None, **overrides: Any
280
+ ) -> OpenAISettings:
281
+ """Build OpenAI settings using this configuration as defaults.
282
+
283
+ Parameters
284
+ ----------
285
+ dotenv_path : Path or None, optional
286
+ Optional dotenv file path for loading environment variables.
287
+ overrides : Any
288
+ Keyword overrides applied on top of environment values. Use this
289
+ to supply API credentials and override defaults.
290
+
291
+ Returns
292
+ -------
293
+ OpenAISettings
294
+ OpenAI settings instance with defaults derived from this
295
+ configuration.
296
+
297
+ Raises
298
+ ------
299
+ ValueError
300
+ If no API key is supplied via overrides or environment variables.
301
+
302
+ Examples
303
+ --------
304
+ >>> configuration = AgentConfiguration(
305
+ ... name="summarizer",
306
+ ... instructions="Summarize text",
307
+ ... model="gpt-4o-mini",
308
+ ... )
309
+ >>> settings = configuration.to_openai_settings(api_key="sk-...")
310
+ >>> # Or rely on environment variables like OPENAI_API_KEY
311
+ >>> settings = configuration.to_openai_settings()
312
+ """
313
+ if self.model and "default_model" not in overrides:
314
+ overrides["default_model"] = self.model
315
+ return OpenAISettings.from_env(dotenv_path=dotenv_path, **overrides)
316
+
275
317
  def resolve_prompt_path(self, prompt_dir: Path | None = None) -> Path | None:
276
318
  """Resolve the prompt template path for this configuration.
277
319
 
@@ -0,0 +1,120 @@
1
+ """File attachment helpers for the Agents SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Literal
6
+
7
+ from ..files_api import FilePurpose, FilesAPIManager
8
+ from ..settings import OpenAISettings
9
+ from ..utils import create_image_data_url, ensure_list, is_image_file
10
+
11
+
12
+ def build_agent_input_messages(
13
+ content: str | list[str],
14
+ files: str | list[str] | None = None,
15
+ *,
16
+ files_manager: FilesAPIManager | None = None,
17
+ openai_settings: OpenAISettings | None = None,
18
+ file_purpose: FilePurpose = "user_data",
19
+ image_detail: Literal["low", "high", "auto"] = "auto",
20
+ ) -> list[dict[str, Any]]:
21
+ """Build Agents SDK input messages with file attachments.
22
+
23
+ Parameters
24
+ ----------
25
+ content : str or list[str]
26
+ Prompt text or list of prompt texts to send.
27
+ files : str, list[str], or None, default None
28
+ Optional file path or list of file paths. Image files are sent as
29
+ base64-encoded ``input_image`` entries. Document files are uploaded
30
+ using ``files_manager`` and sent as ``input_file`` entries.
31
+ files_manager : FilesAPIManager or None, default None
32
+ File upload helper used to create file IDs for document uploads.
33
+ Required when ``files`` contains non-image documents.
34
+ openai_settings : OpenAISettings or None, default None
35
+ Optional OpenAI settings used to build a FilesAPIManager when one is
36
+ not provided. When supplied, ``openai_settings.create_client()`` is
37
+ used to initialize the Files API manager.
38
+ file_purpose : FilePurpose, default "user_data"
39
+ Purpose passed to the Files API when uploading document files.
40
+ image_detail : {"low", "high", "auto"}, default "auto"
41
+ Detail hint passed along with base64-encoded image inputs.
42
+
43
+ Returns
44
+ -------
45
+ list[dict[str, Any]]
46
+ Agents SDK input messages that include text and optional file entries.
47
+
48
+ Raises
49
+ ------
50
+ ValueError
51
+ If document files are provided without a ``files_manager``.
52
+
53
+ Examples
54
+ --------
55
+ >>> from openai import OpenAI
56
+ >>> from openai_sdk_helpers.files_api import FilesAPIManager
57
+ >>> from openai_sdk_helpers.agent.files import build_agent_input_messages
58
+ >>> client = OpenAI()
59
+ >>> files_manager = FilesAPIManager(client)
60
+ >>> messages = build_agent_input_messages(
61
+ ... "Summarize this document",
62
+ ... files="report.pdf",
63
+ ... files_manager=files_manager,
64
+ ... )
65
+ """
66
+ contents = ensure_list(content)
67
+ all_files = ensure_list(files)
68
+
69
+ image_files: list[str] = []
70
+ document_files: list[str] = []
71
+ for file_path in all_files:
72
+ if is_image_file(file_path):
73
+ image_files.append(file_path)
74
+ else:
75
+ document_files.append(file_path)
76
+
77
+ attachments: list[dict[str, Any]] = []
78
+
79
+ if document_files:
80
+ if files_manager is None and openai_settings is not None:
81
+ files_manager = FilesAPIManager(openai_settings.create_client())
82
+ if files_manager is None:
83
+ raise ValueError(
84
+ "files_manager is required to upload document files for agent input."
85
+ )
86
+ expires_after = 86400 if file_purpose == "user_data" else None
87
+ if hasattr(files_manager, "batch_upload"):
88
+ uploaded_files = files_manager.batch_upload(
89
+ document_files,
90
+ purpose=file_purpose,
91
+ expires_after=expires_after,
92
+ )
93
+ else:
94
+ uploaded_files = [
95
+ files_manager.create(
96
+ file_path, purpose=file_purpose, expires_after=expires_after
97
+ )
98
+ for file_path in document_files
99
+ ]
100
+ for uploaded_file in uploaded_files:
101
+ attachments.append({"type": "input_file", "file_id": uploaded_file.id})
102
+
103
+ for image_path in image_files:
104
+ image_url, detail = create_image_data_url(image_path, detail=image_detail)
105
+ attachments.append(
106
+ {"type": "input_image", "image_url": image_url, "detail": detail}
107
+ )
108
+
109
+ messages: list[dict[str, Any]] = []
110
+ for index, raw_content in enumerate(contents):
111
+ text = raw_content.strip()
112
+ content_items: list[dict[str, Any]] = [{"type": "input_text", "text": text}]
113
+ if index == 0:
114
+ content_items.extend(attachments)
115
+ messages.append({"role": "user", "content": content_items})
116
+
117
+ return messages
118
+
119
+
120
+ __all__ = ["build_agent_input_messages"]
@@ -7,7 +7,7 @@ signatures whether they need asynchronous or synchronous results.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from typing import Any, Dict, Optional
10
+ from typing import Any, Dict, Optional, cast
11
11
 
12
12
  from agents import Agent, RunResult, Runner, Session
13
13
 
@@ -17,7 +17,7 @@ from ..structure.base import StructureBase
17
17
 
18
18
  async def run_async(
19
19
  agent: Agent,
20
- input: str,
20
+ input: str | list[dict[str, Any]],
21
21
  *,
22
22
  context: Optional[Dict[str, Any]] = None,
23
23
  output_structure: Optional[type[StructureBase]] = None,
@@ -29,8 +29,8 @@ async def run_async(
29
29
  ----------
30
30
  agent : Agent
31
31
  Configured agent instance to execute.
32
- input : str
33
- Prompt or query string for the agent.
32
+ input : str or list[dict[str, Any]]
33
+ Prompt text or structured input for the agent.
34
34
  context : dict or None, default=None
35
35
  Optional context dictionary passed to the agent.
36
36
  output_structure : type[StructureBase] or None, default=None
@@ -53,7 +53,7 @@ async def run_async(
53
53
  ... return result
54
54
  >>> asyncio.run(example()) # doctest: +SKIP
55
55
  """
56
- result = await Runner.run(agent, input, context=context, session=session)
56
+ result = await Runner.run(agent, cast(Any, input), context=context, session=session)
57
57
  if output_structure is not None:
58
58
  return result.final_output_as(output_structure)
59
59
  return result
@@ -61,7 +61,7 @@ async def run_async(
61
61
 
62
62
  def run_sync(
63
63
  agent: Agent,
64
- input: str,
64
+ input: str | list[dict[str, Any]],
65
65
  *,
66
66
  context: Optional[Dict[str, Any]] = None,
67
67
  output_structure: Optional[type[StructureBase]] = None,
@@ -77,8 +77,8 @@ def run_sync(
77
77
  ----------
78
78
  agent : Agent
79
79
  Configured agent instance to execute.
80
- input : str
81
- Prompt or query string for the agent.
80
+ input : str or list[dict[str, Any]]
81
+ Prompt text or structured input for the agent.
82
82
  context : dict or None, default=None
83
83
  Optional context dictionary passed to the agent.
84
84
  output_structure : type[StructureBase] or None, default=None
@@ -102,7 +102,7 @@ def run_sync(
102
102
  >>> agent = Agent(name="test", instructions="test", model="gpt-4o-mini")
103
103
  >>> result = run_sync(agent, "What is 2+2?") # doctest: +SKIP
104
104
  """
105
- coro = Runner.run(agent, input, context=context, session=session)
105
+ coro = Runner.run(agent, cast(Any, input), context=context, session=session)
106
106
  result: RunResult = run_coroutine_with_fallback(coro)
107
107
  if output_structure is not None:
108
108
  return result.final_output_as(output_structure)
@@ -138,7 +138,7 @@ class TranslatorAgent(AgentBase):
138
138
 
139
139
  def run_sync(
140
140
  self,
141
- input: str,
141
+ input: str | list[dict[str, Any]],
142
142
  *,
143
143
  context: Optional[Dict[str, Any]] = None,
144
144
  output_structure: Optional[type[StructureBase]] = None,
@@ -149,7 +149,7 @@ class TranslatorAgent(AgentBase):
149
149
 
150
150
  Parameters
151
151
  ----------
152
- input : str
152
+ input : str or list[dict[str, Any]]
153
153
  Source content to translate.
154
154
  context : dict or None, default=None
155
155
  Additional context values to merge into the prompt.
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
 
13
13
  import logging
14
14
  from pathlib import Path
15
- from typing import Any, BinaryIO, Literal, cast
15
+ from typing import Any, BinaryIO, Literal, Sequence, cast
16
16
 
17
17
  from openai import OpenAI, NOT_GIVEN
18
18
  from openai.types import FileDeleted, FileObject
@@ -62,6 +62,8 @@ class FilesAPIManager:
62
62
  Delete a specific file.
63
63
  retrieve_content(file_id)
64
64
  Download file content.
65
+ batch_upload(files, purpose, track, expires_after)
66
+ Upload multiple files to the Files API.
65
67
  cleanup()
66
68
  Delete all tracked files.
67
69
 
@@ -350,6 +352,49 @@ class FilesAPIManager:
350
352
  """
351
353
  return self._client.files.content(file_id).read()
352
354
 
355
+ def batch_upload(
356
+ self,
357
+ files: Sequence[BinaryIO | Path | str],
358
+ purpose: FilePurpose,
359
+ track: bool | None = None,
360
+ expires_after: int | None = None,
361
+ ) -> list[FileObject]:
362
+ """Upload multiple files to the OpenAI Files API.
363
+
364
+ Parameters
365
+ ----------
366
+ files : Sequence[BinaryIO | Path | str]
367
+ File-like objects or file paths to upload.
368
+ purpose : FilePurpose
369
+ The intended purpose of the uploaded files.
370
+ track : bool or None, default None
371
+ Override auto_track for these uploads. If None, uses instance setting.
372
+ expires_after : int or None, default None
373
+ Number of seconds after which files expire. See ``create`` for details.
374
+
375
+ Returns
376
+ -------
377
+ list[FileObject]
378
+ Uploaded file objects in the same order as ``files``.
379
+
380
+ Examples
381
+ --------
382
+ >>> files = ["doc1.pdf", "doc2.pdf"]
383
+ >>> uploaded = manager.batch_upload(files, purpose="user_data")
384
+ >>> [file.id for file in uploaded]
385
+ """
386
+ if not files:
387
+ return []
388
+ return [
389
+ self.create(
390
+ file_path,
391
+ purpose=purpose,
392
+ track=track,
393
+ expires_after=expires_after,
394
+ )
395
+ for file_path in files
396
+ ]
397
+
353
398
  def cleanup(self) -> dict[str, bool]:
354
399
  """Delete all tracked files.
355
400
 
@@ -5,12 +5,28 @@ Instructions:
5
5
  - Populate selected_nodes as a list of taxonomy node ids for multi-class matches.
6
6
  - Use selected_node when a single best match is appropriate.
7
7
  - Provide a confidence score between 0 and 1 for the selections; higher means more certain.
8
+ - Interpret confidence as:
9
+ - 0.90–1.00: explicit lexical match.
10
+ - 0.70–0.89: strong semantic alignment.
11
+ - 0.40–0.69: weak or ambiguous alignment.
12
+ - <0.40: low-confidence inference.
8
13
  - Use only taxonomy identifiers from the candidate list for any selections.
9
14
  - Use the stop_reason enum values only: "continue", "stop", "no_match", "max_depth", "no_children".
10
- - If a child level should be explored, set stop_reason to "continue".
11
- - If no appropriate node exists, set stop_reason to "no_match" and leave selections empty.
12
- - If you are confident this is the final level, set stop_reason to "stop".
13
- - Provide a concise rationale in one or two sentences.
15
+ - Stop reason semantics:
16
+ - continue: valid match exists and deeper traversal is required.
17
+ - stop: low confidence, terminate to avoid false precision.
18
+ - no_match: no semantic fit in candidates.
19
+ - max_depth: taxonomy depth limit reached.
20
+ - no_children: matched node has no children.
21
+ - Decision mapping:
22
+ - High or medium confidence with children available: continue.
23
+ - High confidence with terminal node: no_children.
24
+ - Low confidence match: stop.
25
+ - No semantic alignment: no_match.
26
+ - Depth limit reached: max_depth.
27
+ - Provide a concise rationale in one sentence.
28
+ - Keep rationale evidence-based and avoid restating taxonomy labels.
29
+ - Avoid verbosity, speculation, stylistic language, narrative explanation, redundancy, or creativity.
14
30
 
15
31
  Current depth: {{ depth }}
16
32
 
@@ -80,8 +80,10 @@ from .classification import (
80
80
  ClassificationResult,
81
81
  ClassificationStep,
82
82
  ClassificationStopReason,
83
+ Taxonomy,
83
84
  TaxonomyNode,
84
85
  flatten_taxonomy,
86
+ taxonomy_enum_path,
85
87
  )
86
88
  from .extraction import (
87
89
  AnnotatedDocumentStructure,
@@ -108,8 +110,10 @@ __all__ = [
108
110
  "ClassificationResult",
109
111
  "ClassificationStep",
110
112
  "ClassificationStopReason",
113
+ "Taxonomy",
111
114
  "TaxonomyNode",
112
115
  "flatten_taxonomy",
116
+ "taxonomy_enum_path",
113
117
  "TaskStructure",
114
118
  "PlanStructure",
115
119
  "create_plan",
@@ -115,6 +115,48 @@ class TaxonomyNode(StructureBase):
115
115
  )
116
116
 
117
117
 
118
+ class Taxonomy(StructureBase):
119
+ """Represent a taxonomy with metadata and root nodes.
120
+
121
+ Attributes
122
+ ----------
123
+ name : str
124
+ Human-readable taxonomy name.
125
+ description : str | None
126
+ Optional description of the taxonomy.
127
+ nodes : list[TaxonomyNode]
128
+ Root taxonomy nodes.
129
+
130
+ Methods
131
+ -------
132
+ flattened_nodes
133
+ Return a flattened list of all taxonomy nodes.
134
+ """
135
+
136
+ name: str = spec_field("name", description="Human-readable taxonomy name.")
137
+ description: str | None = spec_field(
138
+ "description",
139
+ description="Optional description of the taxonomy.",
140
+ default=None,
141
+ )
142
+ nodes: list[TaxonomyNode] = spec_field(
143
+ "nodes",
144
+ description="Root taxonomy nodes.",
145
+ default_factory=list,
146
+ )
147
+
148
+ @property
149
+ def flattened_nodes(self) -> list[TaxonomyNode]:
150
+ """Return a flattened list of all taxonomy nodes.
151
+
152
+ Returns
153
+ -------
154
+ list[TaxonomyNode]
155
+ Depth-first list of taxonomy nodes.
156
+ """
157
+ return flatten_taxonomy(self.nodes)
158
+
159
+
118
160
  def _split_path_identifier(path: str) -> list[str]:
119
161
  """Split a path identifier into label segments.
120
162
 
@@ -444,10 +486,42 @@ def flatten_taxonomy(nodes: Iterable[TaxonomyNode]) -> list[TaxonomyNode]:
444
486
  return flattened
445
487
 
446
488
 
489
+ def taxonomy_enum_path(value: Enum | str | None) -> list[str]:
490
+ """Return the taxonomy path segments for an enum value.
491
+
492
+ Parameters
493
+ ----------
494
+ value : Enum or str or None
495
+ Enum member or path identifier string to split. If None, return an
496
+ empty list.
497
+
498
+ Returns
499
+ -------
500
+ list[str]
501
+ Path segments extracted from the taxonomy identifier.
502
+
503
+ Examples
504
+ --------
505
+ >>> StepEnum = Enum("StepEnum", {"ROOT_LEAF": "Root > Leaf"})
506
+ >>> taxonomy_enum_path(StepEnum.ROOT_LEAF)
507
+ ['Root', 'Leaf']
508
+ """
509
+ if value is None:
510
+ return []
511
+ normalized_value = _normalize_enum_value(value)
512
+ if not normalized_value:
513
+ return []
514
+ if not isinstance(normalized_value, str):
515
+ normalized_value = str(normalized_value)
516
+ return _split_path_identifier(normalized_value)
517
+
518
+
447
519
  __all__ = [
448
520
  "ClassificationResult",
449
521
  "ClassificationStep",
450
522
  "ClassificationStopReason",
523
+ "Taxonomy",
451
524
  "TaxonomyNode",
452
525
  "flatten_taxonomy",
526
+ "taxonomy_enum_path",
453
527
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openai-sdk-helpers
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
5
5
  Author: openai-sdk-helpers maintainers
6
6
  License: MIT
@@ -2,20 +2,21 @@ openai_sdk_helpers/__init__.py,sha256=8I469KuzrbAjhNX2A5UnYt_kSmjXqQbfHectTeUx7T
2
2
  openai_sdk_helpers/cli.py,sha256=BDc08NqWVfL4GBekxMfN5IPPB4pmN1Od9sVpKtIJRZk,8025
3
3
  openai_sdk_helpers/environment.py,sha256=mNoswzIdv37tTRhFwA2B6_Onxsm7vhfjPArfwhYuL7g,1825
4
4
  openai_sdk_helpers/errors.py,sha256=ZclLp94o08fSsFNjFn_yrX9yTjw1RE0v7A5T1hBChUc,2925
5
- openai_sdk_helpers/files_api.py,sha256=Sg-k4YDsrzggvICYA7h4Ua6_vGhMpZmAeS5JtQVE2hU,12598
5
+ openai_sdk_helpers/files_api.py,sha256=kn-A2pwiNkxMd035PkWDLi_EWzccuEnGyMpLQcY-aVY,14086
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
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=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
14
- openai_sdk_helpers/agent/configuration.py,sha256=FU3xnb8-8qoezLW47WwxZg7z2AxNXRW1Svl0FMsk8kc,14244
11
+ openai_sdk_helpers/agent/__init__.py,sha256=qyzKzPhD8KsEl6d79XERK32AK5It_BZNOqChOpBdmhg,1199
12
+ openai_sdk_helpers/agent/base.py,sha256=vLs0oALhxsd_Xy5dGjSZTUFTug-YwZkF1LabQ2ruLxk,29508
13
+ openai_sdk_helpers/agent/classifier.py,sha256=GWgjQxkh1QbZhKlcDCkj-aNgpa8seJWxTfbtXyQSkSg,34889
14
+ openai_sdk_helpers/agent/configuration.py,sha256=ZeH4ErgVe-BZamjUeNONbQi60ViolgYAWh-c8hNAQTw,15810
15
15
  openai_sdk_helpers/agent/coordinator.py,sha256=lVjA0yI-GhGKlqbNR_k9GOCrUjFoZ0QoqRaafHckyME,18052
16
- openai_sdk_helpers/agent/runner.py,sha256=l2NPS9VA9d4RISuBfanFfKxXNYSHQ7MTjRsuzx4APls,3473
16
+ openai_sdk_helpers/agent/files.py,sha256=H7UfSZSjFUbv1cjRvNld9kZwIjc5wPq4vynqU8HgGJE,4478
17
+ openai_sdk_helpers/agent/runner.py,sha256=uNf8FiLIlZsbSvE-CopYhv5sPAyxU2te0OaBBxO9RWY,3613
17
18
  openai_sdk_helpers/agent/summarizer.py,sha256=-yVm-KdTvGRXGj1MlEikTAFYVlPoovLNIL3Tc_WYIzs,3653
18
- openai_sdk_helpers/agent/translator.py,sha256=6Gj1cqT-W5j32F14sY9kOCFQenq_odceu2fi8hud_Z0,5970
19
+ openai_sdk_helpers/agent/translator.py,sha256=Skke5wyZTpo_9gMcwHRyoBQl00zTBeXnIUujUIr2ZDE,6017
19
20
  openai_sdk_helpers/agent/utils.py,sha256=DTD5foCqGYfXf13F2bZMYIQROl7SbDSy5GDPGi0Zl-0,1089
20
21
  openai_sdk_helpers/agent/validator.py,sha256=krktzjaHhEprn76F7hD4cH6H2CwucmFN1KWJ_vjl01g,4774
21
22
  openai_sdk_helpers/agent/search/__init__.py,sha256=LXXzEcX2MU7_htHRdRCGPw0hsr9CrZn0ESii7GZJMBw,806
@@ -29,7 +30,7 @@ openai_sdk_helpers/extract/extractor.py,sha256=vmRJyhKDEYAVfRk0KMgLH5hTqUfDAUyWB
29
30
  openai_sdk_helpers/extract/generator.py,sha256=K9Euq0IaWs82oe5aRm73_18DelLKYyuH8VhfZ1_ZCEU,14695
30
31
  openai_sdk_helpers/prompt/__init__.py,sha256=MOqgKwG9KLqKudoKRlUfLxiSmdOi2aD6hNrWDFqLHkk,418
31
32
  openai_sdk_helpers/prompt/base.py,sha256=6X0zeopEvO0ba8207O8Nnj1QvFZEZier7kNNh4qkcmE,7782
32
- openai_sdk_helpers/prompt/classifier.jinja,sha256=PgJ8tvnuOcEa4DGbOqIrEyrG0GJ26bBpTZ7FlRZoL-s,1239
33
+ openai_sdk_helpers/prompt/classifier.jinja,sha256=6od2DyyEUUrT0AmeJfJ57gJxJ6gdbPc11vff-VNywNk,1895
33
34
  openai_sdk_helpers/prompt/extractor_config_agent_instructions.jinja,sha256=vCrsoUnsgHWSr7OS_ojMUjmPtHfbyv9bzKfaMaCJ99E,329
34
35
  openai_sdk_helpers/prompt/extractor_config_generator.jinja,sha256=9rZ1PZdoQtnxDxFUlKRb0SooIEfNw4_Em99n9xvFyyU,960
35
36
  openai_sdk_helpers/prompt/extractor_config_generator_instructions.jinja,sha256=GqV3DrGObyER_Fa-GMGGqhWBrQIH9FFlyKdgTjidyzg,534
@@ -54,10 +55,10 @@ openai_sdk_helpers/response/vector_store.py,sha256=HClp6O_g20uklQTY7trC4age3rtDm
54
55
  openai_sdk_helpers/streamlit_app/__init__.py,sha256=3yAkl6qV71cqtT5YFZuC9Bkqit0NtffDV6jmMWpT1k4,812
55
56
  openai_sdk_helpers/streamlit_app/app.py,sha256=kkjtdCKVwrJ9nZWuBArm3dhvcjMESX0TMqAiF61_JLM,17402
56
57
  openai_sdk_helpers/streamlit_app/configuration.py,sha256=0KeJ4HqCNFthBHsedV6ptqHluAcTPBb5_TujFOGkIUU,16685
57
- openai_sdk_helpers/structure/__init__.py,sha256=-_bEFvvKhg99bgsMnimpxx7RpLQpQyReSMquOc-2Ts8,4173
58
+ openai_sdk_helpers/structure/__init__.py,sha256=ErtNlTADV4cc7s27i_CbQATd2PD9xcJd8_D273QmyOI,4253
58
59
  openai_sdk_helpers/structure/agent_blueprint.py,sha256=VyJWkgPNzAYKRDMeR1M4kE6qqQURnwqtrrEn0TRJf0g,9698
59
60
  openai_sdk_helpers/structure/base.py,sha256=UrnNNU9qQ9mEES8MB9y6QESbDgPXH47XW8LVWSxYUYM,25280
60
- openai_sdk_helpers/structure/classification.py,sha256=q7d9x2Ya7ICBr6rk5SOSrQrW5lDLat345wHQisKZO7Y,13351
61
+ openai_sdk_helpers/structure/classification.py,sha256=Vk7LGG3pty5T0Eh94Pao7kWY8_Wcuw37ywdPDcnElrg,15316
61
62
  openai_sdk_helpers/structure/extraction.py,sha256=wODP0iLAhhsdQkMWRYPYTiLUMU8bFMKiBjPl3PKUleg,37335
62
63
  openai_sdk_helpers/structure/prompt.py,sha256=ZfsaHdA0hj5zmZDrOdpXjCsC8U-jjzwFG4JBsWYiaH4,1535
63
64
  openai_sdk_helpers/structure/responses.py,sha256=WUwh0DhXj24pkvgqH1FMkdx5V2ArdvdtrDN_fuMBtDU,4882
@@ -91,8 +92,8 @@ openai_sdk_helpers/vector_storage/__init__.py,sha256=L5LxO09puh9_yBB9IDTvc1CvVkA
91
92
  openai_sdk_helpers/vector_storage/cleanup.py,sha256=sZ4ZSTlnjF52o9Cc8A9dTX37ZYXXDxS_fdIpoOBWvrg,3666
92
93
  openai_sdk_helpers/vector_storage/storage.py,sha256=t_ukacaXRa9EXE4-3BxsrB4Rjhu6nTu7NA9IjCJBIpQ,24259
93
94
  openai_sdk_helpers/vector_storage/types.py,sha256=jTCcOYMeOpZWvcse0z4T3MVs-RBOPC-fqWTBeQrgafU,1639
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,,
95
+ openai_sdk_helpers-0.6.2.dist-info/METADATA,sha256=TGZjA_nQ2FDm9KeEjun4MrIAUl-zAxB-Xi5UCUkn8nY,24622
96
+ openai_sdk_helpers-0.6.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
97
+ openai_sdk_helpers-0.6.2.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
98
+ openai_sdk_helpers-0.6.2.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
99
+ openai_sdk_helpers-0.6.2.dist-info/RECORD,,