openai-sdk-helpers 0.0.8__py3-none-any.whl → 0.1.0__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 (67) hide show
  1. openai_sdk_helpers/__init__.py +90 -2
  2. openai_sdk_helpers/agent/__init__.py +8 -4
  3. openai_sdk_helpers/agent/base.py +80 -45
  4. openai_sdk_helpers/agent/config.py +6 -4
  5. openai_sdk_helpers/agent/{project_manager.py → coordination.py} +29 -45
  6. openai_sdk_helpers/agent/prompt_utils.py +7 -1
  7. openai_sdk_helpers/agent/runner.py +67 -141
  8. openai_sdk_helpers/agent/search/__init__.py +33 -0
  9. openai_sdk_helpers/agent/search/base.py +297 -0
  10. openai_sdk_helpers/agent/{vector_search.py → search/vector.py} +89 -157
  11. openai_sdk_helpers/agent/{web_search.py → search/web.py} +77 -156
  12. openai_sdk_helpers/agent/summarizer.py +29 -8
  13. openai_sdk_helpers/agent/translator.py +40 -13
  14. openai_sdk_helpers/agent/validation.py +32 -8
  15. openai_sdk_helpers/async_utils.py +132 -0
  16. openai_sdk_helpers/config.py +101 -65
  17. openai_sdk_helpers/context_manager.py +241 -0
  18. openai_sdk_helpers/enums/__init__.py +9 -1
  19. openai_sdk_helpers/enums/base.py +67 -8
  20. openai_sdk_helpers/environment.py +33 -6
  21. openai_sdk_helpers/errors.py +133 -0
  22. openai_sdk_helpers/logging_config.py +105 -0
  23. openai_sdk_helpers/prompt/__init__.py +10 -71
  24. openai_sdk_helpers/prompt/base.py +222 -0
  25. openai_sdk_helpers/response/__init__.py +38 -3
  26. openai_sdk_helpers/response/base.py +363 -210
  27. openai_sdk_helpers/response/config.py +318 -0
  28. openai_sdk_helpers/response/messages.py +56 -40
  29. openai_sdk_helpers/response/runner.py +77 -33
  30. openai_sdk_helpers/response/tool_call.py +62 -27
  31. openai_sdk_helpers/response/vector_store.py +27 -14
  32. openai_sdk_helpers/retry.py +175 -0
  33. openai_sdk_helpers/streamlit_app/__init__.py +19 -2
  34. openai_sdk_helpers/streamlit_app/app.py +114 -39
  35. openai_sdk_helpers/streamlit_app/config.py +502 -0
  36. openai_sdk_helpers/streamlit_app/streamlit_web_search.py +5 -6
  37. openai_sdk_helpers/structure/__init__.py +72 -3
  38. openai_sdk_helpers/structure/agent_blueprint.py +82 -19
  39. openai_sdk_helpers/structure/base.py +208 -93
  40. openai_sdk_helpers/structure/plan/__init__.py +29 -1
  41. openai_sdk_helpers/structure/plan/enum.py +41 -5
  42. openai_sdk_helpers/structure/plan/helpers.py +172 -0
  43. openai_sdk_helpers/structure/plan/plan.py +109 -49
  44. openai_sdk_helpers/structure/plan/task.py +38 -6
  45. openai_sdk_helpers/structure/plan/types.py +15 -0
  46. openai_sdk_helpers/structure/prompt.py +21 -2
  47. openai_sdk_helpers/structure/responses.py +52 -11
  48. openai_sdk_helpers/structure/summary.py +55 -7
  49. openai_sdk_helpers/structure/validation.py +34 -6
  50. openai_sdk_helpers/structure/vector_search.py +132 -18
  51. openai_sdk_helpers/structure/web_search.py +125 -13
  52. openai_sdk_helpers/tools.py +193 -0
  53. openai_sdk_helpers/types.py +57 -0
  54. openai_sdk_helpers/utils/__init__.py +34 -1
  55. openai_sdk_helpers/utils/core.py +296 -34
  56. openai_sdk_helpers/validation.py +302 -0
  57. openai_sdk_helpers/vector_storage/__init__.py +21 -1
  58. openai_sdk_helpers/vector_storage/cleanup.py +25 -13
  59. openai_sdk_helpers/vector_storage/storage.py +123 -64
  60. openai_sdk_helpers/vector_storage/types.py +20 -19
  61. openai_sdk_helpers-0.1.0.dist-info/METADATA +550 -0
  62. openai_sdk_helpers-0.1.0.dist-info/RECORD +69 -0
  63. openai_sdk_helpers/streamlit_app/configuration.py +0 -324
  64. openai_sdk_helpers-0.0.8.dist-info/METADATA +0 -194
  65. openai_sdk_helpers-0.0.8.dist-info/RECORD +0 -55
  66. {openai_sdk_helpers-0.0.8.dist-info → openai_sdk_helpers-0.1.0.dist-info}/WHEEL +0 -0
  67. {openai_sdk_helpers-0.0.8.dist-info → openai_sdk_helpers-0.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,29 +1,37 @@
1
- """Core utility helpers for openai-sdk-helpers."""
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
+ """
2
7
 
3
8
  from __future__ import annotations
4
9
 
5
10
  import json
6
11
  import logging
7
12
  import ast
13
+ from collections.abc import Iterable, Mapping
8
14
  from dataclasses import asdict, is_dataclass
9
15
  from datetime import datetime
10
16
  from enum import Enum
11
17
  from pathlib import Path
12
- from typing import Any, Dict, Iterable, List, Mapping, Optional, TypeVar
18
+ from typing import Any, TypeVar
19
+
13
20
 
21
+ def coerce_optional_float(value: object) -> float | None:
22
+ """Return a float when the provided value can be coerced, otherwise None.
14
23
 
15
- def coerce_optional_float(value: Any) -> Optional[float]:
16
- """Return a float when the provided value can be coerced, otherwise ``None``.
24
+ Handles float, int, and string inputs. Empty strings or None return None.
17
25
 
18
26
  Parameters
19
27
  ----------
20
- value : Any
28
+ value : object
21
29
  Value to convert into a float. Strings must be parseable as floats.
22
30
 
23
31
  Returns
24
32
  -------
25
- float | None
26
- Converted float value or ``None`` if the input is ``None``.
33
+ float or None
34
+ Converted float value or None if the input is None.
27
35
 
28
36
  Raises
29
37
  ------
@@ -31,6 +39,15 @@ def coerce_optional_float(value: Any) -> Optional[float]:
31
39
  If a non-empty string cannot be converted to a float.
32
40
  TypeError
33
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
34
51
  """
35
52
  if value is None:
36
53
  return None
@@ -44,18 +61,21 @@ def coerce_optional_float(value: Any) -> Optional[float]:
44
61
  raise TypeError("timeout must be a float, int, str, or None")
45
62
 
46
63
 
47
- def coerce_optional_int(value: Any) -> Optional[int]:
48
- """Return an int when the provided value can be coerced, otherwise ``None``.
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.
49
69
 
50
70
  Parameters
51
71
  ----------
52
- value : Any
72
+ value : object
53
73
  Value to convert into an int. Strings must be parseable as integers.
54
74
 
55
75
  Returns
56
76
  -------
57
- int | None
58
- Converted integer value or ``None`` if the input is ``None``.
77
+ int or None
78
+ Converted integer value or None if the input is None.
59
79
 
60
80
  Raises
61
81
  ------
@@ -63,6 +83,17 @@ def coerce_optional_int(value: Any) -> Optional[int]:
63
83
  If a non-empty string cannot be converted to an integer.
64
84
  TypeError
65
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
66
97
  """
67
98
  if value is None:
68
99
  return None
@@ -78,23 +109,32 @@ def coerce_optional_int(value: Any) -> Optional[int]:
78
109
  raise TypeError("max_retries must be an int, str, or None")
79
110
 
80
111
 
81
- def coerce_dict(value: Any) -> Dict[str, Any]:
82
- """Return a string-keyed dictionary built from ``value`` if possible.
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.
83
116
 
84
117
  Parameters
85
118
  ----------
86
- value : Any
87
- Mapping-like value to convert. ``None`` yields an empty dictionary.
119
+ value : object
120
+ Mapping-like value to convert. None yields an empty dictionary.
88
121
 
89
122
  Returns
90
123
  -------
91
124
  dict[str, Any]
92
- Dictionary representation of ``value``.
125
+ Dictionary representation of value.
93
126
 
94
127
  Raises
95
128
  ------
96
129
  TypeError
97
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
+ {}
98
138
  """
99
139
  if value is None:
100
140
  return {}
@@ -103,22 +143,160 @@ def coerce_dict(value: Any) -> Dict[str, Any]:
103
143
  raise TypeError("extra_client_kwargs must be a mapping or None")
104
144
 
105
145
 
146
+ def build_openai_settings(
147
+ api_key: str | None = None,
148
+ org_id: str | None = None,
149
+ project_id: str | None = None,
150
+ base_url: str | None = None,
151
+ default_model: str | None = None,
152
+ timeout: float | str | None = None,
153
+ max_retries: int | str | None = None,
154
+ dotenv_path: Path | None = None,
155
+ **extra_kwargs: Any,
156
+ ) -> Any: # Returns OpenAISettings but use Any to avoid circular import
157
+ """Build OpenAI settings from environment with explicit validation.
158
+
159
+ Convenience function for creating OpenAISettings with validation and
160
+ clear error messages. Reads from environment variables and validates
161
+ required fields, with explicit type coercion for timeout and max_retries.
162
+
163
+ Parameters
164
+ ----------
165
+ api_key : str or None, default None
166
+ API key for OpenAI authentication. If None, reads from OPENAI_API_KEY.
167
+ org_id : str or None, default None
168
+ Organization ID. If None, reads from OPENAI_ORG_ID.
169
+ project_id : str or None, default None
170
+ Project ID. If None, reads from OPENAI_PROJECT_ID.
171
+ base_url : str or None, default None
172
+ Base URL for API requests. If None, reads from OPENAI_BASE_URL.
173
+ default_model : str or None, default None
174
+ Default model name. If None, reads from OPENAI_MODEL.
175
+ timeout : float, str, or None, default None
176
+ Request timeout in seconds. If None, reads from OPENAI_TIMEOUT.
177
+ Can be string that will be parsed to float.
178
+ max_retries : int, str, or None, default None
179
+ Maximum retry attempts. If None, reads from OPENAI_MAX_RETRIES.
180
+ Can be string that will be parsed to int.
181
+ dotenv_path : Path or None, default None
182
+ Path to .env file. If None, searches for .env in current directory.
183
+ **extra_kwargs : Any
184
+ Additional keyword arguments for extra_client_kwargs.
185
+
186
+ Returns
187
+ -------
188
+ OpenAISettings
189
+ Configured settings instance.
190
+
191
+ Raises
192
+ ------
193
+ ValueError
194
+ If OPENAI_API_KEY is not found in environment or parameters.
195
+ If timeout cannot be parsed as float.
196
+ If max_retries cannot be parsed as int.
197
+ TypeError
198
+ If timeout or max_retries have invalid types.
199
+
200
+ Examples
201
+ --------
202
+ Build from explicit parameters:
203
+
204
+ >>> settings = build_openai_settings(
205
+ ... api_key="sk-...",
206
+ ... default_model="gpt-4o",
207
+ ... timeout=30.0
208
+ ... )
209
+
210
+ Build from environment:
211
+
212
+ >>> settings = build_openai_settings() # doctest: +SKIP
213
+
214
+ With custom .env location:
215
+
216
+ >>> settings = build_openai_settings(
217
+ ... dotenv_path=Path("/path/to/.env")
218
+ ... ) # doctest: +SKIP
219
+ """
220
+ # Import at runtime to avoid circular import
221
+ from openai_sdk_helpers.config import OpenAISettings
222
+
223
+ # Parse timeout with validation
224
+ parsed_timeout: float | None = None
225
+ if timeout is not None:
226
+ try:
227
+ parsed_timeout = coerce_optional_float(timeout)
228
+ except (ValueError, TypeError) as exc:
229
+ raise ValueError(
230
+ f"Invalid timeout value '{timeout}'. Must be a number or numeric string."
231
+ ) from exc
232
+
233
+ # Parse max_retries with validation
234
+ parsed_max_retries: int | None = None
235
+ if max_retries is not None:
236
+ try:
237
+ parsed_max_retries = coerce_optional_int(max_retries)
238
+ except (ValueError, TypeError) as exc:
239
+ raise ValueError(
240
+ f"Invalid max_retries value '{max_retries}'. "
241
+ "Must be an integer or numeric string."
242
+ ) from exc
243
+
244
+ # Build settings using from_env with overrides
245
+ overrides = {}
246
+ if api_key is not None:
247
+ overrides["api_key"] = api_key
248
+ if org_id is not None:
249
+ overrides["org_id"] = org_id
250
+ if project_id is not None:
251
+ overrides["project_id"] = project_id
252
+ if base_url is not None:
253
+ overrides["base_url"] = base_url
254
+ if default_model is not None:
255
+ overrides["default_model"] = default_model
256
+ if parsed_timeout is not None:
257
+ overrides["timeout"] = parsed_timeout
258
+ if parsed_max_retries is not None:
259
+ overrides["max_retries"] = parsed_max_retries
260
+ if extra_kwargs:
261
+ overrides["extra_client_kwargs"] = extra_kwargs
262
+
263
+ try:
264
+ return OpenAISettings.from_env(dotenv_path=dotenv_path, **overrides)
265
+ except ValueError as exc:
266
+ # Re-raise with more context but preserve original message
267
+ raise ValueError(f"Failed to build OpenAI settings: {exc}") from exc
268
+
269
+
106
270
  T = TypeVar("T")
107
271
  _configured_logging = False
108
272
 
109
273
 
110
- def ensure_list(value: Iterable[T] | T | None) -> List[T]:
274
+ def ensure_list(value: Iterable[T] | T | None) -> list[T]:
111
275
  """Normalize a single item or iterable into a list.
112
276
 
277
+ Converts None to empty list, tuples to lists, and wraps single
278
+ items in a list.
279
+
113
280
  Parameters
114
281
  ----------
115
282
  value : Iterable[T] | T | None
116
- Item or iterable to wrap. ``None`` yields an empty list.
283
+ Item or iterable to wrap. None yields an empty list.
117
284
 
118
285
  Returns
119
286
  -------
120
287
  list[T]
121
- Normalized list representation of ``value``.
288
+ Normalized list representation of value.
289
+
290
+ Examples
291
+ --------
292
+ >>> ensure_list(None)
293
+ []
294
+ >>> ensure_list(5)
295
+ [5]
296
+ >>> ensure_list([1, 2, 3])
297
+ [1, 2, 3]
298
+ >>> ensure_list(("a", "b"))
299
+ ['a', 'b']
122
300
  """
123
301
  if value is None:
124
302
  return []
@@ -134,12 +312,15 @@ def check_filepath(
134
312
  ) -> Path:
135
313
  """Ensure the parent directory for a file path exists.
136
314
 
315
+ Creates parent directories as needed. Exactly one of filepath or
316
+ fullfilepath must be provided.
317
+
137
318
  Parameters
138
319
  ----------
139
- filepath : Path | None, optional
140
- Path object to validate. Mutually exclusive with ``fullfilepath``.
141
- fullfilepath : str | None, optional
142
- String path to validate. Mutually exclusive with ``filepath``.
320
+ filepath : Path or None, optional
321
+ Path object to validate. Mutually exclusive with fullfilepath.
322
+ fullfilepath : str or None, optional
323
+ String path to validate. Mutually exclusive with filepath.
143
324
 
144
325
  Returns
145
326
  -------
@@ -149,7 +330,14 @@ def check_filepath(
149
330
  Raises
150
331
  ------
151
332
  ValueError
152
- If neither ``filepath`` nor ``fullfilepath`` is provided.
333
+ If neither filepath nor fullfilepath is provided.
334
+
335
+ Examples
336
+ --------
337
+ >>> from pathlib import Path
338
+ >>> path = check_filepath(filepath=Path("/tmp/test.txt"))
339
+ >>> isinstance(path, Path)
340
+ True
153
341
  """
154
342
  if filepath is None and fullfilepath is None:
155
343
  raise ValueError("filepath or fullfilepath is required.")
@@ -166,6 +354,9 @@ def check_filepath(
166
354
  def _to_jsonable(value: Any) -> Any:
167
355
  """Convert common helper types to JSON-serializable forms.
168
356
 
357
+ Handles Enum, Path, datetime, dataclasses, Pydantic models, dicts,
358
+ lists, tuples, and sets.
359
+
169
360
  Parameters
170
361
  ----------
171
362
  value : Any
@@ -174,7 +365,11 @@ def _to_jsonable(value: Any) -> Any:
174
365
  Returns
175
366
  -------
176
367
  Any
177
- A JSON-safe representation of ``value``.
368
+ A JSON-safe representation of value.
369
+
370
+ Notes
371
+ -----
372
+ This is an internal helper function. Use coerce_jsonable for public API.
178
373
  """
179
374
  if value is None:
180
375
  return None
@@ -197,7 +392,10 @@ def _to_jsonable(value: Any) -> Any:
197
392
 
198
393
 
199
394
  def coerce_jsonable(value: Any) -> Any:
200
- """Convert ``value`` into a JSON-serializable representation.
395
+ """Convert value into a JSON-serializable representation.
396
+
397
+ Handles BaseStructure, BaseResponse, dataclasses, and other complex
398
+ types by recursively converting them to JSON-compatible forms.
201
399
 
202
400
  Parameters
203
401
  ----------
@@ -207,7 +405,14 @@ def coerce_jsonable(value: Any) -> Any:
207
405
  Returns
208
406
  -------
209
407
  Any
210
- JSON-serializable representation of ``value``.
408
+ JSON-serializable representation of value.
409
+
410
+ Examples
411
+ --------
412
+ >>> from datetime import datetime
413
+ >>> result = coerce_jsonable({"date": datetime(2024, 1, 1)})
414
+ >>> isinstance(result, dict)
415
+ True
211
416
  """
212
417
  from openai_sdk_helpers.response.base import BaseResponse
213
418
  from openai_sdk_helpers.structure.base import BaseStructure
@@ -229,16 +434,29 @@ def coerce_jsonable(value: Any) -> Any:
229
434
 
230
435
 
231
436
  class customJSONEncoder(json.JSONEncoder):
232
- """Encode common helper types like enums and paths.
437
+ """JSON encoder for common helper types like enums and paths.
438
+
439
+ Extends json.JSONEncoder to handle Enum, Path, datetime, dataclasses,
440
+ and Pydantic models automatically.
233
441
 
234
442
  Methods
235
443
  -------
236
444
  default(o)
237
- Return a JSON-serializable representation of ``o``.
445
+ Return a JSON-serializable representation of o.
446
+
447
+ Examples
448
+ --------
449
+ >>> import json
450
+ >>> from pathlib import Path
451
+ >>> json.dumps({"path": Path("/tmp")}, cls=customJSONEncoder)
452
+ '{"path": "/tmp"}'
238
453
  """
239
454
 
240
455
  def default(self, o: Any) -> Any:
241
- """Return a JSON-serializable representation of ``o``.
456
+ """Return a JSON-serializable representation of o.
457
+
458
+ Called by the json module when the default serialization fails.
459
+ Delegates to _to_jsonable for type-specific conversions.
242
460
 
243
461
  Parameters
244
462
  ----------
@@ -248,7 +466,7 @@ class customJSONEncoder(json.JSONEncoder):
248
466
  Returns
249
467
  -------
250
468
  Any
251
- JSON-safe representation of ``o``.
469
+ JSON-safe representation of o.
252
470
  """
253
471
  return _to_jsonable(o)
254
472
 
@@ -256,21 +474,44 @@ class customJSONEncoder(json.JSONEncoder):
256
474
  class JSONSerializable:
257
475
  """Mixin for classes that can be serialized to JSON.
258
476
 
477
+ Provides to_json() and to_json_file() methods for any class. Works
478
+ with dataclasses, Pydantic models, and regular classes with __dict__.
479
+
259
480
  Methods
260
481
  -------
261
482
  to_json()
262
483
  Return a JSON-compatible dict representation of the instance.
263
484
  to_json_file(filepath)
264
485
  Write serialized JSON data to a file path.
486
+
487
+ Examples
488
+ --------
489
+ >>> from dataclasses import dataclass
490
+ >>> @dataclass
491
+ ... class MyClass(JSONSerializable):
492
+ ... value: int
493
+ >>> obj = MyClass(value=42)
494
+ >>> obj.to_json()
495
+ {'value': 42}
265
496
  """
266
497
 
267
- def to_json(self) -> Dict[str, Any]:
498
+ def to_json(self) -> dict[str, Any]:
268
499
  """Return a JSON-compatible dict representation.
269
500
 
501
+ Automatically handles dataclasses, Pydantic models, and objects
502
+ with __dict__ attributes.
503
+
270
504
  Returns
271
505
  -------
272
506
  dict[str, Any]
273
507
  Mapping with only JSON-serializable values.
508
+
509
+ Examples
510
+ --------
511
+ >>> obj = JSONSerializable()
512
+ >>> result = obj.to_json()
513
+ >>> isinstance(result, dict)
514
+ True
274
515
  """
275
516
  if is_dataclass(self) and not isinstance(self, type):
276
517
  return {k: _to_jsonable(v) for k, v in asdict(self).items()}
@@ -282,6 +523,9 @@ class JSONSerializable:
282
523
  def to_json_file(self, filepath: str | Path) -> str:
283
524
  """Write serialized JSON data to a file path.
284
525
 
526
+ Creates parent directories as needed. Uses customJSONEncoder for
527
+ handling special types.
528
+
285
529
  Parameters
286
530
  ----------
287
531
  filepath : str | Path
@@ -291,6 +535,11 @@ class JSONSerializable:
291
535
  -------
292
536
  str
293
537
  String representation of the file path written.
538
+
539
+ Examples
540
+ --------
541
+ >>> obj = JSONSerializable()
542
+ >>> path = obj.to_json_file("/tmp/output.json") # doctest: +SKIP
294
543
  """
295
544
  target = Path(filepath)
296
545
  check_filepath(fullfilepath=str(target))
@@ -308,12 +557,21 @@ class JSONSerializable:
308
557
  def log(message: str, level: int = logging.INFO) -> None:
309
558
  """Log a message with a basic configuration.
310
559
 
560
+ Configures logging on first use with a simple timestamp format.
561
+ Subsequent calls use the existing configuration.
562
+
311
563
  Parameters
312
564
  ----------
313
565
  message : str
314
566
  Message to emit.
315
567
  level : int, optional
316
- Logging level, by default ``logging.INFO``.
568
+ Logging level (e.g., logging.INFO, logging.WARNING), by default
569
+ logging.INFO.
570
+
571
+ Examples
572
+ --------
573
+ >>> import logging
574
+ >>> log("Test message", level=logging.INFO) # doctest: +SKIP
317
575
  """
318
576
  global _configured_logging
319
577
  if not _configured_logging:
@@ -331,4 +589,8 @@ __all__ = [
331
589
  "JSONSerializable",
332
590
  "customJSONEncoder",
333
591
  "log",
592
+ "coerce_optional_float",
593
+ "coerce_optional_int",
594
+ "coerce_dict",
595
+ "build_openai_settings",
334
596
  ]