openai-sdk-helpers 0.0.7__py3-none-any.whl → 0.0.8__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.
@@ -3,10 +3,10 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  # Standard library imports
6
+ import ast
6
7
  import inspect
7
8
  import json
8
9
  import logging
9
- from abc import ABC, abstractmethod
10
10
  from enum import Enum
11
11
  from pathlib import Path
12
12
  from collections.abc import Mapping, Sequence
@@ -570,6 +570,45 @@ class BaseStructure(BaseModel):
570
570
 
571
571
  return cls(**clean_data)
572
572
 
573
+ @classmethod
574
+ def from_tool_arguments(cls: Type[T], arguments: str) -> T:
575
+ """Parse tool call arguments which may not be valid JSON.
576
+
577
+ The OpenAI API is expected to return well-formed JSON for tool arguments,
578
+ but minor formatting issues (such as the use of single quotes) can occur.
579
+ This helper first tries ``json.loads`` and falls back to
580
+ ``ast.literal_eval`` for simple cases.
581
+
582
+ Parameters
583
+ ----------
584
+ arguments
585
+ Raw argument string from the tool call.
586
+
587
+ Returns
588
+ -------
589
+ dict
590
+ Parsed dictionary of arguments.
591
+
592
+ Raises
593
+ ------
594
+ ValueError
595
+ If the arguments cannot be parsed as JSON.
596
+
597
+ Examples
598
+ --------
599
+ >>> parse_tool_arguments('{"key": "value"}')["key"]
600
+ 'value'
601
+ """
602
+ try:
603
+ structured_data = json.loads(arguments)
604
+
605
+ except json.JSONDecodeError:
606
+ try:
607
+ structured_data = ast.literal_eval(arguments)
608
+ except Exception as exc: # noqa: BLE001
609
+ raise ValueError(f"Invalid JSON arguments: {arguments}") from exc
610
+ return cls.from_raw_input(structured_data)
611
+
573
612
  @staticmethod
574
613
  def format_output(label: str, value: Any) -> str:
575
614
  """
@@ -44,3 +44,7 @@ class WebSearchStructure(BaseStructure):
44
44
  "web_search_results"
45
45
  )
46
46
  web_search_report: WebSearchReportStructure = spec_field("web_search_report")
47
+
48
+ def print(self) -> str:
49
+ """Return the markdown report."""
50
+ return self.web_search_report.markdown_report
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  from .core import (
6
6
  JSONSerializable,
7
7
  check_filepath,
8
+ coerce_jsonable,
8
9
  coerce_dict,
9
10
  coerce_optional_float,
10
11
  coerce_optional_int,
@@ -19,6 +20,7 @@ __all__ = [
19
20
  "coerce_optional_float",
20
21
  "coerce_optional_int",
21
22
  "coerce_dict",
23
+ "coerce_jsonable",
22
24
  "JSONSerializable",
23
25
  "customJSONEncoder",
24
26
  "log",
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import logging
7
+ import ast
7
8
  from dataclasses import asdict, is_dataclass
8
9
  from datetime import datetime
9
10
  from enum import Enum
@@ -195,6 +196,38 @@ def _to_jsonable(value: Any) -> Any:
195
196
  return value
196
197
 
197
198
 
199
+ def coerce_jsonable(value: Any) -> Any:
200
+ """Convert ``value`` into a JSON-serializable representation.
201
+
202
+ Parameters
203
+ ----------
204
+ value : Any
205
+ Object to convert into a JSON-friendly structure.
206
+
207
+ Returns
208
+ -------
209
+ Any
210
+ JSON-serializable representation of ``value``.
211
+ """
212
+ from openai_sdk_helpers.response.base import BaseResponse
213
+ from openai_sdk_helpers.structure.base import BaseStructure
214
+
215
+ if value is None:
216
+ return None
217
+ if isinstance(value, BaseStructure):
218
+ return value.model_dump()
219
+ if isinstance(value, BaseResponse):
220
+ return coerce_jsonable(value.messages.to_json())
221
+ if is_dataclass(value) and not isinstance(value, type):
222
+ return {key: coerce_jsonable(item) for key, item in asdict(value).items()}
223
+ coerced = _to_jsonable(value)
224
+ try:
225
+ json.dumps(coerced)
226
+ return coerced
227
+ except TypeError:
228
+ return str(coerced)
229
+
230
+
198
231
  class customJSONEncoder(json.JSONEncoder):
199
232
  """Encode common helper types like enums and paths.
