openai-sdk-helpers 0.6.4__py3-none-any.whl → 0.6.5__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.
@@ -174,6 +174,100 @@ def _ensure_schema_has_type(schema: dict[str, Any]) -> None:
174
174
  schema.update(_build_any_value_schema())
175
175
 
176
176
 
177
+ def _strip_ref_types(
178
+ schema: dict[str, Any],
179
+ *,
180
+ nullable_fields: set[str] | None = None,
181
+ ) -> None:
182
+ """Remove type entries from enum $ref nodes when non-nullable.
183
+
184
+ Parameters
185
+ ----------
186
+ schema : dict[str, Any]
187
+ Root schema to clean in place.
188
+ nullable_fields : set[str] | None, optional
189
+ Field names that should remain nullable. Defaults to None.
190
+ """
191
+ field_names = nullable_fields or set()
192
+
193
+ def _resolve_ref(ref: str) -> dict[str, Any] | None:
194
+ if not ref.startswith("#/"):
195
+ return None
196
+ pointer = ref.removeprefix("#/")
197
+ current: Any = schema
198
+ for part in pointer.split("/"):
199
+ if not isinstance(current, dict):
200
+ return None
201
+ current = current.get(part)
202
+ if isinstance(current, dict):
203
+ return current
204
+ return None
205
+
206
+ def _is_enum_ref(ref: str) -> bool:
207
+ ref_target = _resolve_ref(ref)
208
+ if not isinstance(ref_target, dict):
209
+ return False
210
+ return "enum" in ref_target
211
+
212
+ def _is_null_schema(entry: Any) -> bool:
213
+ if not isinstance(entry, dict):
214
+ return False
215
+ entry_type = entry.get("type")
216
+ if entry_type == "null":
217
+ return True
218
+ if isinstance(entry_type, list) and "null" in entry_type:
219
+ return True
220
+ return False
221
+
222
+ def _walk(
223
+ node: Any,
224
+ *,
225
+ nullable_context: bool = False,
226
+ nullable_property: bool = False,
227
+ ) -> None:
228
+ if isinstance(node, dict):
229
+ ref = node.get("$ref")
230
+ if (
231
+ isinstance(ref, str)
232
+ and _is_enum_ref(ref)
233
+ and not nullable_context
234
+ and not nullable_property
235
+ ):
236
+ node.pop("type", None)
237
+ for key, value in node.items():
238
+ if key == "anyOf" and isinstance(value, list):
239
+ anyof_nullable = any(_is_null_schema(entry) for entry in value)
240
+ for entry in value:
241
+ _walk(
242
+ entry,
243
+ nullable_context=anyof_nullable or nullable_context,
244
+ nullable_property=nullable_property,
245
+ )
246
+ continue
247
+ if key == "properties" and isinstance(value, dict):
248
+ for prop_name, prop_schema in value.items():
249
+ _walk(
250
+ prop_schema,
251
+ nullable_context=nullable_context,
252
+ nullable_property=prop_name in field_names,
253
+ )
254
+ continue
255
+ _walk(
256
+ value,
257
+ nullable_context=nullable_context,
258
+ nullable_property=nullable_property,
259
+ )
260
+ elif isinstance(node, list):
261
+ for item in node:
262
+ _walk(
263
+ item,
264
+ nullable_context=nullable_context,
265
+ nullable_property=nullable_property,
266
+ )
267
+
268
+ _walk(schema)
269
+
270
+
177
271
  def _hydrate_ref_types(schema: dict[str, Any]) -> None:
