agentics-py 0.3.2__tar.gz → 0.3.3__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentics-py
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: Agentics is a Python framework that provides structured, scalable, and semantically grounded agentic computation.
5
5
  Author-email: Alfio Gliozzo <gliozzo@us.ibm.com>, Junkyu Lee <Junkyu.Lee@ibm.com>, Nahuel Defosse <nahuel.defosse@ibm.com>, Mustafa Eyceoz <Mustafa.Eyceoz@partner.ibm.com>, Naweed Aghmad Khan <naweed.khan@ibm.com>
6
6
  License-Expression: Apache-2.0
@@ -94,7 +94,7 @@ class AG(BaseModel, Generic[T]):
94
94
  None,
95
95
  description="""Python code for the used type""",
96
96
  )
97
- states: List[BaseModel] = []
97
+ states: List[BaseModel] = Field(default_factory=list)
98
98
  tools: Optional[List[Any]] = Field(None, exclude=True)
99
99
  transduce_fields: Optional[List[str]] = Field(
100
100
  None,
@@ -549,6 +549,48 @@ class AG(BaseModel, Generic[T]):
549
549
  if self.transduce_fields
550
550
  else self.atype
551
551
  )
552
+
553
+ # If self has no states, we need to initialize with empty states based on the input
554
+ if len(self.states) == 0:
555
+ # Helper function to create an empty state, handling required fields
556
+ def create_empty_state():
557
+ try:
558
+ return self.atype()
559
+ except Exception:
560
+ # If the model has required fields, use model_construct with defaults
561
+ # Get default values for all fields
562
+ defaults = {}
563
+ for field_name, field_info in self.atype.model_fields.items():
564
+ if field_info.is_required():
565
+ # Provide sensible defaults based on field type
566
+ if hasattr(field_info.annotation, "__origin__"):
567
+ origin = field_info.annotation.__origin__
568
+ if origin is list:
569
+ defaults[field_name] = []
570
+ elif origin is dict:
571
+ defaults[field_name] = {}
572
+ else:
573
+ defaults[field_name] = None
574
+ else:
575
+ defaults[field_name] = None
576
+ return self.atype.model_construct(**defaults)
577
+
578
+ if isinstance(other, AG):
579
+ # Match the number of states in other
580
+ self.states = [create_empty_state() for _ in range(len(other.states))]
581
+ elif is_str_or_list_of_str(other):
582
+ # For strings or list of strings, create one state per input
583
+ if isinstance(other, str):
584
+ self.states = [create_empty_state()]
585
+ else:
586
+ self.states = [create_empty_state() for _ in range(len(other))]
587
+ elif isinstance(other, list):
588
+ # For other lists, create one state per item
589
+ self.states = [create_empty_state() for _ in range(len(other))]
590
+ else:
591
+ # For single non-list inputs, create one state
592
+ self.states = [create_empty_state()]
593
+
552
594
  if isinstance(other, AG):
553
595
  if other.prompt_template:
554
596
  prompt_template = PromptTemplate.from_template(other.prompt_template)
@@ -673,19 +715,37 @@ class AG(BaseModel, Generic[T]):
673
715
  )
674
716
  allowed = self.atype.model_fields.keys() # pydantic v2
675
717
  filtered = {k: v for k, v in data.items() if k in allowed}
676
- merged = self.atype(**filtered)
718
+ try:
719
+ merged = self.atype(**filtered)
720
+ except Exception:
721
+ # If validation fails due to missing required fields, use model_construct with defaults
722
+ defaults = {}
723
+ for field_name, field_info in self.atype.model_fields.items():
724
+ if field_info.is_required() and field_name not in filtered:
725
+ # Provide sensible defaults based on field type
726
+ if hasattr(field_info.annotation, "__origin__"):
727
+ origin = field_info.annotation.__origin__
728
+ if origin is list:
729
+ defaults[field_name] = []
730
+ elif origin is dict:
731
+ defaults[field_name] = {}
732
+ else:
733
+ defaults[field_name] = None
734
+ else:
735
+ defaults[field_name] = None
736
+ merged = self.atype.model_construct(**{**defaults, **filtered})
677
737
 
678
738
  output.states.append(merged)
679
739
  # elif is_str_or_list_of_str(other):
680
740
  elif isinstance(other, list):
681
741
  for i in range(len(other)):
682
- if isinstance(output_states[i], self.atype):
742
+ if i < len(output_states) and isinstance(output_states[i], self.atype):
683
743
  output.states.append(self.atype(**output_states[i].model_dump()))
684
744
  else:
685
745
  output.states.append(self.atype())
686
746
  else:
687
- if isinstance(output_states[0], self.atype):
688
- output.states.append(self.atype(**output_states[i].model_dump()))
747
+ if len(output_states) > 0 and isinstance(output_states[0], self.atype):
748
+ output.states.append(self.atype(**output_states[0].model_dump()))
689
749
 
690
750
  if self.provide_explanations and isinstance(other, AG):
691
751
  target_explanation = AG(atype=Explanation)
File without changes
File without changes
File without changes
File without changes