Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ dependencies = [
"duckdb>=1.4.3",
"pandas>=2",
"async-lru>=2.0.5",
"apscheduler>=3.10.0",
"fastapi-sso>=0.10.0",
]


Expand Down
17 changes: 11 additions & 6 deletions src/agentics/core/agentics.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class AG(BaseModel, Generic[T]):
None,
description="""Python code for the used type""",
)
states: List[BaseModel] = []
states: List[BaseModel] = Field(default_factory=list)
tools: Optional[List[Any]] = Field(None, exclude=True)
transduce_fields: Optional[List[str]] = Field(
None,
Expand Down Expand Up @@ -138,11 +138,11 @@ class AG(BaseModel, Generic[T]):
20,
description="The size of the bathes to be used when transduction type is amap",
)
areduce_batches: List[BaseModel] = []
areduce_batches: List[BaseModel] = Field(default_factory=list)
save_amap_batches_to_path: Optional[str] = None

crew_prompt_params: Optional[Dict[str, str]] = Field(
{
default_factory=lambda: {
"role": "Task Executor",
"goal": "You execute tasks",
"backstory": "You are always faithful and provide only fact based answers.",
Expand Down Expand Up @@ -1063,21 +1063,26 @@ def product(self, other: AG) -> AG:

def merge_states(self, other: AG) -> AG:
"""
Merge states of two AGs pairwise

Merge states of two AGs pairwise.

The 'other' AG's fields take precedence over 'self' fields when there are conflicts.
This ensures that newly generated data (other) overwrites existing data (self).
"""
if len(self) == len(other):
merged = self.clone()
merged.states = []
merged.explanations = []
# Put self.atype first so its fields appear first in the merged schema,
# but other.atype values will overwrite in the instance creation below
merged.atype = merge_pydantic_models(
self.atype,
other.atype,
name=f"Merged{self.atype.__name__}#{other.atype.__name__}",
)
# Create instances with self first, then other overwrites
for self_state, other_state in zip(self, other):
merged.states.append(
merged.atype(**other_state.model_dump(), **self_state.model_dump())
merged.atype(**self_state.model_dump(), **other_state.model_dump())
)
return merged
else:
Expand Down
12 changes: 10 additions & 2 deletions src/agentics/core/mellea_pydantic_transducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,21 @@ async def structured_decoding_using_mellea(
# At this point we're outside the `with`: session should be closed

if mellea_output is None or mellea_output.content is None:
return targetAtype()
logging.warning(
f"Received None or empty response from LLM call. "
f"LLM: {llm}, Input length: {len(input)} chars. "
f"Check LLM configuration, API credentials, and model availability."
)
raise ValueError(
"Invalid response from LLM call - None or empty. "
"Please check your LLM configuration and API credentials."
)

raw = mellea_output.content
# If Mellea gave us a dict-like object:
if isinstance(raw, dict):
return targetAtype.model_validate(raw)
# If its a JSON string:
# If it's a JSON string:
if isinstance(raw, str):
return targetAtype.model_validate_json(raw)

Expand Down
Loading