openai-sdk-helpers 0.0.9__py3-none-any.whl → 0.1.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.
Files changed (46) hide show
  1. openai_sdk_helpers/__init__.py +63 -5
  2. openai_sdk_helpers/agent/base.py +5 -1
  3. openai_sdk_helpers/agent/coordination.py +4 -5
  4. openai_sdk_helpers/agent/runner.py +4 -1
  5. openai_sdk_helpers/agent/search/base.py +1 -0
  6. openai_sdk_helpers/agent/search/vector.py +2 -0
  7. openai_sdk_helpers/cli.py +265 -0
  8. openai_sdk_helpers/config.py +120 -31
  9. openai_sdk_helpers/context_manager.py +1 -1
  10. openai_sdk_helpers/deprecation.py +167 -0
  11. openai_sdk_helpers/environment.py +3 -2
  12. openai_sdk_helpers/errors.py +0 -12
  13. openai_sdk_helpers/logging_config.py +24 -95
  14. openai_sdk_helpers/prompt/base.py +56 -6
  15. openai_sdk_helpers/response/__init__.py +5 -2
  16. openai_sdk_helpers/response/base.py +84 -115
  17. openai_sdk_helpers/response/config.py +142 -0
  18. openai_sdk_helpers/response/messages.py +1 -0
  19. openai_sdk_helpers/response/tool_call.py +15 -4
  20. openai_sdk_helpers/retry.py +1 -1
  21. openai_sdk_helpers/streamlit_app/app.py +14 -3
  22. openai_sdk_helpers/streamlit_app/streamlit_web_search.py +15 -8
  23. openai_sdk_helpers/structure/__init__.py +3 -0
  24. openai_sdk_helpers/structure/base.py +6 -6
  25. openai_sdk_helpers/structure/plan/__init__.py +15 -1
  26. openai_sdk_helpers/structure/plan/helpers.py +173 -0
  27. openai_sdk_helpers/structure/plan/plan.py +13 -9
  28. openai_sdk_helpers/structure/plan/task.py +7 -7
  29. openai_sdk_helpers/structure/plan/types.py +15 -0
  30. openai_sdk_helpers/tools.py +296 -0
  31. openai_sdk_helpers/utils/__init__.py +82 -31
  32. openai_sdk_helpers/{async_utils.py → utils/async_utils.py} +5 -6
  33. openai_sdk_helpers/utils/coercion.py +138 -0
  34. openai_sdk_helpers/utils/deprecation.py +167 -0
  35. openai_sdk_helpers/utils/json_utils.py +98 -0
  36. openai_sdk_helpers/utils/output_validation.py +448 -0
  37. openai_sdk_helpers/utils/path_utils.py +46 -0
  38. openai_sdk_helpers/{validation.py → utils/validation.py} +7 -3
  39. openai_sdk_helpers/vector_storage/storage.py +9 -6
  40. {openai_sdk_helpers-0.0.9.dist-info → openai_sdk_helpers-0.1.1.dist-info}/METADATA +59 -3
  41. openai_sdk_helpers-0.1.1.dist-info/RECORD +76 -0
  42. openai_sdk_helpers-0.1.1.dist-info/entry_points.txt +2 -0
  43. openai_sdk_helpers/utils/core.py +0 -468
  44. openai_sdk_helpers-0.0.9.dist-info/RECORD +0 -66
  45. {openai_sdk_helpers-0.0.9.dist-info → openai_sdk_helpers-0.1.1.dist-info}/WHEEL +0 -0
  46. {openai_sdk_helpers-0.0.9.dist-info → openai_sdk_helpers-0.1.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,76 @@
1
+ openai_sdk_helpers/__init__.py,sha256=7UoioqeijT413TbjSjiAl64vKgJcQkY067OEpSDTdbU,4532
2
+ openai_sdk_helpers/cli.py,sha256=J62XKPkGgYzYHKHfnkFy53Dp4rvBXf9cPEl1hrev3ZU,7400
3
+ openai_sdk_helpers/config.py,sha256=pjBzjYM9Fs4DQqwio387lBt_4IwWKct_VNZBSe-bMqg,10972
4
+ openai_sdk_helpers/context_manager.py,sha256=QqlrtenwKoz2krY0IzuToKdTX1HptUYtIEylxieybgY,6633
5
+ openai_sdk_helpers/deprecation.py,sha256=VF0VDDegawYhsu5f-vE6dop9ob-jv8egxsm0KsPvP9E,4753
6
+ openai_sdk_helpers/environment.py,sha256=RBYpRFamclaom07msipJ7jnnPkfVqjl1PRhDE5phZdg,1401
7
+ openai_sdk_helpers/errors.py,sha256=0TLrcpRXPBvk2KlrU5I1VAQl-sYy-d15h_SMDkEawvI,2757
8
+ openai_sdk_helpers/logging_config.py,sha256=JcR0FTWht1tYdwD-bXH835pr0JV0RwHfY3poruiZGHM,795
9
+ openai_sdk_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ openai_sdk_helpers/retry.py,sha256=J10oQYphfzDXm3BnLoXwxk7PAhN93TC2LQOv0VDGOwI,6533
11
+ openai_sdk_helpers/tools.py,sha256=C2xl0euovFyrDVh0qf1pEyuaicmrTmoZcJu9CxCKqic,9534
12
+ openai_sdk_helpers/types.py,sha256=xzldCRfwCZ3rZl18IBmfgA-PVdoZKSWNrlSIhirumSo,1451
13
+ openai_sdk_helpers/agent/__init__.py,sha256=giowU8jke0z0h7FFUG9V6Vssja8AYwvJMQbiMb3s64k,960
14
+ openai_sdk_helpers/agent/base.py,sha256=8ZkW57vL8_fYzuLr6f9kMvBChYq5lN5vQ8MMJtcWD9s,11784
15
+ openai_sdk_helpers/agent/config.py,sha256=htqy5bcrJeMf3rIpRdL9CKlYwyQI4po420rcgR3i8XI,1971
16
+ openai_sdk_helpers/agent/coordination.py,sha256=knhQtOyQGGkqKb6Q-pWSRwrVW0qJcVvxelinIctNs-A,16152
17
+ openai_sdk_helpers/agent/prompt_utils.py,sha256=-1M66tqQxh9wWCFg6X-K7cCcqauca3yA04ZjvOpN3bA,337
18
+ openai_sdk_helpers/agent/runner.py,sha256=1_azIWx1Bcy7RRlEbizTD0LXBdYgof_tYMpDUcnJJuM,4164
19
+ openai_sdk_helpers/agent/summarizer.py,sha256=fH8AnYK_68ERf2U7mv0nwXL8KyhrluE-TDY_M5TCdD0,3266
20
+ openai_sdk_helpers/agent/translator.py,sha256=GhUuwFTBecgOO9pMQ41VPvK9mTub5DXJ_7BIS9Xp7bs,5082
21
+ openai_sdk_helpers/agent/utils.py,sha256=DTD5foCqGYfXf13F2bZMYIQROl7SbDSy5GDPGi0Zl-0,1089
22
+ openai_sdk_helpers/agent/validation.py,sha256=JIYVhBTTs0tTxYyzYgY3BHC-9psyzE3LLQDZDqpg13M,4191
23
+ openai_sdk_helpers/agent/search/__init__.py,sha256=xqosfzH4HcBs9IFZks9msG_694rS5q6Ea4_qNeRQRmU,798
24
+ openai_sdk_helpers/agent/search/base.py,sha256=EP4WCIC-IItToTFVRVpg1pj1PC5QtqheIiK1l087yRg,8613
25
+ openai_sdk_helpers/agent/search/vector.py,sha256=xMWhuRQENdWfLN1NTBzEjMfq1WsaGS6yn70-Xq9oFj4,13622
26
+ openai_sdk_helpers/agent/search/web.py,sha256=8le4xnZ3nllySqWb7rZaOq44ZR8q67c_WiE57ncmL90,10014
27
+ openai_sdk_helpers/enums/__init__.py,sha256=aFf79C4JBeLC3kMlJfSpehyjx5uNCtW6eK5rD6ZFfhM,322
28
+ openai_sdk_helpers/enums/base.py,sha256=cNllDtzcgI0_eZYXxFko14yhxwicX6xbeDfz9gFE3qo,2753
29
+ openai_sdk_helpers/prompt/__init__.py,sha256=MOqgKwG9KLqKudoKRlUfLxiSmdOi2aD6hNrWDFqLHkk,418
30
+ openai_sdk_helpers/prompt/base.py,sha256=o-O5S-et4mE30_LkFPzL3o67Z_3KrLFG55gQDlL4vqE,7575
31
+ openai_sdk_helpers/prompt/summarizer.jinja,sha256=jliSetWDISbql1EkWi1RB8-L_BXUg8JMkRRsPRHuzbY,309
32
+ openai_sdk_helpers/prompt/translator.jinja,sha256=SZhW8ipEzM-9IA4wyS_r2wIMTAclWrilmk1s46njoL0,291
33
+ openai_sdk_helpers/prompt/validator.jinja,sha256=6t8q_IdxFd3mVBGX6SFKNOert1Wo3YpTOji2SNEbbtE,547
34
+ openai_sdk_helpers/response/__init__.py,sha256=eoQF086o3OZYmVfJWXhSpYlPhQBb-VLDA5hvw7guLEc,1741
35
+ openai_sdk_helpers/response/base.py,sha256=zxQQRKmmpzYPmw0aqIgwKry713gYmMLkA8jhSKIoyHY,26207
36
+ openai_sdk_helpers/response/config.py,sha256=WheEWkTxNFHL54_yvFY3M0LclNmajwTiMftSFeAH2eI,10300
37
+ openai_sdk_helpers/response/messages.py,sha256=G4V8a9gis4b8wFW5XnvBE0AHMX0FrkOzqiQ6FxigpnU,9145
38
+ openai_sdk_helpers/response/runner.py,sha256=Rf13cQGsR7sN9gA81Y5th1tfH2DCCAwQ6RMs3bVgjnk,4269
39
+ openai_sdk_helpers/response/tool_call.py,sha256=VYPvKUR-Ren0Y_nYS4jUSinhTyXKzFwQLxu-d3r_YuM,4506
40
+ openai_sdk_helpers/response/vector_store.py,sha256=MyHUu6P9ueNsd9erbBkyVqq3stLK6qVuehdvmFAHq9E,3074
41
+ openai_sdk_helpers/streamlit_app/__init__.py,sha256=RjJbnBDS5_YmAmxvaa3phB5u9UcXsXDEk_jMlY_pa5Q,793
42
+ openai_sdk_helpers/streamlit_app/app.py,sha256=MBMtzZk3ywEccLHfy3K--pmKNGTBHw_PpQjIBeXzqtI,11099
43
+ openai_sdk_helpers/streamlit_app/config.py,sha256=EK6LWACo7YIkDko1oesvupOx56cTuWWnwnXRiu8EYbs,15986
44
+ openai_sdk_helpers/streamlit_app/streamlit_web_search.py,sha256=0RjB545dIvEeZiiLWM7C4CufbD3DITOWLZEVgxAL6mo,2812
45
+ openai_sdk_helpers/structure/__init__.py,sha256=QUvRdJMbKsumjwJdWq9ihfcOED4ZbJMBQbmA1nmYJVw,3339
46
+ openai_sdk_helpers/structure/agent_blueprint.py,sha256=2W-RBM5G3ZefMcYHqqoV6Y1witcSbMlUpdU1CA9n3tg,9698
47
+ openai_sdk_helpers/structure/base.py,sha256=i937ZjMqTcdFd8UQXcA1sv-Lz1WJZlweGd-qLdD8TQE,28322
48
+ openai_sdk_helpers/structure/prompt.py,sha256=7DBdLu6WDvXy2RkEBayDiX2Jn8T4-hJuohsOaKEoqJs,1075
49
+ openai_sdk_helpers/structure/responses.py,sha256=iYJBT_4VFifzQqPnTpRWTcB0o7xkhPIQ2ugedivrpto,4868
50
+ openai_sdk_helpers/structure/summary.py,sha256=MyZzMuqHP9F8B4rYYxCGJwojy5RavWUkMiRZ6yMQzvU,3143
51
+ openai_sdk_helpers/structure/validation.py,sha256=vsilA3Qs3fjWLeYlnZnMEGj9i_bOJtXc2J3mSIEHncg,2409
52
+ openai_sdk_helpers/structure/vector_search.py,sha256=A0w2AR0r6aIFoYbNkscUAGT7VzTe6WuvxrqUsWT2PMQ,5782
53
+ openai_sdk_helpers/structure/web_search.py,sha256=S8OdllBWqEGXaKf6Alocl89ZuG7BlvXK5ra1Lm7lfjE,4572
54
+ openai_sdk_helpers/structure/plan/__init__.py,sha256=IGr0Tk4inN_8o7fT2N02_FTi6U6l2T9_npcQHAlBwKA,1076
55
+ openai_sdk_helpers/structure/plan/enum.py,sha256=seESSwH-IeeW-9BqIMUQyk3qjtchfU3TDhF9HPDB1OM,3079
56
+ openai_sdk_helpers/structure/plan/helpers.py,sha256=Vc6dBTMFrNWlsaCTpEImEIKjfFq4BSSxNjB4K8dywOQ,5139
57
+ openai_sdk_helpers/structure/plan/plan.py,sha256=LtfwWwZiHGe06nFCXSbT8p3x3w9hhI0wXS7hTeeWXvY,9663
58
+ openai_sdk_helpers/structure/plan/task.py,sha256=R2MInXiOWvs5zFGVOfAhVivRxXWTBp8NrmVpZ7aUmM8,4580
59
+ openai_sdk_helpers/structure/plan/types.py,sha256=7y9QEVdZreQUXV7n-R4RoNZzw5HeOVbJGWx9QkSfuNY,418
60
+ openai_sdk_helpers/utils/__init__.py,sha256=N4jHd0QXaqU7aDBYraRoXas-MG1_CKm8uU1HdPVDS_k,2875
61
+ openai_sdk_helpers/utils/async_utils.py,sha256=9KbPEVfi6IXdbwkTUE0h5DleK8TI7I6P_VPL8UgUv98,3689
62
+ openai_sdk_helpers/utils/coercion.py,sha256=Pq1u7tAbD7kTZ84lK-7Fb9CyYKKKQt4fypG5BlSI6oQ,3774
63
+ openai_sdk_helpers/utils/deprecation.py,sha256=VF0VDDegawYhsu5f-vE6dop9ob-jv8egxsm0KsPvP9E,4753
64
+ openai_sdk_helpers/utils/json_utils.py,sha256=dpv0IPZp4WKL7HsDAQY2za820ukn0cre6kAv-pYw7P0,3141
65
+ openai_sdk_helpers/utils/output_validation.py,sha256=O9Adt-fxL5DtnMd1GuZ9E2YxX3yj4uzSZuBNKVH2GkI,12152
66
+ openai_sdk_helpers/utils/path_utils.py,sha256=qGGDpuDnY5EODOACzH23MYECQOE2rKhrQ3sbDvefwEg,1307
67
+ openai_sdk_helpers/utils/validation.py,sha256=ZjnZNOy5AoFlszRxarNol6YZwfgw6LnwPtkCekZmwAU,7826
68
+ openai_sdk_helpers/vector_storage/__init__.py,sha256=L5LxO09puh9_yBB9IDTvc1CvVkARVkHqYY1KX3inB4c,975
69
+ openai_sdk_helpers/vector_storage/cleanup.py,sha256=ImWIE-9lli-odD8qIARvmeaa0y8ZD4pYYP-kT0O3178,3552
70
+ openai_sdk_helpers/vector_storage/storage.py,sha256=pRUPssHH_o-ydijGW8U9XC2Lu06HEO0KnrNd3X9_Qc0,21807
71
+ openai_sdk_helpers/vector_storage/types.py,sha256=jTCcOYMeOpZWvcse0z4T3MVs-RBOPC-fqWTBeQrgafU,1639
72
+ openai_sdk_helpers-0.1.1.dist-info/METADATA,sha256=tFCRcJgKKEpRRDYFVYUSHwJ7GBKVtnK2h7x8MzopFMU,20927
73
+ openai_sdk_helpers-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
74
+ openai_sdk_helpers-0.1.1.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
75
+ openai_sdk_helpers-0.1.1.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
76
+ openai_sdk_helpers-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ openai-helpers = openai_sdk_helpers.cli:main
@@ -1,468 +0,0 @@
1
- """Core utility helpers for openai-sdk-helpers.
2
-
3
- This module provides foundational utility functions for type coercion,
4
- file path validation, JSON serialization, and logging. These utilities
5
- support consistent data handling across the package.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import json
11
- import logging
12
- import ast
13
- from collections.abc import Iterable, Mapping
14
- from dataclasses import asdict, is_dataclass
15
- from datetime import datetime
16
- from enum import Enum
17
- from pathlib import Path
18
- from typing import Any, TypeVar
19
-
20
-
21
- def coerce_optional_float(value: object) -> float | None:
22
- """Return a float when the provided value can be coerced, otherwise None.
23
-
24
- Handles float, int, and string inputs. Empty strings or None return None.
25
-
26
- Parameters
27
- ----------
28
- value : object
29
- Value to convert into a float. Strings must be parseable as floats.
30
-
31
- Returns
32
- -------
33
- float or None
34
- Converted float value or None if the input is None.
35
-
36
- Raises
37
- ------
38
- ValueError
39
- If a non-empty string cannot be converted to a float.
40
- TypeError
41
- If the value is not a float-compatible type.
42
-
43
- Examples
44
- --------
45
- >>> coerce_optional_float(3.14)
46
- 3.14
47
- >>> coerce_optional_float("2.5")
48
- 2.5
49
- >>> coerce_optional_float(None) is None
50
- True
51
- """
52
- if value is None:
53
- return None
54
- if isinstance(value, (float, int)):
55
- return float(value)
56
- if isinstance(value, str) and value.strip():
57
- try:
58
- return float(value)
59
- except ValueError as exc:
60
- raise ValueError("timeout must be a float-compatible value") from exc
61
- raise TypeError("timeout must be a float, int, str, or None")
62
-
63
-
64
- def coerce_optional_int(value: object) -> int | None:
65
- """Return an int when the provided value can be coerced, otherwise None.
66
-
67
- Handles int, float (if whole number), and string inputs. Empty strings
68
- or None return None. Booleans are not considered valid integers.
69
-
70
- Parameters
71
- ----------
72
- value : object
73
- Value to convert into an int. Strings must be parseable as integers.
74
-
75
- Returns
76
- -------
77
- int or None
78
- Converted integer value or None if the input is None.
79
-
80
- Raises
81
- ------
82
- ValueError
83
- If a non-empty string cannot be converted to an integer.
84
- TypeError
85
- If the value is not an int-compatible type.
86
-
87
- Examples
88
- --------
89
- >>> coerce_optional_int(42)
90
- 42
91
- >>> coerce_optional_int("100")
92
- 100
93
- >>> coerce_optional_int(3.0)
94
- 3
95
- >>> coerce_optional_int(None) is None
96
- True
97
- """
98
- if value is None:
99
- return None
100
- if isinstance(value, int) and not isinstance(value, bool):
101
- return value
102
- if isinstance(value, float) and value.is_integer():
103
- return int(value)
104
- if isinstance(value, str) and value.strip():
105
- try:
106
- return int(value)
107
- except ValueError as exc:
108
- raise ValueError("max_retries must be an int-compatible value") from exc
109
- raise TypeError("max_retries must be an int, str, or None")
110
-
111
-
112
- def coerce_dict(value: object) -> dict[str, Any]:
113
- """Return a string-keyed dictionary built from value if possible.
114
-
115
- Converts Mapping objects to dictionaries. None returns an empty dict.
116
-
117
- Parameters
118
- ----------
119
- value : object
120
- Mapping-like value to convert. None yields an empty dictionary.
121
-
122
- Returns
123
- -------
124
- dict[str, Any]
125
- Dictionary representation of value.
126
-
127
- Raises
128
- ------
129
- TypeError
130
- If the value cannot be treated as a mapping.
131
-
132
- Examples
133
- --------
134
- >>> coerce_dict({"a": 1})
135
- {'a': 1}
136
- >>> coerce_dict(None)
137
- {}
138
- """
139
- if value is None:
140
- return {}
141
- if isinstance(value, Mapping):
142
- return dict(value)
143
- raise TypeError("extra_client_kwargs must be a mapping or None")
144
-
145
-
146
- T = TypeVar("T")
147
- _configured_logging = False
148
-
149
-
150
- def ensure_list(value: Iterable[T] | T | None) -> list[T]:
151
- """Normalize a single item or iterable into a list.
152
-
153
- Converts None to empty list, tuples to lists, and wraps single
154
- items in a list.
155
-
156
- Parameters
157
- ----------
158
- value : Iterable[T] | T | None
159
- Item or iterable to wrap. None yields an empty list.
160
-
161
- Returns
162
- -------
163
- list[T]
164
- Normalized list representation of value.
165
-
166
- Examples
167
- --------
168
- >>> ensure_list(None)
169
- []
170
- >>> ensure_list(5)
171
- [5]
172
- >>> ensure_list([1, 2, 3])
173
- [1, 2, 3]
174
- >>> ensure_list(("a", "b"))
175
- ['a', 'b']
176
- """
177
- if value is None:
178
- return []
179
- if isinstance(value, list):
180
- return value
181
- if isinstance(value, tuple):
182
- return list(value)
183
- return [value] # type: ignore[list-item]
184
-
185
-
186
- def check_filepath(
187
- filepath: Path | None = None, *, fullfilepath: str | None = None
188
- ) -> Path:
189
- """Ensure the parent directory for a file path exists.
190
-
191
- Creates parent directories as needed. Exactly one of filepath or
192
- fullfilepath must be provided.
193
-
194
- Parameters
195
- ----------
196
- filepath : Path or None, optional
197
- Path object to validate. Mutually exclusive with fullfilepath.
198
- fullfilepath : str or None, optional
199
- String path to validate. Mutually exclusive with filepath.
200
-
201
- Returns
202
- -------
203
- Path
204
- Path object representing the validated file path.
205
-
206
- Raises
207
- ------
208
- ValueError
209
- If neither filepath nor fullfilepath is provided.
210
-
211
- Examples
212
- --------
213
- >>> from pathlib import Path
214
- >>> path = check_filepath(filepath=Path("/tmp/test.txt"))
215
- >>> isinstance(path, Path)
216
- True
217
- """
218
- if filepath is None and fullfilepath is None:
219
- raise ValueError("filepath or fullfilepath is required.")
220
- if fullfilepath is not None:
221
- target = Path(fullfilepath)
222
- elif filepath is not None:
223
- target = Path(filepath)
224
- else:
225
- raise ValueError("filepath or fullfilepath is required.")
226
- target.parent.mkdir(parents=True, exist_ok=True)
227
- return target
228
-
229
-
230
- def _to_jsonable(value: Any) -> Any:
231
- """Convert common helper types to JSON-serializable forms.
232
-
233
- Handles Enum, Path, datetime, dataclasses, Pydantic models, dicts,
234
- lists, tuples, and sets.
235
-
236
- Parameters
237
- ----------
238
- value : Any
239
- Value to convert.
240
-
241
- Returns
242
- -------
243
- Any
244
- A JSON-safe representation of value.
245
-
246
- Notes
247
- -----
248
- This is an internal helper function. Use coerce_jsonable for public API.
249
- """
250
- if value is None:
251
- return None
252
- if isinstance(value, Enum):
253
- return value.value
254
- if isinstance(value, Path):
255
- return str(value)
256
- if isinstance(value, datetime):
257
- return value.isoformat()
258
- if is_dataclass(value) and not isinstance(value, type):
259
- return {k: _to_jsonable(v) for k, v in asdict(value).items()}
260
- if hasattr(value, "model_dump"):
261
- model_dump = getattr(value, "model_dump")
262
- return model_dump()
263
- if isinstance(value, dict):
264
- return {str(k): _to_jsonable(v) for k, v in value.items()}
265
- if isinstance(value, (list, tuple, set)):
266
- return [_to_jsonable(v) for v in value]
267
- return value
268
-
269
-
270
- def coerce_jsonable(value: Any) -> Any:
271
- """Convert value into a JSON-serializable representation.
272
-
273
- Handles BaseStructure, BaseResponse, dataclasses, and other complex
274
- types by recursively converting them to JSON-compatible forms.
275
-
276
- Parameters
277
- ----------
278
- value : Any
279
- Object to convert into a JSON-friendly structure.
280
-
281
- Returns
282
- -------
283
- Any
284
- JSON-serializable representation of value.
285
-
286
- Examples
287
- --------
288
- >>> from datetime import datetime
289
- >>> result = coerce_jsonable({"date": datetime(2024, 1, 1)})
290
- >>> isinstance(result, dict)
291
- True
292
- """
293
- from openai_sdk_helpers.response.base import BaseResponse
294
- from openai_sdk_helpers.structure.base import BaseStructure
295
-
296
- if value is None:
297
- return None
298
- if isinstance(value, BaseStructure):
299
- return value.model_dump()
300
- if isinstance(value, BaseResponse):
301
- return coerce_jsonable(value.messages.to_json())
302
- if is_dataclass(value) and not isinstance(value, type):
303
- return {key: coerce_jsonable(item) for key, item in asdict(value).items()}
304
- coerced = _to_jsonable(value)
305
- try:
306
- json.dumps(coerced)
307
- return coerced
308
- except TypeError:
309
- return str(coerced)
310
-
311
-
312
- class customJSONEncoder(json.JSONEncoder):
313
- """JSON encoder for common helper types like enums and paths.
314
-
315
- Extends json.JSONEncoder to handle Enum, Path, datetime, dataclasses,
316
- and Pydantic models automatically.
317
-
318
- Methods
319
- -------
320
- default(o)
321
- Return a JSON-serializable representation of o.
322
-
323
- Examples
324
- --------
325
- >>> import json
326
- >>> from pathlib import Path
327
- >>> json.dumps({"path": Path("/tmp")}, cls=customJSONEncoder)
328
- '{"path": "/tmp"}'
329
- """
330
-
331
- def default(self, o: Any) -> Any:
332
- """Return a JSON-serializable representation of o.
333
-
334
- Called by the json module when the default serialization fails.
335
- Delegates to _to_jsonable for type-specific conversions.
336
-
337
- Parameters
338
- ----------
339
- o : Any
340
- Object to serialize.
341
-
342
- Returns
343
- -------
344
- Any
345
- JSON-safe representation of o.
346
- """
347
- return _to_jsonable(o)
348
-
349
-
350
- class JSONSerializable:
351
- """Mixin for classes that can be serialized to JSON.
352
-
353
- Provides to_json() and to_json_file() methods for any class. Works
354
- with dataclasses, Pydantic models, and regular classes with __dict__.
355
-
356
- Methods
357
- -------
358
- to_json()
359
- Return a JSON-compatible dict representation of the instance.
360
- to_json_file(filepath)
361
- Write serialized JSON data to a file path.
362
-
363
- Examples
364
- --------
365
- >>> from dataclasses import dataclass
366
- >>> @dataclass
367
- ... class MyClass(JSONSerializable):
368
- ... value: int
369
- >>> obj = MyClass(value=42)
370
- >>> obj.to_json()
371
- {'value': 42}
372
- """
373
-
374
- def to_json(self) -> dict[str, Any]:
375
- """Return a JSON-compatible dict representation.
376
-
377
- Automatically handles dataclasses, Pydantic models, and objects
378
- with __dict__ attributes.
379
-
380
- Returns
381
- -------
382
- dict[str, Any]
383
- Mapping with only JSON-serializable values.
384
-
385
- Examples
386
- --------
387
- >>> obj = JSONSerializable()
388
- >>> result = obj.to_json()
389
- >>> isinstance(result, dict)
390
- True
391
- """
392
- if is_dataclass(self) and not isinstance(self, type):
393
- return {k: _to_jsonable(v) for k, v in asdict(self).items()}
394
- if hasattr(self, "model_dump"):
395
- model_dump = getattr(self, "model_dump")
396
- return _to_jsonable(model_dump())
397
- return _to_jsonable(self.__dict__)
398
-
399
- def to_json_file(self, filepath: str | Path) -> str:
400
- """Write serialized JSON data to a file path.
401
-
402
- Creates parent directories as needed. Uses customJSONEncoder for
403
- handling special types.
404
-
405
- Parameters
406
- ----------
407
- filepath : str | Path
408
- Destination file path. Parent directories are created as needed.
409
-
410
- Returns
411
- -------
412
- str
413
- String representation of the file path written.
414
-
415
- Examples
416
- --------
417
- >>> obj = JSONSerializable()
418
- >>> path = obj.to_json_file("/tmp/output.json") # doctest: +SKIP
419
- """
420
- target = Path(filepath)
421
- check_filepath(fullfilepath=str(target))
422
- with open(target, "w", encoding="utf-8") as handle:
423
- json.dump(
424
- self.to_json(),
425
- handle,
426
- indent=2,
427
- ensure_ascii=False,
428
- cls=customJSONEncoder,
429
- )
430
- return str(target)
431
-
432
-
433
- def log(message: str, level: int = logging.INFO) -> None:
434
- """Log a message with a basic configuration.
435
-
436
- Configures logging on first use with a simple timestamp format.
437
- Subsequent calls use the existing configuration.
438
-
439
- Parameters
440
- ----------
441
- message : str
442
- Message to emit.
443
- level : int, optional
444
- Logging level (e.g., logging.INFO, logging.WARNING), by default
445
- logging.INFO.
446
-
447
- Examples
448
- --------
449
- >>> import logging
450
- >>> log("Test message", level=logging.INFO) # doctest: +SKIP
451
- """
452
- global _configured_logging
453
- if not _configured_logging:
454
- logging.basicConfig(
455
- level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s"
456
- )
457
- _configured_logging = True
458
- logging.log(level, message)
459
-
460
-
461
- __all__ = [
462
- "ensure_list",
463
- "check_filepath",
464
- "coerce_jsonable",
465
- "JSONSerializable",
466
- "customJSONEncoder",
467
- "log",
468
- ]
@@ -1,66 +0,0 @@
1
- openai_sdk_helpers/__init__.py,sha256=rXQ5KjONsOf1aN31NKXfljN7FlEvxg8s29Z6LkIG3fw,3231
2
- openai_sdk_helpers/async_utils.py,sha256=_GPiSDQhWehiZu2S_jB_Xgl0p2qGc5MNu1NN92zz3bg,3726
3
- openai_sdk_helpers/config.py,sha256=ChJmSfi71T3LyNYhsNpJF_bho1a3d5vCGIRD0IwLh9o,7662
4
- openai_sdk_helpers/context_manager.py,sha256=9z54rjcJ-nAFdEoZHjFdk1YYpeD9bet13MOgn23FzM8,6629
5
- openai_sdk_helpers/environment.py,sha256=HSPI1h1JUuMxzcTSvr28ktHBvyEJLRzL4bZhNfy59lI,1372
6
- openai_sdk_helpers/errors.py,sha256=oytqn-6Jg6nPMQOP956ftfkLS0R5c1XBDX-lNstrb3Y,3135
7
- openai_sdk_helpers/logging_config.py,sha256=fOKBgisOkM0VYDt68pmUSxVWzTeO25_u-El0HOxqEYM,2928
8
- openai_sdk_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- openai_sdk_helpers/retry.py,sha256=3I5cZOq5X6d7kno3fk1SVDYJ7U2VDHqBS7ZsaXWbU6A,6529
10
- openai_sdk_helpers/types.py,sha256=xzldCRfwCZ3rZl18IBmfgA-PVdoZKSWNrlSIhirumSo,1451
11
- openai_sdk_helpers/validation.py,sha256=fr3zVZ7uEokJJqF3LSIcQm4wV3MvWXcep2ZRpseXZBk,7789
12
- openai_sdk_helpers/agent/__init__.py,sha256=giowU8jke0z0h7FFUG9V6Vssja8AYwvJMQbiMb3s64k,960
13
- openai_sdk_helpers/agent/base.py,sha256=CKHfcUsBc8Hd5UAKehHw6E3GVEs7VasZZ0M8WrWJPv4,11737
14
- openai_sdk_helpers/agent/config.py,sha256=htqy5bcrJeMf3rIpRdL9CKlYwyQI4po420rcgR3i8XI,1971
15
- openai_sdk_helpers/agent/coordination.py,sha256=00iJPHZvpLEDRDeon_HRQPEHdyQnEk4NTjAj9VgkqVI,16204
16
- openai_sdk_helpers/agent/prompt_utils.py,sha256=-1M66tqQxh9wWCFg6X-K7cCcqauca3yA04ZjvOpN3bA,337
17
- openai_sdk_helpers/agent/runner.py,sha256=XRa17OV8f0G8--6qyUFw6BwJSHBNe_Yx8DFajxVYFxA,4137
18
- openai_sdk_helpers/agent/summarizer.py,sha256=fH8AnYK_68ERf2U7mv0nwXL8KyhrluE-TDY_M5TCdD0,3266
19
- openai_sdk_helpers/agent/translator.py,sha256=GhUuwFTBecgOO9pMQ41VPvK9mTub5DXJ_7BIS9Xp7bs,5082
20
- openai_sdk_helpers/agent/utils.py,sha256=DTD5foCqGYfXf13F2bZMYIQROl7SbDSy5GDPGi0Zl-0,1089
21
- openai_sdk_helpers/agent/validation.py,sha256=JIYVhBTTs0tTxYyzYgY3BHC-9psyzE3LLQDZDqpg13M,4191
22
- openai_sdk_helpers/agent/search/__init__.py,sha256=xqosfzH4HcBs9IFZks9msG_694rS5q6Ea4_qNeRQRmU,798
23
- openai_sdk_helpers/agent/search/base.py,sha256=05ERHgNqUrG7bs0zrtFgDps_m_dq1b_Hr1W1aSWm5BM,8602
24
- openai_sdk_helpers/agent/search/vector.py,sha256=ebIRPFusLJa5SfwV4Ush_8eoLVMlH0OsOFi_dCFXF0M,13600
25
- openai_sdk_helpers/agent/search/web.py,sha256=8le4xnZ3nllySqWb7rZaOq44ZR8q67c_WiE57ncmL90,10014
26
- openai_sdk_helpers/enums/__init__.py,sha256=aFf79C4JBeLC3kMlJfSpehyjx5uNCtW6eK5rD6ZFfhM,322
27
- openai_sdk_helpers/enums/base.py,sha256=cNllDtzcgI0_eZYXxFko14yhxwicX6xbeDfz9gFE3qo,2753
28
- openai_sdk_helpers/prompt/__init__.py,sha256=MOqgKwG9KLqKudoKRlUfLxiSmdOi2aD6hNrWDFqLHkk,418
29
- openai_sdk_helpers/prompt/base.py,sha256=4VJFmJozVmKQ04dqm8jYSiOijcQbT0CSAll2NE8zF68,5734
30
- openai_sdk_helpers/prompt/summarizer.jinja,sha256=jliSetWDISbql1EkWi1RB8-L_BXUg8JMkRRsPRHuzbY,309
31
- openai_sdk_helpers/prompt/translator.jinja,sha256=SZhW8ipEzM-9IA4wyS_r2wIMTAclWrilmk1s46njoL0,291
32
- openai_sdk_helpers/prompt/validator.jinja,sha256=6t8q_IdxFd3mVBGX6SFKNOert1Wo3YpTOji2SNEbbtE,547
33
- openai_sdk_helpers/response/__init__.py,sha256=BbKIigsEVQGbxRSBp9FSLPM9OYsEndKHZpGHonnu8P4,1599
34
- openai_sdk_helpers/response/base.py,sha256=-d-vvY4OId_MU6EAN55bBPEftnskw9Ry8TVQ705f9Xw,27965
35
- openai_sdk_helpers/response/config.py,sha256=kSsZtDT9JYK8KgF3OaFeeP2rhGtSsFlw535HJoPqpUk,6523
36
- openai_sdk_helpers/response/messages.py,sha256=oVSHpSV_iQxHreCXm--a6MlHg_kkElQi3R2Y8Y7VphA,9134
37
- openai_sdk_helpers/response/runner.py,sha256=Rf13cQGsR7sN9gA81Y5th1tfH2DCCAwQ6RMs3bVgjnk,4269
38
- openai_sdk_helpers/response/tool_call.py,sha256=218mWOj-QGW3IwVsgnSurSRWRcdUiFT-5C44Zn_m4pQ,3943
39
- openai_sdk_helpers/response/vector_store.py,sha256=MyHUu6P9ueNsd9erbBkyVqq3stLK6qVuehdvmFAHq9E,3074
40
- openai_sdk_helpers/streamlit_app/__init__.py,sha256=RjJbnBDS5_YmAmxvaa3phB5u9UcXsXDEk_jMlY_pa5Q,793
41
- openai_sdk_helpers/streamlit_app/app.py,sha256=ID3B4fUQHvv1Cwuuvrlm4nK4d0nWL6uBE40O_T6r7yY,10808
42
- openai_sdk_helpers/streamlit_app/config.py,sha256=EK6LWACo7YIkDko1oesvupOx56cTuWWnwnXRiu8EYbs,15986
43
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py,sha256=OrX-kgW_yaHgIsK6wY9gBVLbvDaMFXgkgdhKQDsA8kQ,2506
44
- openai_sdk_helpers/structure/__init__.py,sha256=YI15qqUr2hezDJoShUfhEfRWcO2iEe9CQEBM5tAQQB4,3280
45
- openai_sdk_helpers/structure/agent_blueprint.py,sha256=2W-RBM5G3ZefMcYHqqoV6Y1witcSbMlUpdU1CA9n3tg,9698
46
- openai_sdk_helpers/structure/base.py,sha256=7RMsCMjQR7u3mksirqd0E6AgCgWEMVRQtgNefwHWPGo,28278
47
- openai_sdk_helpers/structure/prompt.py,sha256=7DBdLu6WDvXy2RkEBayDiX2Jn8T4-hJuohsOaKEoqJs,1075
48
- openai_sdk_helpers/structure/responses.py,sha256=iYJBT_4VFifzQqPnTpRWTcB0o7xkhPIQ2ugedivrpto,4868
49
- openai_sdk_helpers/structure/summary.py,sha256=MyZzMuqHP9F8B4rYYxCGJwojy5RavWUkMiRZ6yMQzvU,3143
50
- openai_sdk_helpers/structure/validation.py,sha256=vsilA3Qs3fjWLeYlnZnMEGj9i_bOJtXc2J3mSIEHncg,2409
51
- openai_sdk_helpers/structure/vector_search.py,sha256=A0w2AR0r6aIFoYbNkscUAGT7VzTe6WuvxrqUsWT2PMQ,5782
52
- openai_sdk_helpers/structure/web_search.py,sha256=S8OdllBWqEGXaKf6Alocl89ZuG7BlvXK5ra1Lm7lfjE,4572
53
- openai_sdk_helpers/structure/plan/__init__.py,sha256=0kLN6n3wTAFuOvCOWiDrreWpv6RX4ycD4HNhVqF4pTs,667
54
- openai_sdk_helpers/structure/plan/enum.py,sha256=seESSwH-IeeW-9BqIMUQyk3qjtchfU3TDhF9HPDB1OM,3079
55
- openai_sdk_helpers/structure/plan/plan.py,sha256=Rc8vwY2RmDrRRhVtiOv0BXjoRKn3T1RGY0Pi3wRvLjk,9602
56
- openai_sdk_helpers/structure/plan/task.py,sha256=2dH8iaLhjC7MKZEW1T_HICaggi1RPyKSPOl9ORmmYdg,4538
57
- openai_sdk_helpers/utils/__init__.py,sha256=L4U5uaBIt0nIV-GhFc5Kotx9h69SryoCmfJL9u23IJU,1388
58
- openai_sdk_helpers/utils/core.py,sha256=XvQePx0CDkcwkENAatcPwF9H_b4N5nedlIX3viW2RtM,12684
59
- openai_sdk_helpers/vector_storage/__init__.py,sha256=L5LxO09puh9_yBB9IDTvc1CvVkARVkHqYY1KX3inB4c,975
60
- openai_sdk_helpers/vector_storage/cleanup.py,sha256=ImWIE-9lli-odD8qIARvmeaa0y8ZD4pYYP-kT0O3178,3552
61
- openai_sdk_helpers/vector_storage/storage.py,sha256=ZiTZnvCY28R-WUQjHdnjQo1xIRbXAM6JL0VhqW9MM9I,21725
62
- openai_sdk_helpers/vector_storage/types.py,sha256=jTCcOYMeOpZWvcse0z4T3MVs-RBOPC-fqWTBeQrgafU,1639
63
- openai_sdk_helpers-0.0.9.dist-info/METADATA,sha256=lKUWNHXa5c7maQW4p7pQA0uM0cPSyvNf_TMce5huHlo,18492
64
- openai_sdk_helpers-0.0.9.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
65
- openai_sdk_helpers-0.0.9.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
66
- openai_sdk_helpers-0.0.9.dist-info/RECORD,,