openai-sdk-helpers 0.6.5__py3-none-any.whl → 0.6.6__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.
@@ -26,6 +26,8 @@ from ..utils import ensure_list
26
26
  from .base import AgentBase
27
27
  from .configuration import AgentConfiguration
28
28
 
29
+ _CONTINUE_CONFIDENCE_THRESHOLD = 0.7
30
+
29
31
 
30
32
  class TaxonomyClassifierAgent(AgentBase):
31
33
  """Classify text by recursively traversing a taxonomy.
@@ -394,6 +396,13 @@ class TaxonomyClassifierAgent(AgentBase):
394
396
 
395
397
  resolved_nodes = _resolve_nodes(node_paths, step)
396
398
 
399
+ should_continue = _should_continue_from_stop(step, resolved_nodes)
400
+ if should_continue:
401
+ step = step.model_copy(
402
+ update={"stop_reason": ClassificationStopReason.CONTINUE}
403
+ )
404
+ state.steps[-1] = step
405
+
397
406
  if step.stop_reason.is_terminal:
398
407
  if resolved_nodes:
399
408
  state.final_nodes.extend(resolved_nodes)
@@ -407,7 +416,7 @@ class TaxonomyClassifierAgent(AgentBase):
407
416
  return
408
417
 
409
418
  base_steps_len = len(state.steps)
410
- child_tasks: list[tuple[Awaitable["_TraversalState"], int]] = []
419
+ child_tasks: list[tuple[Awaitable["_TraversalState"], int, TaxonomyNode]] = []
411
420
  for node in resolved_nodes:
412
421
  if node.children:
413
422
  sub_agent = self._build_sub_agent(list(node.children))
@@ -429,6 +438,7 @@ class TaxonomyClassifierAgent(AgentBase):
429
438
  state=sub_state,
430
439
  ),
431
440
  base_final_nodes_len,
441
+ node,
432
442
  )
433
443
  )
434
444
  else:
@@ -439,13 +449,19 @@ class TaxonomyClassifierAgent(AgentBase):
439
449
  )
440
450
  if child_tasks:
441
451
  child_states = await asyncio.gather(
442
- *(child_task for child_task, _ in child_tasks)
452
+ *(child_task for child_task, _, _ in child_tasks)
443
453
  )
444
- for child_state, (_, base_final_nodes_len) in zip(
454
+ for child_state, (_, base_final_nodes_len, parent_node) in zip(
445
455
  child_states, child_tasks, strict=True
446
456
  ):
447
457
  state.steps.extend(child_state.steps[base_steps_len:])
448
- state.final_nodes.extend(child_state.final_nodes[base_final_nodes_len:])
458
+ child_final_nodes = child_state.final_nodes[base_final_nodes_len:]
459
+ state.final_nodes.extend(child_final_nodes)
460
+ if should_continue and not child_final_nodes:
461
+ state.final_nodes.append(parent_node)
462
+ state.best_confidence = _max_confidence(
463
+ state.best_confidence, step.confidence
464
+ )
449
465
  state.best_confidence = _max_confidence(
450
466
  state.best_confidence, child_state.best_confidence
451
467
  )
@@ -627,6 +643,34 @@ def _resolve_stop_reason(state: _TraversalState) -> ClassificationStopReason:
627
643
  return ClassificationStopReason.NO_MATCH
628
644
 
629
645
 
646
+ def _should_continue_from_stop(
647
+ step: ClassificationStep,
648
+ resolved_nodes: Sequence[TaxonomyNode],
649
+ threshold: float = _CONTINUE_CONFIDENCE_THRESHOLD,
650
+ ) -> bool:
651
+ """Return True when a stop reason should continue traversal.
652
+
653
+ Parameters
654
+ ----------
655
+ step : ClassificationStep
656
+ Classification step to evaluate.
657
+ resolved_nodes : Sequence[TaxonomyNode]
658
+ Resolved taxonomy nodes from the classification step.
659
+ threshold : float, default=0.7
660
+ Confidence threshold for overriding a stop reason.
661
+
662
+ Returns
663
+ -------
664
+ bool
665
+ True when traversal should proceed despite a stop reason.
666
+ """
667
+ if step.stop_reason is not ClassificationStopReason.STOP:
668
+ return False
669
+ if step.confidence is None or step.confidence < threshold:
670
+ return False
671
+ return any(node.children for node in resolved_nodes)
672
+
673
+
630
674
  def _normalize_roots(
631
675
  taxonomy: TaxonomyNode | Sequence[TaxonomyNode],
632
676
  ) -> list[TaxonomyNode]:
@@ -480,6 +480,8 @@ class ClassificationResult(StructureBase):
480
480
  Yield selected identifiers across all steps.
481
481
  selected_nodes
482
482
  Return the selected identifiers across all steps.
483
+ to_lightweight_summary
484
+ Return a lightweight summary of selected node paths.
483
485
 
484
486
  Examples
485
487
  --------
@@ -565,6 +567,52 @@ class ClassificationResult(StructureBase):
565
567
  if normalized:
566
568
  yield normalized
567
569
 
570
+ def to_lightweight_summary(self) -> "ClassificationSummary | None":
571
+ """Return a lightweight summary of selected node paths.
572
+
573
+ Returns
574
+ -------
575
+ ClassificationSummary or None
576
+ Summary containing the ``full_paths`` of selected nodes, or None
577
+ when no selections exist.
578
+
579
+ Examples
580
+ --------
581
+ >>> result = ClassificationResult(steps=[])
582
+ >>> result.to_lightweight_summary() is None
583
+ True
584
+ """
585
+ full_paths = [
586
+ format_path_identifier(taxonomy_enum_path(node))
587
+ for node in self.selected_nodes
588
+ ]
589
+ if not full_paths:
590
+ return None
591
+ return ClassificationSummary(full_paths=full_paths)
592
+
593
+
594
+ class ClassificationSummary(StructureBase):
595
+ """Represent a lightweight summary of selected taxonomy paths.
596
+
597
+ Attributes
598
+ ----------
599
+ full_paths : list[str] or None
600
+ Selected taxonomy paths including parent segments.
601
+
602
+ Methods
603
+ -------
604
+ to_json()
605
+ Serialize the summary to a JSON-compatible dictionary.
606
+ from_json(data)
607
+ Construct a summary instance from JSON-compatible data.
608
+ """
609
+
610
+ full_paths: list[str] | None = spec_field(
611
+ "full_paths",
612
+ description="Selected taxonomy paths including parent segments.",
613
+ default=None,
614
+ )
615
+
568
616
 
569
617
  def taxonomy_enum_path(value: Enum | str | None) -> list[str]:
570
618
  """Return the taxonomy path segments for an enum value.