200
233
 
@@ -294,6 +327,7 @@ def log(message: str, level: int = logging.INFO) -> None:
294
327
  __all__ = [
295
328
  "ensure_list",
296
329
  "check_filepath",
330
+ "coerce_jsonable",
297
331
  "JSONSerializable",
298
332
  "customJSONEncoder",
299
333
  "log",
@@ -199,20 +199,19 @@ class VectorStorage:
199
199
 
200
200
  Parameters
201
201
  ----------
202
- file_path
202
+ file_path : str
203
203
  Local path to the file to upload.
204
- purpose
205
- Purpose of the file (for example ``"assistants"``). Default
206
- ``"assistants"``.
207
- attributes
204
+ purpose : str, default "assistants"
205
+ Purpose of the file (for example ``"assistants"``).
206
+ attributes : dict or None, default None
208
207
  Custom attributes to associate with the file. The ``file_name``
209
- attribute is added automatically. Default ``None``.
210
- overwrite
208
+ attribute is added automatically.
209
+ overwrite : bool, default False
211
210
  When ``True``, re-upload even if a file with the same name already
212
- exists. Default ``False``.
213
- refresh_cache
211
+ exists.
212
+ refresh_cache : bool, default False
214
213
  When ``True``, refresh the local cache of existing files before
215
- checking for duplicates. Default ``False``.
214
+ checking for duplicates.
216
215
 
217
216
  Returns
218
217
  -------
@@ -284,16 +283,16 @@ class VectorStorage:
284
283
 
285
284
  Parameters
286
285
  ----------
287
- file_patterns
286
+ file_patterns : str or list of str
288
287
  Glob pattern or list of patterns (for example
289
288
  ``'/path/to/files/**/*.txt'``).
290
- purpose
291
- Purpose assigned to uploaded files. Default ``"assistants"``.
292
- attributes
293
- Custom attributes to associate with each file. Default ``None``.
294
- overwrite
289
+ purpose : str, default "assistants"
290
+ Purpose assigned to uploaded files.
291
+ attributes : dict or None, default None
292
+ Custom attributes to associate with each file.
293
+ overwrite : bool, default False
295
294
  When ``True``, re-upload files even if files with the same name
296
- already exist. Default ``False``.
295
+ already exist.
297
296
 
298
297
  Returns
299
298
  -------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openai-sdk-helpers
3
- Version: 0.0.7
3
+ Version: 0.0.8
4
4
  Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
5
5
  Author: openai-sdk-helpers maintainers
6
6
  License: MIT
@@ -11,6 +11,7 @@ Requires-Dist: openai
11
11
  Requires-Dist: openai-agents
12
12
  Requires-Dist: pydantic<3,>=2.7
13
13
  Requires-Dist: python-dotenv
14
+ Requires-Dist: streamlit
14
15
  Requires-Dist: typing-extensions<5,>=4.15.0
15
16
  Description-Content-Type: text/markdown
16
17
 
@@ -1,9 +1,9 @@
1
- openai_sdk_helpers/__init__.py,sha256=aqesJ3gPruETXtksvQga-iNJYBQZG6TY2YGK7iNOY6g,1324
1
+ openai_sdk_helpers/__init__.py,sha256=510VjcPPtGcjEQuhkAswEi7guNFhBHBpaPuuFzAO3RA,1592
2
2
  openai_sdk_helpers/config.py,sha256=OH--g7Xp4ftucA2C4o6FCX0M9Z15KMRpkY0lpn0mmOI,6455
3
3
  openai_sdk_helpers/environment.py,sha256=t_AFP6OXjRBoIQVZdgjqZzcUWB-FDeYn4KzKn5FgrnY,693
4
4
  openai_sdk_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  openai_sdk_helpers/agent/__init__.py,sha256=1sRtu_TbnKR7EstzZjoi2OUOk0xJOTn4xbo5ZeoPIhk,825
6
- openai_sdk_helpers/agent/base.py,sha256=JHJnI7nW6e6l_FrEVoyHjFd_agE5CAM_E8rUPMrlZsk,10053
6
+ openai_sdk_helpers/agent/base.py,sha256=P6FYmXssJduFvLaupde0H6lXIe0IJyDZGfEPOHAlMxA,10060
7
7
  openai_sdk_helpers/agent/config.py,sha256=IZDF83f_QT-1-3GdTVrn9cQCoaaH4KNcrO-ocfc-LwY,1925
8
8
  openai_sdk_helpers/agent/project_manager.py,sha256=uYCZyAG8_Snxef4mv5ax-nI_XVvRPUh43I0pY_AdiiU,16249
9
9
  openai_sdk_helpers/agent/prompt_utils.py,sha256=8uCm08YuJ94rKgBuIkio2O4EpbwDmTXNfgeddbih8JA,228
@@ -13,39 +13,43 @@ openai_sdk_helpers/agent/translator.py,sha256=Cj3eJ2IakX2UqSeDotgqpbmM89FekpYt3G
13
13
  openai_sdk_helpers/agent/utils.py,sha256=DTD5foCqGYfXf13F2bZMYIQROl7SbDSy5GDPGi0Zl-0,1089
14
14
  openai_sdk_helpers/agent/validation.py,sha256=omKfbClYdPQxxn9WKlw33s42AkudeFw54DmgGSe2UhQ,3216
15
15
  openai_sdk_helpers/agent/vector_search.py,sha256=pf_kIFl_TK4ZXvTcZzNqXxZuyq4QfF4ncDluAp4nj0c,15529
16
- openai_sdk_helpers/agent/web_search.py,sha256=VCsMN75XlwrifqOVMSDYxkrLJ2oJl-yInMdMtx6Puqo,12147
16
+ openai_sdk_helpers/agent/web_search.py,sha256=mAtUoXSULn5p1Et6XrGptdZHBlBPNMXnSaTx8pSRsfs,12155
17
17
  openai_sdk_helpers/enums/__init__.py,sha256=HhzM9YVDqPijpnKzA-qnzbX62104FrGDcnN-cEYMD_w,149
18
18
  openai_sdk_helpers/enums/base.py,sha256=dBrzbIA3Ft2Jy-1PhMImEQeDwH0FXIMGHdg68DsG7WE,697
19
19
  openai_sdk_helpers/prompt/__init__.py,sha256=Pio9s99ej0ior5gKr8m-hSUgqkBOgFdNu1xofvjPEf8,2275
20
20
  openai_sdk_helpers/prompt/summarizer.jinja,sha256=jliSetWDISbql1EkWi1RB8-L_BXUg8JMkRRsPRHuzbY,309
21
21
  openai_sdk_helpers/prompt/translator.jinja,sha256=SZhW8ipEzM-9IA4wyS_r2wIMTAclWrilmk1s46njoL0,291
22
22
  openai_sdk_helpers/prompt/validator.jinja,sha256=6t8q_IdxFd3mVBGX6SFKNOert1Wo3YpTOji2SNEbbtE,547
23
- openai_sdk_helpers/response/__init__.py,sha256=LOCBPGe--iKHHCU1WVcljXV5tLFFRdv1dTJZeip7gc8,505
24
- openai_sdk_helpers/response/base.py,sha256=vOibHp9xQiC4Nu-kNJ8GutRCwBPAtShgybf9_T_lHWk,19593
25
- openai_sdk_helpers/response/messages.py,sha256=Ot432B9qbbvinGG0aO6mWYeeEUSVqmLiNlvulKbUlZQ,6487
26
- openai_sdk_helpers/response/runner.py,sha256=OD-lNgpuhBULKS9-fyYAicKONdx_Tk48qGOzVBmG00s,2536
27
- openai_sdk_helpers/response/tool_call.py,sha256=kYUfkjmkLbEJun_QByMuAvYjdixwoRAjHNy2Sk_riXA,1937
28
- openai_sdk_helpers/response/vector_store.py,sha256=wCPPppzCQ-PYSS4T2QHqDUHcPMYNlQFeV-Pu33KBRy8,2418
23
+ openai_sdk_helpers/response/__init__.py,sha256=TSTewIzMyAkR7kcxZlZ7-v3KXpDD2JBC6xG3eYa67zQ,505
24
+ openai_sdk_helpers/response/base.py,sha256=tCWRcBhNIRUz77HWxHRdCPFuywbUKCYa7ac-TvxNWiI,22593
25
+ openai_sdk_helpers/response/messages.py,sha256=O6c2E8Q6cm1nE4McPevvqcxa4kUFd5pL2MuUHtOVqsY,7917
26
+ openai_sdk_helpers/response/runner.py,sha256=xCiZ1-1kGLmVuDzX31zrx7snNrbQfn7OS-BYN-XG0es,2536
27
+ openai_sdk_helpers/response/tool_call.py,sha256=5ZZLyblNe35kRZ3_0JgGASS92nlT2xAxvCsncAss_xg,2960
28
+ openai_sdk_helpers/response/vector_store.py,sha256=T1xiev85xv0C9f5t25ss8HUfir0c9zLPwXk3C1qAel0,2418
29
+ openai_sdk_helpers/streamlit_app/__init__.py,sha256=RNcbMPaIERdFQ4wh_td3EjS6cJ_72eMBP-Ti7SVeiwY,261
30
+ openai_sdk_helpers/streamlit_app/app.py,sha256=o-0Zh9lR_-ubOQX79sfA-6rFxdxhGWlRzOazmECxomE,8066
31
+ openai_sdk_helpers/streamlit_app/configuration.py,sha256=KUo4E1yTSyuI9MV17Lw8_FP6OhEqS-zv2HdsGk9bCQA,10340
32
+ openai_sdk_helpers/streamlit_app/streamlit_web_search.py,sha256=1eUCYFh0b_LnWb6HSBMztt1h92TF3fTW_InUNMOPkG8,2480
29
33
  openai_sdk_helpers/structure/__init__.py,sha256=GBD48p3M9wnOPmEO9t9t5XuiMQedmDBClKmjDLEjcUo,1129
30
34
  openai_sdk_helpers/structure/agent_blueprint.py,sha256=opL-dER3a_f_JWC3Jx9ovRdbC4XZe9X20-o1YUq9sgw,7569
31
- openai_sdk_helpers/structure/base.py,sha256=FJvB-HedXG02VJEEgymMd2adcJCwugdGHidj4ne7phU,22975
35
+ openai_sdk_helpers/structure/base.py,sha256=0OZao5cenz52AKoMLjLO8f_it_5Nm38FPvO8GGyMzNA,24170
32
36
  openai_sdk_helpers/structure/prompt.py,sha256=Yovho9WA1AZP1FhKBieBpVThrUn62g4k40mxNrBoY9s,582
33
37
  openai_sdk_helpers/structure/responses.py,sha256=KivhRltUlrK8ey9Tk9rDNceHb7uC2gNE38iQJXFOxug,3507
34
38
  openai_sdk_helpers/structure/summary.py,sha256=zYRKuBjZHz0GvLRofvJdfD9u101xKgVhFc5CZIlscUE,1682
35
39
  openai_sdk_helpers/structure/validation.py,sha256=IdlPb3I1PdCah7kciE8iDRZy_ltk5GSXQyRJUufz7K0,1405
36
40
  openai_sdk_helpers/structure/vector_search.py,sha256=M3TQwxOg9mJmZcLgx7UhZkclnbdcH2K_N-XxUU9Eoxo,2457
37
- openai_sdk_helpers/structure/web_search.py,sha256=XGJS5S-a0t62k7y8r65JzCEdIQh_5dr10EPT-k134Ys,1371
41
+ openai_sdk_helpers/structure/web_search.py,sha256=6RA0gS8tAe_8zBMA1IS-YLNoGzLFmvS0YG0OwfUGo7Y,1496
38
42
  openai_sdk_helpers/structure/plan/__init__.py,sha256=OVTGp0MAb8RLjE7TZk5zoXjXIih7zzfwPYIyO7CCwVM,261
39
43
  openai_sdk_helpers/structure/plan/enum.py,sha256=EYGdUckSUSOXQCTIbD8RhSQNylgVTVvOnb7za6fv6_A,1772
40
44
  openai_sdk_helpers/structure/plan/plan.py,sha256=33qBu-yzFEpYHVsvGiGMsdZphYpOD7eT5AjNQzt5cmo,7480
41
45
  openai_sdk_helpers/structure/plan/task.py,sha256=Qn-GXV0VuOYA-EHXSC6tQlcXObKMeV3-TQhgeepl2L8,3481
42
- openai_sdk_helpers/utils/__init__.py,sha256=JRmAwQz2qE0bNhshAq5HAlXjYMyE5OqLl-vOKcD6MZY,463
43
- openai_sdk_helpers/utils/core.py,sha256=mKCkGE1cC06ZcOip70eiA8rJ4jaRmnGm4zJfwDPLkQM,8161
46
+ openai_sdk_helpers/utils/__init__.py,sha256=54_AalcYtv3cgkg86yvHLe2cVuSEYizehf6arv37JJQ,507
47
+ openai_sdk_helpers/utils/core.py,sha256=1Q8zaOkuorbj3tYcbM0iIjhURKJpD0xl6rEaXjI-080,9132
44
48
  openai_sdk_helpers/vector_storage/__init__.py,sha256=BjUueFnxmF4T6YOCra2nqa8rEAzsihEYWavkYB7S_lM,384
45
49
  openai_sdk_helpers/vector_storage/cleanup.py,sha256=6e_A9MAOKhJl_9EbRgGiB0NrrN79IwN0mMnHrwp4gd8,2964
46
- openai_sdk_helpers/vector_storage/storage.py,sha256=-Yk9RwzG6ABkhH1p3Y-6tv5sGu2MdxHvwkxEtB9N9_c,19295
50
+ openai_sdk_helpers/vector_storage/storage.py,sha256=alOetHIJUrZ6hjP3Q_3A-g5ROraw7FXJOWhOSdNorOA,19345
47
51
  openai_sdk_helpers/vector_storage/types.py,sha256=9u5oBxKTDf_ljvbWhp1dWVW1zrlVwLd4OpikygvlKJI,1298
48
- openai_sdk_helpers-0.0.7.dist-info/METADATA,sha256=zYMBq4ke7ex0StA0Q4ddjD4GAsx9cI8oEWTXpZOV1SY,6557
49
- openai_sdk_helpers-0.0.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
50
- openai_sdk_helpers-0.0.7.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
51
- openai_sdk_helpers-0.0.7.dist-info/RECORD,,
52
+ openai_sdk_helpers-0.0.8.dist-info/METADATA,sha256=OWSkOhsK10d3ko-ItS9O47OTtJDDS6QUgIGiBvXeKFg,6582
53
+ openai_sdk_helpers-0.0.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
54
+ openai_sdk_helpers-0.0.8.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
55
+ openai_sdk_helpers-0.0.8.dist-info/RECORD,,