178
272
  """Attach explicit types to $ref nodes when available.
179
273
 
@@ -556,17 +650,18 @@ class StructureBase(BaseModelJSONSerializable):
556
650
 
557
651
  cleaned_schema = cast(dict[str, Any], clean_refs(schema))
558
652
 
559
- cleaned_schema = cast(dict[str, Any], cleaned_schema)
560
- _hydrate_ref_types(cleaned_schema)
561
- _ensure_items_have_schema(cleaned_schema)
562
- _ensure_schema_has_type(cleaned_schema)
563
-
564
653
  nullable_fields = {
565
654
  name
566
655
  for name, model_field in getattr(cls, "model_fields", {}).items()
567
656
  if getattr(model_field, "default", inspect.Signature.empty) is None
568
657
  }
569
658
 
659
+ cleaned_schema = cast(dict[str, Any], cleaned_schema)
660
+ _hydrate_ref_types(cleaned_schema)
661
+ _ensure_items_have_schema(cleaned_schema)
662
+ _ensure_schema_has_type(cleaned_schema)
663
+ _strip_ref_types(cleaned_schema, nullable_fields=nullable_fields)
664
+
570
665
  properties = cleaned_schema.get("properties", {})
571
666
  if isinstance(properties, dict) and nullable_fields:
572
667
  for field_name in nullable_fields:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openai-sdk-helpers
3
- Version: 0.6.4
3
+ Version: 0.6.5
4
4
  Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
5
5
  Author: openai-sdk-helpers maintainers
6
6
  License: MIT
@@ -57,7 +57,7 @@ openai_sdk_helpers/streamlit_app/app.py,sha256=kkjtdCKVwrJ9nZWuBArm3dhvcjMESX0TM
57
57
  openai_sdk_helpers/streamlit_app/configuration.py,sha256=0KeJ4HqCNFthBHsedV6ptqHluAcTPBb5_TujFOGkIUU,16685
58
58
  openai_sdk_helpers/structure/__init__.py,sha256=w27ezTYVLzZdDMFfA8mawE82h8zO53idFBCiCfYfh7s,4321
59
59
  openai_sdk_helpers/structure/agent_blueprint.py,sha256=VyJWkgPNzAYKRDMeR1M4kE6qqQURnwqtrrEn0TRJf0g,9698
60
- openai_sdk_helpers/structure/base.py,sha256=UrnNNU9qQ9mEES8MB9y6QESbDgPXH47XW8LVWSxYUYM,25280
60
+ openai_sdk_helpers/structure/base.py,sha256=OVI305F2suG6c2Qh_ZD_wZ1mS1GpqPBC-4RqInXqiAU,28512
61
61
  openai_sdk_helpers/structure/classification.py,sha256=SYrrsv0Y2A2kXhL3jbn7lWnTb5jB_UE-cx-sJSRCxEA,17312
62
62
  openai_sdk_helpers/structure/extraction.py,sha256=wODP0iLAhhsdQkMWRYPYTiLUMU8bFMKiBjPl3PKUleg,37335
63
63
  openai_sdk_helpers/structure/prompt.py,sha256=ZfsaHdA0hj5zmZDrOdpXjCsC8U-jjzwFG4JBsWYiaH4,1535
@@ -92,8 +92,8 @@ openai_sdk_helpers/vector_storage/__init__.py,sha256=L5LxO09puh9_yBB9IDTvc1CvVkA
92
92
  openai_sdk_helpers/vector_storage/cleanup.py,sha256=sZ4ZSTlnjF52o9Cc8A9dTX37ZYXXDxS_fdIpoOBWvrg,3666
93
93
  openai_sdk_helpers/vector_storage/storage.py,sha256=t_ukacaXRa9EXE4-3BxsrB4Rjhu6nTu7NA9IjCJBIpQ,24259
94
94
  openai_sdk_helpers/vector_storage/types.py,sha256=jTCcOYMeOpZWvcse0z4T3MVs-RBOPC-fqWTBeQrgafU,1639
95
- openai_sdk_helpers-0.6.4.dist-info/METADATA,sha256=l5XBsVFPOrOSDskGR0ZhgKHjJFLtO_-ZgWrRjXi1_bU,24622
96
- openai_sdk_helpers-0.6.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
97
- openai_sdk_helpers-0.6.4.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
98
- openai_sdk_helpers-0.6.4.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
99
- openai_sdk_helpers-0.6.4.dist-info/RECORD,,
95
+ openai_sdk_helpers-0.6.5.dist-info/METADATA,sha256=xInZz82S0zSN3YkKs_T949-3h0E_8mJaslN1nBgvES8,24622
96
+ openai_sdk_helpers-0.6.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
97
+ openai_sdk_helpers-0.6.5.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
98
+ openai_sdk_helpers-0.6.5.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
99
+ openai_sdk_helpers-0.6.5.dist-info/RECORD,,