@@ -598,6 +646,7 @@ def taxonomy_enum_path(value: Enum | str | None) -> list[str]:
598
646
 
599
647
  __all__ = [
600
648
  "ClassificationResult",
649
+ "ClassificationSummary",
601
650
  "ClassificationStep",
602
651
  "ClassificationStopReason",
603
652
  "Taxonomy",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openai-sdk-helpers
3
- Version: 0.6.5
3
+ Version: 0.6.6
4
4
  Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
5
5
  Author: openai-sdk-helpers maintainers
6
6
  License: MIT
@@ -10,7 +10,7 @@ openai_sdk_helpers/tools.py,sha256=8hhcytpmDfoXV16UQbDmDVV0rhLOn8c_VjXO8XaTFLQ,1
10
10
  openai_sdk_helpers/types.py,sha256=ejCG0rYqJhjOQvKLoNnzq-TzcKCFt69GVfi7y805NkU,1451
11
11
  openai_sdk_helpers/agent/__init__.py,sha256=qyzKzPhD8KsEl6d79XERK32AK5It_BZNOqChOpBdmhg,1199
12
12
  openai_sdk_helpers/agent/base.py,sha256=vLs0oALhxsd_Xy5dGjSZTUFTug-YwZkF1LabQ2ruLxk,29508
13
- openai_sdk_helpers/agent/classifier.py,sha256=PHUnA5dSDWBQeRxwo0Qe8xIe7Ren3xSRAOmsQrRK_oA,33241
13
+ openai_sdk_helpers/agent/classifier.py,sha256=PyeLNnu2cHx_zjY8ReLV2AN5olc0LZuvh6urNZgK6jc,34795
14
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
16
  openai_sdk_helpers/agent/files.py,sha256=H7UfSZSjFUbv1cjRvNld9kZwIjc5wPq4vynqU8HgGJE,4478
@@ -58,7 +58,7 @@ openai_sdk_helpers/streamlit_app/configuration.py,sha256=0KeJ4HqCNFthBHsedV6ptqH
58
58
  openai_sdk_helpers/structure/__init__.py,sha256=w27ezTYVLzZdDMFfA8mawE82h8zO53idFBCiCfYfh7s,4321
59
59
  openai_sdk_helpers/structure/agent_blueprint.py,sha256=VyJWkgPNzAYKRDMeR1M4kE6qqQURnwqtrrEn0TRJf0g,9698
60
60
  openai_sdk_helpers/structure/base.py,sha256=OVI305F2suG6c2Qh_ZD_wZ1mS1GpqPBC-4RqInXqiAU,28512
61
- openai_sdk_helpers/structure/classification.py,sha256=SYrrsv0Y2A2kXhL3jbn7lWnTb5jB_UE-cx-sJSRCxEA,17312
61
+ openai_sdk_helpers/structure/classification.py,sha256=aIelEz3Ffj4CKd0P_EB4uOMr0yX4uqqdKcRP9hjY0nw,18769
62
62
  openai_sdk_helpers/structure/extraction.py,sha256=wODP0iLAhhsdQkMWRYPYTiLUMU8bFMKiBjPl3PKUleg,37335
63
63
  openai_sdk_helpers/structure/prompt.py,sha256=ZfsaHdA0hj5zmZDrOdpXjCsC8U-jjzwFG4JBsWYiaH4,1535
64
64
  openai_sdk_helpers/structure/responses.py,sha256=WUwh0DhXj24pkvgqH1FMkdx5V2ArdvdtrDN_fuMBtDU,4882
@@ -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.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,,
95
+ openai_sdk_helpers-0.6.6.dist-info/METADATA,sha256=cyg4hIimWHNrkSxsEwWZGOOmaBFAWtSHfL9JkGQXHxw,24622
96
+ openai_sdk_helpers-0.6.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
97
+ openai_sdk_helpers-0.6.6.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
98
+ openai_sdk_helpers-0.6.6.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
99
+ openai_sdk_helpers-0.6.6.dist-info/RECORD,,