From 528883d7df61962c2c88b5f0a0ac721bc02a9f81 Mon Sep 17 00:00:00 2001 From: ahmetgunduz Date: Fri, 29 Aug 2025 10:11:28 +0000 Subject: [PATCH 1/2] ENG-2501 evolver params renaming --- aixplain/modules/agent/__init__.py | 44 +++--- aixplain/modules/agent/evolve_param.py | 145 +++++++++++--------- aixplain/modules/team_agent/__init__.py | 48 +++---- aixplain/utils/evolve_utils.py | 30 ++-- tests/functional/team_agent/evolver_test.py | 4 +- tests/unit/agent/evolve_param_test.py | 106 +++++++------- tests/unit/agent/test_agent_evolve.py | 40 +++--- tests/unit/agent/test_evolver_llm_utils.py | 42 +++--- 8 files changed, 236 insertions(+), 223 deletions(-) diff --git a/aixplain/modules/agent/__init__.py b/aixplain/modules/agent/__init__.py index af32bdb3..095eb598 100644 --- a/aixplain/modules/agent/__init__.py +++ b/aixplain/modules/agent/__init__.py @@ -749,9 +749,9 @@ def evolve_async( evolve_type: Union[EvolveType, str] = EvolveType.TEAM_TUNING, max_successful_generations: int = 3, max_failed_generation_retries: int = 3, - recursion_limit: int = 50, + max_iterations: int = 50, max_non_improving_generations: Optional[int] = 2, - evolver_llm: Optional[Union[Text, LLM]] = None, + llm: Optional[Union[Text, LLM]] = None, ) -> AgentResponse: """Asynchronously evolve the Agent and return a polling URL in the AgentResponse. @@ -759,14 +759,14 @@ def evolve_async( evolve_type (Union[EvolveType, str]): Type of evolution (TEAM_TUNING or INSTRUCTION_TUNING). Defaults to TEAM_TUNING. max_successful_generations (int): Maximum number of successful generations to evolve. Defaults to 3. max_failed_generation_retries (int): Maximum retry attempts for failed generations. Defaults to 3. - recursion_limit (int): Limit for recursive operations. Defaults to 50. + max_iterations (int): Maximum number of iterations. Defaults to 50. max_non_improving_generations (Optional[int]): Stop condition parameter for non-improving generations. Defaults to 2, can be None. - evolver_llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. + llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. Returns: AgentResponse: Response containing polling URL and status. """ - from aixplain.utils.evolve_utils import create_evolver_llm_dict + from aixplain.utils.evolve_utils import create_llm_dict query = "" @@ -774,11 +774,11 @@ def evolve_async( evolve_parameters = EvolveParam( to_evolve=True, evolve_type=evolve_type, - max_generations=max_successful_generations, - max_retries=max_failed_generation_retries, - recursion_limit=recursion_limit, - max_iterations_without_improvement=max_non_improving_generations, - evolver_llm=create_evolver_llm_dict(evolver_llm), + max_successful_generations=max_successful_generations, + max_failed_generation_retries=max_failed_generation_retries, + max_iterations=max_iterations, + max_non_improving_generations=max_non_improving_generations, + llm=create_llm_dict(llm), ) return self.run_async(query=query, evolve=evolve_parameters) @@ -788,9 +788,9 @@ def evolve( evolve_type: Union[EvolveType, str] = EvolveType.TEAM_TUNING, max_successful_generations: int = 3, max_failed_generation_retries: int = 3, - recursion_limit: int = 50, + max_iterations: int = 50, max_non_improving_generations: Optional[int] = 2, - evolver_llm: Optional[Union[Text, LLM]] = None, + llm: Optional[Union[Text, LLM]] = None, ) -> AgentResponse: """Synchronously evolve the Agent and poll for the result. @@ -798,24 +798,24 @@ def evolve( evolve_type (Union[EvolveType, str]): Type of evolution (TEAM_TUNING or INSTRUCTION_TUNING). Defaults to TEAM_TUNING. max_successful_generations (int): Maximum number of successful generations to evolve. Defaults to 3. max_failed_generation_retries (int): Maximum retry attempts for failed generations. Defaults to 3. - recursion_limit (int): Limit for recursive operations. Defaults to 50. + max_iterations (int): Maximum number of iterations. Defaults to 50. max_non_improving_generations (Optional[int]): Stop condition parameter for non-improving generations. Defaults to 2, can be None. - evolver_llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. + llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. Returns: AgentResponse: Final response from the evolution process. """ - from aixplain.utils.evolve_utils import from_yaml, create_evolver_llm_dict + from aixplain.utils.evolve_utils import from_yaml, create_llm_dict # Create EvolveParam from individual parameters evolve_parameters = EvolveParam( to_evolve=True, evolve_type=evolve_type, - max_generations=max_successful_generations, - max_retries=max_failed_generation_retries, - recursion_limit=recursion_limit, - max_iterations_without_improvement=max_non_improving_generations, - evolver_llm=create_evolver_llm_dict(evolver_llm), + max_successful_generations=max_successful_generations, + max_failed_generation_retries=max_failed_generation_retries, + max_iterations=max_iterations, + max_non_improving_generations=max_non_improving_generations, + llm=create_llm_dict(llm), ) start = time.time() @@ -826,9 +826,9 @@ def evolve( evolve_type=evolve_type, max_successful_generations=max_successful_generations, max_failed_generation_retries=max_failed_generation_retries, - recursion_limit=recursion_limit, + max_iterations=max_iterations, max_non_improving_generations=max_non_improving_generations, - evolver_llm=evolver_llm, + llm=llm, ) if response["status"] == ResponseStatus.FAILED: end = time.time() diff --git a/aixplain/modules/agent/evolve_param.py b/aixplain/modules/agent/evolve_param.py index c622f90b..1693293e 100644 --- a/aixplain/modules/agent/evolve_param.py +++ b/aixplain/modules/agent/evolve_param.py @@ -32,21 +32,21 @@ class EvolveParam: Attributes: to_evolve (bool): Whether to enable evolution. Defaults to False. evolve_type (Optional[EvolveType]): Type of evolve. - max_generations (int): Maximum number of generations. - max_retries (int): Maximum number of retries. - recursion_limit (int): Maximum number of recursion. - max_iterations_without_improvement (int): Maximum number of iterations without improvement. - evolver_llm (Optional[Dict[str, Any]]): Evolver LLM configuration with all parameters. + max_successful_generations (int): Maximum number of successful generations. + max_failed_generation_retries (int): Maximum number of failed generation retries. + max_iterations (int): Maximum number of iterations. + max_non_improving_generations (Optional[int]): Maximum number of non-improving generations. + llm (Optional[Dict[str, Any]]): LLM configuration with all parameters. additional_params (Optional[Dict[str, Any]]): Additional parameters. """ to_evolve: bool = False evolve_type: Optional[EvolveType] = EvolveType.TEAM_TUNING - max_generations: int = 3 - max_retries: int = 3 - recursion_limit: int = 50 - max_iterations_without_improvement: Optional[int] = 2 - evolver_llm: Optional[Dict[str, Any]] = None + max_successful_generations: int = 3 + max_failed_generation_retries: int = 3 + max_iterations: int = 50 + max_non_improving_generations: Optional[int] = 2 + llm: Optional[Dict[str, Any]] = None additional_params: Optional[Dict[str, Any]] = field(default_factory=dict) def __post_init__(self): @@ -74,29 +74,34 @@ def validate(self) -> None: if not isinstance(self.additional_params, dict): raise ValueError("additional_params must be a dictionary") - if self.max_generations is not None: - if not isinstance(self.max_generations, int): - raise ValueError("max_generations must be an integer") - if self.max_generations <= 0: - raise ValueError("max_generations must be positive") - - if self.max_retries is not None: - if not isinstance(self.max_retries, int): - raise ValueError("max_retries must be an integer") - if self.max_retries <= 0: - raise ValueError("max_retries must be positive") - - if self.recursion_limit is not None: - if not isinstance(self.recursion_limit, int): - raise ValueError("recursion_limit must be an integer") - if self.recursion_limit <= 0: - raise ValueError("recursion_limit must be positive") - - if self.max_iterations_without_improvement is not None: - if not isinstance(self.max_iterations_without_improvement, int): - raise ValueError("max_iterations_without_improvement must be an integer or None") - if self.max_iterations_without_improvement <= 0: - raise ValueError("max_iterations_without_improvement must be positive or None") + if self.max_successful_generations is not None: + if not isinstance(self.max_successful_generations, int): + raise ValueError("max_successful_generations must be an integer") + if self.max_successful_generations <= 0: + raise ValueError("max_successful_generations must be positive") + + if self.max_failed_generation_retries is not None: + if not isinstance(self.max_failed_generation_retries, int): + raise ValueError("max_failed_generation_retries must be an integer") + if self.max_failed_generation_retries <= 0: + raise ValueError("max_failed_generation_retries must be positive") + + if self.max_iterations is not None: + if not isinstance(self.max_iterations, int): + raise ValueError("max_iterations must be an integer") + if self.max_iterations <= 0: + raise ValueError("max_iterations must be positive") + + if self.max_non_improving_generations is not None: + if not isinstance(self.max_non_improving_generations, int): + raise ValueError("max_non_improving_generations must be an integer or None") + if self.max_non_improving_generations <= 0: + raise ValueError("max_non_improving_generations must be positive or None") + + # Add validation for llm parameter + if self.llm is not None: + if not isinstance(self.llm, dict): + raise ValueError("llm must be a dictionary or None") @classmethod def from_dict(cls, data: Union[Dict[str, Any], None]) -> "EvolveParam": @@ -121,11 +126,11 @@ def from_dict(cls, data: Union[Dict[str, Any], None]) -> "EvolveParam": known_params = { "to_evolve": data.get("toEvolve", data.get("to_evolve", False)), "evolve_type": data.get("evolve_type"), - "max_generations": data.get("max_generations"), - "max_retries": data.get("max_retries"), - "recursion_limit": data.get("recursion_limit"), - "max_iterations_without_improvement": data.get("max_iterations_without_improvement"), - "evolver_llm": data.get("evolver_llm"), + "max_successful_generations": data.get("max_successful_generations"), + "max_failed_generation_retries": data.get("max_failed_generation_retries"), + "max_iterations": data.get("max_iterations"), + "max_non_improving_generations": data.get("max_non_improving_generations"), + "llm": data.get("llm"), "additional_params": data.get("additional_params"), } @@ -141,11 +146,11 @@ def from_dict(cls, data: Union[Dict[str, Any], None]) -> "EvolveParam": "toEvolve", "to_evolve", "evolve_type", - "max_generations", - "max_retries", - "recursion_limit", - "max_iterations_without_improvement", - "evolver_llm", + "max_successful_generations", + "max_failed_generation_retries", + "max_iterations", + "max_non_improving_generations", + "llm", "additional_params", ] } @@ -165,16 +170,16 @@ def to_dict(self) -> Dict[str, Any]: # Add optional parameters if they are set if self.evolve_type is not None: result["evolve_type"] = self.evolve_type - if self.max_generations is not None: - result["max_generations"] = self.max_generations - if self.max_retries is not None: - result["max_retries"] = self.max_retries - if self.recursion_limit is not None: - result["recursion_limit"] = self.recursion_limit - # Always include max_iterations_without_improvement, even if None - result["max_iterations_without_improvement"] = self.max_iterations_without_improvement - if self.evolver_llm is not None: - result["evolver_llm"] = self.evolver_llm + if self.max_successful_generations is not None: + result["max_successful_generations"] = self.max_successful_generations + if self.max_failed_generation_retries is not None: + result["max_failed_generation_retries"] = self.max_failed_generation_retries + if self.max_iterations is not None: + result["max_iterations"] = self.max_iterations + # Always include max_non_improving_generations, even if None + result["max_non_improving_generations"] = self.max_non_improving_generations + if self.llm is not None: + result["llm"] = self.llm if self.additional_params is not None: result.update(self.additional_params) @@ -200,15 +205,23 @@ def merge(self, other: Union[Dict[str, Any], "EvolveParam"]) -> "EvolveParam": return EvolveParam( to_evolve=other.to_evolve if other.to_evolve else self.to_evolve, evolve_type=(other.evolve_type if other.evolve_type is not None else self.evolve_type), - max_generations=(other.max_generations if other.max_generations is not None else self.max_generations), - max_retries=(other.max_retries if other.max_retries is not None else self.max_retries), - recursion_limit=(other.recursion_limit if other.recursion_limit is not None else self.recursion_limit), - max_iterations_without_improvement=( - other.max_iterations_without_improvement - if other.max_iterations_without_improvement is not None - else self.max_iterations_without_improvement + max_successful_generations=( + other.max_successful_generations + if other.max_successful_generations is not None + else self.max_successful_generations ), - evolver_llm=(other.evolver_llm if other.evolver_llm is not None else self.evolver_llm), + max_failed_generation_retries=( + other.max_failed_generation_retries + if other.max_failed_generation_retries is not None + else self.max_failed_generation_retries + ), + max_iterations=(other.max_iterations if other.max_iterations is not None else self.max_iterations), + max_non_improving_generations=( + other.max_non_improving_generations + if other.max_non_improving_generations is not None + else self.max_non_improving_generations + ), + llm=(other.llm if other.llm is not None else self.llm), additional_params=merged_additional, ) @@ -217,11 +230,11 @@ def __repr__(self) -> str: f"EvolveParam(" f"to_evolve={self.to_evolve}, " f"evolve_type={self.evolve_type}, " - f"max_generations={self.max_generations}, " - f"max_retries={self.max_retries}, " - f"recursion_limit={self.recursion_limit}, " - f"max_iterations_without_improvement={self.max_iterations_without_improvement}, " - f"evolver_llm={self.evolver_llm}, " + f"max_successful_generations={self.max_successful_generations}, " + f"max_failed_generation_retries={self.max_failed_generation_retries}, " + f"max_iterations={self.max_iterations}, " + f"max_non_improving_generations={self.max_non_improving_generations}, " + f"llm={self.llm}, " f"additional_params={self.additional_params})" ) diff --git a/aixplain/modules/team_agent/__init__.py b/aixplain/modules/team_agent/__init__.py index 077026ac..55b36bab 100644 --- a/aixplain/modules/team_agent/__init__.py +++ b/aixplain/modules/team_agent/__init__.py @@ -806,9 +806,9 @@ def evolve_async( evolve_type: Union[EvolveType, str] = EvolveType.TEAM_TUNING, max_successful_generations: int = 3, max_failed_generation_retries: int = 3, - recursion_limit: int = 50, + max_iterations: int = 50, max_non_improving_generations: Optional[int] = 2, - evolver_llm: Optional[Union[Text, LLM]] = None, + llm: Optional[Union[Text, LLM]] = None, ) -> AgentResponse: """Asynchronously evolve the Team Agent and return a polling URL in the AgentResponse. @@ -816,26 +816,26 @@ def evolve_async( evolve_type (Union[EvolveType, str]): Type of evolution (TEAM_TUNING or INSTRUCTION_TUNING). Defaults to TEAM_TUNING. max_successful_generations (int): Maximum number of successful generations to evolve. Defaults to 3. max_failed_generation_retries (int): Maximum retry attempts for failed generations. Defaults to 3. - recursion_limit (int): Limit for recursive operations. Defaults to 50. + max_iterations (int): Maximum number of iterations. Defaults to 50. max_non_improving_generations (Optional[int]): Stop condition parameter for non-improving generations. Defaults to 2, can be None. - evolver_llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. + llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. Returns: AgentResponse: Response containing polling URL and status. """ - from aixplain.utils.evolve_utils import create_evolver_llm_dict + from aixplain.utils.evolve_utils import create_llm_dict query = "" - # Create EvolveParam from individual parameters (map new names to old keys) + # Create EvolveParam from individual parameters evolve_parameters = EvolveParam( to_evolve=True, evolve_type=evolve_type, - max_generations=max_successful_generations, - max_retries=max_failed_generation_retries, - recursion_limit=recursion_limit, - max_iterations_without_improvement=max_non_improving_generations, - evolver_llm=create_evolver_llm_dict(evolver_llm), + max_successful_generations=max_successful_generations, + max_failed_generation_retries=max_failed_generation_retries, + max_iterations=max_iterations, + max_non_improving_generations=max_non_improving_generations, + llm=create_llm_dict(llm), ) response = self.run_async(query=query, evolve=evolve_parameters) @@ -846,9 +846,9 @@ def evolve( evolve_type: Union[EvolveType, str] = EvolveType.TEAM_TUNING, max_successful_generations: int = 3, max_failed_generation_retries: int = 3, - recursion_limit: int = 50, + max_iterations: int = 50, max_non_improving_generations: Optional[int] = 2, - evolver_llm: Optional[Union[Text, LLM]] = None, + llm: Optional[Union[Text, LLM]] = None, ) -> AgentResponse: """Synchronously evolve the Team Agent and poll for the result. @@ -856,25 +856,25 @@ def evolve( evolve_type (Union[EvolveType, str]): Type of evolution (TEAM_TUNING or INSTRUCTION_TUNING). Defaults to TEAM_TUNING. max_successful_generations (int): Maximum number of successful generations to evolve. Defaults to 3. max_failed_generation_retries (int): Maximum retry attempts for failed generations. Defaults to 3. - recursion_limit (int): Limit for recursive operations. Defaults to 50. + max_iterations (int): Maximum number of iterations. Defaults to 50. max_non_improving_generations (Optional[int]): Stop condition parameter for non-improving generations. Defaults to 2, can be None. - evolver_llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. + llm (Optional[Union[Text, LLM]]): LLM to use for evolution. Can be an LLM ID string or LLM object. Defaults to None. Returns: AgentResponse: Final response from the evolution process. """ from aixplain.enums import EvolveType - from aixplain.utils.evolve_utils import from_yaml, create_evolver_llm_dict + from aixplain.utils.evolve_utils import from_yaml, create_llm_dict - # Create EvolveParam from individual parameters (map new names to old keys) + # Create EvolveParam from individual parameters evolve_parameters = EvolveParam( to_evolve=True, evolve_type=evolve_type, - max_generations=max_successful_generations, - max_retries=max_failed_generation_retries, - recursion_limit=recursion_limit, - max_iterations_without_improvement=max_non_improving_generations, - evolver_llm=create_evolver_llm_dict(evolver_llm), + max_successful_generations=max_successful_generations, + max_failed_generation_retries=max_failed_generation_retries, + max_iterations=max_iterations, + max_non_improving_generations=max_non_improving_generations, + llm=create_llm_dict(llm), ) start = time.time() try: @@ -884,9 +884,9 @@ def evolve( evolve_type=evolve_type, max_successful_generations=max_successful_generations, max_failed_generation_retries=max_failed_generation_retries, - recursion_limit=recursion_limit, + max_iterations=max_iterations, max_non_improving_generations=max_non_improving_generations, - evolver_llm=evolver_llm, + llm=llm, ) if response["status"] == ResponseStatus.FAILED: end = time.time() diff --git a/aixplain/utils/evolve_utils.py b/aixplain/utils/evolve_utils.py index 8e1b1c92..2b021bd2 100644 --- a/aixplain/utils/evolve_utils.py +++ b/aixplain/utils/evolve_utils.py @@ -7,31 +7,31 @@ from aixplain.factories import AgentFactory, TeamAgentFactory -def create_evolver_llm_dict(evolver_llm: Optional[Union[Text, LLM]]) -> Optional[Dict[str, Any]]: - """Create a dictionary representation of an evolver LLM for evolution parameters. +def create_llm_dict(llm: Optional[Union[Text, LLM]]) -> Optional[Dict[str, Any]]: + """Create a dictionary representation of an LLM for evolution parameters. Args: - evolver_llm: Either an LLM ID string or an LLM object instance. + llm: Either an LLM ID string or an LLM object instance. Returns: - Dictionary with LLM information if evolver_llm is provided, None otherwise. + Dictionary with LLM information if llm is provided, None otherwise. """ - if evolver_llm is None: + if llm is None: return None - if isinstance(evolver_llm, LLM): + if isinstance(llm, LLM): return { - "id": evolver_llm.id, - "name": evolver_llm.name, - "description": evolver_llm.description, - "supplier": evolver_llm.supplier, - "version": evolver_llm.version, - "function": evolver_llm.function, - "parameters": (evolver_llm.get_parameters().to_list() if evolver_llm.get_parameters() else None), - "temperature": getattr(evolver_llm, "temperature", None), + "id": llm.id, + "name": llm.name, + "description": llm.description, + "supplier": llm.supplier, + "version": llm.version, + "function": llm.function, + "parameters": (llm.get_parameters().to_list() if llm.get_parameters() else None), + "temperature": getattr(llm, "temperature", None), } else: - return {"id": evolver_llm} + return {"id": llm} def generate_tools_from_str(tools: list) -> list: diff --git a/tests/functional/team_agent/evolver_test.py b/tests/functional/team_agent/evolver_test.py index 4edf0c39..47c45e45 100644 --- a/tests/functional/team_agent/evolver_test.py +++ b/tests/functional/team_agent/evolver_test.py @@ -130,8 +130,8 @@ def test_evolver_with_custom_llm_id(team_agent): """Test evolver functionality with custom LLM ID""" custom_llm_id = "6646261c6eb563165658bbb1" # GPT-4o ID - # Test with evolver_llm parameter - response = team_agent.evolve_async(evolver_llm=custom_llm_id) + # Test with llm parameter + response = team_agent.evolve_async(llm=custom_llm_id) assert response is not None assert "url" in response or response.get("url") is not None diff --git a/tests/unit/agent/evolve_param_test.py b/tests/unit/agent/evolve_param_test.py index b108c146..2f0f744e 100644 --- a/tests/unit/agent/evolve_param_test.py +++ b/tests/unit/agent/evolve_param_test.py @@ -20,11 +20,11 @@ def test_default_initialization(self): assert default_param is not None assert default_param.to_evolve is False assert default_param.evolve_type == EvolveType.TEAM_TUNING - assert default_param.max_generations == 3 - assert default_param.max_retries == 3 - assert default_param.recursion_limit == 50 - assert default_param.max_iterations_without_improvement == 2 - assert default_param.evolver_llm is None + assert default_param.max_successful_generations == 3 + assert default_param.max_failed_generation_retries == 3 + assert default_param.max_iterations == 50 + assert default_param.max_non_improving_generations == 2 + assert default_param.llm is None assert default_param.additional_params == {} # Test to_dict method @@ -36,65 +36,65 @@ def test_custom_initialization(self): """Test EvolveParam custom initialization""" custom_param = EvolveParam( to_evolve=True, - max_generations=5, - max_retries=2, - recursion_limit=30, - max_iterations_without_improvement=4, + max_successful_generations=5, + max_failed_generation_retries=2, + max_iterations=30, + max_non_improving_generations=4, evolve_type=EvolveType.TEAM_TUNING, - evolver_llm={"id": "test_llm_id", "name": "Test LLM"}, + llm={"id": "test_llm_id", "name": "Test LLM"}, additional_params={"customParam": "custom_value"}, ) assert custom_param.to_evolve is True - assert custom_param.max_generations == 5 - assert custom_param.max_retries == 2 - assert custom_param.recursion_limit == 30 - assert custom_param.max_iterations_without_improvement == 4 + assert custom_param.max_successful_generations == 5 + assert custom_param.max_failed_generation_retries == 2 + assert custom_param.max_iterations == 30 + assert custom_param.max_non_improving_generations == 4 assert custom_param.evolve_type == EvolveType.TEAM_TUNING - assert custom_param.evolver_llm == {"id": "test_llm_id", "name": "Test LLM"} + assert custom_param.llm == {"id": "test_llm_id", "name": "Test LLM"} assert custom_param.additional_params == {"customParam": "custom_value"} # Test to_dict method result_dict = custom_param.to_dict() assert result_dict["toEvolve"] is True - assert result_dict["max_generations"] == 5 - assert result_dict["max_retries"] == 2 - assert result_dict["recursion_limit"] == 30 - assert result_dict["max_iterations_without_improvement"] == 4 + assert result_dict["max_successful_generations"] == 5 + assert result_dict["max_failed_generation_retries"] == 2 + assert result_dict["max_iterations"] == 30 + assert result_dict["max_non_improving_generations"] == 4 assert result_dict["evolve_type"] == EvolveType.TEAM_TUNING - assert result_dict["evolver_llm"] == {"id": "test_llm_id", "name": "Test LLM"} + assert result_dict["llm"] == {"id": "test_llm_id", "name": "Test LLM"} assert result_dict["customParam"] == "custom_value" def test_from_dict_with_api_format(self): """Test EvolveParam from_dict() with API format""" api_dict = { "toEvolve": True, - "max_generations": 10, - "max_retries": 4, - "recursion_limit": 40, - "max_iterations_without_improvement": 5, + "max_successful_generations": 10, + "max_failed_generation_retries": 4, + "max_iterations": 40, + "max_non_improving_generations": 5, "evolve_type": EvolveType.TEAM_TUNING, - "evolver_llm": {"id": "api_llm_id", "name": "API LLM"}, + "llm": {"id": "api_llm_id", "name": "API LLM"}, "customParam": "custom_value", } from_dict_param = EvolveParam.from_dict(api_dict) assert from_dict_param.to_evolve is True - assert from_dict_param.max_generations == 10 - assert from_dict_param.max_retries == 4 - assert from_dict_param.recursion_limit == 40 - assert from_dict_param.max_iterations_without_improvement == 5 + assert from_dict_param.max_successful_generations == 10 + assert from_dict_param.max_failed_generation_retries == 4 + assert from_dict_param.max_iterations == 40 + assert from_dict_param.max_non_improving_generations == 5 assert from_dict_param.evolve_type == EvolveType.TEAM_TUNING - assert from_dict_param.evolver_llm == {"id": "api_llm_id", "name": "API LLM"} + assert from_dict_param.llm == {"id": "api_llm_id", "name": "API LLM"} # Test round-trip conversion result_dict = from_dict_param.to_dict() assert result_dict["toEvolve"] is True - assert result_dict["max_generations"] == 10 - assert result_dict["max_retries"] == 4 - assert result_dict["recursion_limit"] == 40 - assert result_dict["max_iterations_without_improvement"] == 5 + assert result_dict["max_successful_generations"] == 10 + assert result_dict["max_failed_generation_retries"] == 4 + assert result_dict["max_iterations"] == 40 + assert result_dict["max_non_improving_generations"] == 5 def test_validate_evolve_param_with_none(self): """Test validate_evolve_param() with None input""" @@ -109,27 +109,27 @@ def test_validate_evolve_param_with_none(self): def test_validate_evolve_param_with_dict(self): """Test validate_evolve_param() with dictionary input""" - input_dict = {"toEvolve": True, "max_generations": 5} + input_dict = {"toEvolve": True, "max_successful_generations": 5} validated_dict = validate_evolve_param(input_dict) assert isinstance(validated_dict, EvolveParam) assert validated_dict.to_evolve is True - assert validated_dict.max_generations == 5 + assert validated_dict.max_successful_generations == 5 result_dict = validated_dict.to_dict() assert result_dict["toEvolve"] is True - assert result_dict["max_generations"] == 5 + assert result_dict["max_successful_generations"] == 5 def test_validate_evolve_param_with_instance(self): """Test validate_evolve_param() with EvolveParam instance""" custom_param = EvolveParam( to_evolve=True, - max_generations=5, - max_retries=2, - recursion_limit=30, - max_iterations_without_improvement=4, + max_successful_generations=5, + max_failed_generation_retries=2, + max_iterations=30, + max_non_improving_generations=4, evolve_type=EvolveType.TEAM_TUNING, - evolver_llm={"id": "instance_llm_id"}, + llm={"id": "instance_llm_id"}, additional_params={"customParam": "custom_value"}, ) @@ -137,13 +137,13 @@ def test_validate_evolve_param_with_instance(self): assert validated_instance is custom_param # Should return the same instance assert validated_instance.to_evolve is True - assert validated_instance.max_generations == 5 - assert validated_instance.max_retries == 2 + assert validated_instance.max_successful_generations == 5 + assert validated_instance.max_failed_generation_retries == 2 - def test_invalid_max_generations_raises_error(self): - """Test that invalid max_generations raises ValueError""" - with pytest.raises(ValueError, match="max_generations must be positive"): - EvolveParam(max_generations=0) # max_generations <= 0 should fail + def test_invalid_max_successful_generations_raises_error(self): + """Test that invalid max_successful_generations raises ValueError""" + with pytest.raises(ValueError, match="max_successful_generations must be positive"): + EvolveParam(max_successful_generations=0) # max_successful_generations <= 0 should fail def test_validate_evolve_param_missing_to_evolve_key(self): """Test that missing toEvolve key raises ValueError""" @@ -168,19 +168,19 @@ def test_invalid_additional_params_type(self): def test_merge_with_dict(self): """Test merging with a dictionary""" - base_param = EvolveParam(to_evolve=False, max_generations=3, additional_params={"base": "value"}) + base_param = EvolveParam(to_evolve=False, max_successful_generations=3, additional_params={"base": "value"}) merge_dict = { "toEvolve": True, - "max_generations": 5, - "evolver_llm": {"id": "merged_llm_id"}, + "max_successful_generations": 5, + "llm": {"id": "merged_llm_id"}, "customParam": "custom_value", } merged = base_param.merge(merge_dict) assert merged.to_evolve is True - assert merged.max_generations == 5 - assert merged.evolver_llm == {"id": "merged_llm_id"} + assert merged.max_successful_generations == 5 + assert merged.llm == {"id": "merged_llm_id"} assert merged.additional_params == { "base": "value", "customParam": "custom_value", diff --git a/tests/unit/agent/test_agent_evolve.py b/tests/unit/agent/test_agent_evolve.py index 1aa6cd70..f4aa1990 100644 --- a/tests/unit/agent/test_agent_evolve.py +++ b/tests/unit/agent/test_agent_evolve.py @@ -1,5 +1,5 @@ """ -Unit tests for Agent evolve functionality with evolver_llm parameter +Unit tests for Agent evolve functionality with llm parameter """ import pytest @@ -43,8 +43,8 @@ def mock_llm(self): return llm - def test_evolve_async_with_evolver_llm_string(self, mock_agent): - """Test evolve_async with evolver_llm as string ID""" + def test_evolve_async_with_llm_string(self, mock_agent): + """Test evolve_async with llm as string ID""" from aixplain.modules.agent import Agent # Create a real Agent instance but mock its methods @@ -67,21 +67,21 @@ def test_evolve_async_with_evolver_llm_string(self, mock_agent): ) with patch.object(agent, "run_async", return_value=mock_response) as mock_run_async: - result = agent.evolve_async(evolver_llm="custom_llm_id_123") + result = agent.evolve_async(llm="custom_llm_id_123") # Verify run_async was called with correct evolve parameter mock_run_async.assert_called_once() call_args = mock_run_async.call_args - # Check that evolve parameter contains evolver_llm + # Check that evolve parameter contains llm evolve_param = call_args[1]["evolve"] assert isinstance(evolve_param, EvolveParam) - assert evolve_param.evolver_llm == {"id": "custom_llm_id_123"} + assert evolve_param.llm == {"id": "custom_llm_id_123"} assert result == mock_response - def test_evolve_async_with_evolver_llm_object(self, mock_agent, mock_llm): - """Test evolve_async with evolver_llm as LLM object""" + def test_evolve_async_with_llm_object(self, mock_agent, mock_llm): + """Test evolve_async with llm as LLM object""" from aixplain.modules.agent import Agent # Create a real Agent instance but mock its methods @@ -104,13 +104,13 @@ def test_evolve_async_with_evolver_llm_object(self, mock_agent, mock_llm): ) with patch.object(agent, "run_async", return_value=mock_response) as mock_run_async: - result = agent.evolve_async(evolver_llm=mock_llm) + result = agent.evolve_async(llm=mock_llm) # Verify run_async was called with correct evolve parameter mock_run_async.assert_called_once() call_args = mock_run_async.call_args - # Check that evolve parameter contains evolver_llm + # Check that evolve parameter contains llm evolve_param = call_args[1]["evolve"] assert isinstance(evolve_param, EvolveParam) @@ -124,12 +124,12 @@ def test_evolve_async_with_evolver_llm_object(self, mock_agent, mock_llm): "parameters": [{"name": "temperature", "type": "float"}], "temperature": 0.7, } - assert evolve_param.evolver_llm == expected_llm_dict + assert evolve_param.llm == expected_llm_dict assert result == mock_response - def test_evolve_async_without_evolver_llm(self, mock_agent): - """Test evolve_async without evolver_llm parameter""" + def test_evolve_async_without_llm(self, mock_agent): + """Test evolve_async without llm parameter""" from aixplain.modules.agent import Agent # Create a real Agent instance but mock its methods @@ -158,15 +158,15 @@ def test_evolve_async_without_evolver_llm(self, mock_agent): mock_run_async.assert_called_once() call_args = mock_run_async.call_args - # Check that evolve parameter has evolver_llm as None + # Check that evolve parameter has llm as None evolve_param = call_args[1]["evolve"] assert isinstance(evolve_param, EvolveParam) - assert evolve_param.evolver_llm is None + assert evolve_param.llm is None assert result == mock_response def test_evolve_with_custom_parameters(self, mock_agent): - """Test evolve with custom parameters including evolver_llm""" + """Test evolve with custom parameters including llm""" from aixplain.modules.agent import Agent # Create a real Agent instance but mock its methods @@ -193,9 +193,9 @@ def test_evolve_with_custom_parameters(self, mock_agent): evolve_type=EvolveType.TEAM_TUNING, max_successful_generations=5, max_failed_generation_retries=3, - recursion_limit=40, + max_iterations=40, max_non_improving_generations=3, - evolver_llm="custom_evolver_llm_id", + llm="custom_llm_id", ) # Verify evolve_async was called with correct parameters @@ -203,9 +203,9 @@ def test_evolve_with_custom_parameters(self, mock_agent): evolve_type=EvolveType.TEAM_TUNING, max_successful_generations=5, max_failed_generation_retries=3, - recursion_limit=40, + max_iterations=40, max_non_improving_generations=3, - evolver_llm="custom_evolver_llm_id", + llm="custom_llm_id", ) # Verify sync_poll was called diff --git a/tests/unit/agent/test_evolver_llm_utils.py b/tests/unit/agent/test_evolver_llm_utils.py index dfcb4ec7..1997115b 100644 --- a/tests/unit/agent/test_evolver_llm_utils.py +++ b/tests/unit/agent/test_evolver_llm_utils.py @@ -3,29 +3,29 @@ """ from unittest.mock import Mock -from aixplain.utils.evolve_utils import create_evolver_llm_dict +from aixplain.utils.evolve_utils import create_llm_dict from aixplain.modules.model.llm_model import LLM from aixplain.enums import Function, Supplier -class TestCreateEvolverLLMDict: - """Test class for create_evolver_llm_dict functionality""" +class TestCreateLLMDict: + """Test class for create_llm_dict functionality""" - def test_create_evolver_llm_dict_with_none(self): - """Test create_evolver_llm_dict with None input""" - result = create_evolver_llm_dict(None) + def test_create_llm_dict_with_none(self): + """Test create_llm_dict with None input""" + result = create_llm_dict(None) assert result is None - def test_create_evolver_llm_dict_with_string_id(self): - """Test create_evolver_llm_dict with LLM ID string""" + def test_create_llm_dict_with_string_id(self): + """Test create_llm_dict with LLM ID string""" llm_id = "test_llm_id_123" - result = create_evolver_llm_dict(llm_id) + result = create_llm_dict(llm_id) expected = {"id": llm_id} assert result == expected - def test_create_evolver_llm_dict_with_llm_object(self): - """Test create_evolver_llm_dict with LLM object""" + def test_create_llm_dict_with_llm_object(self): + """Test create_llm_dict with LLM object""" # Create a mock LLM object mock_llm = Mock(spec=LLM) mock_llm.id = "llm_id_456" @@ -44,7 +44,7 @@ def test_create_evolver_llm_dict_with_llm_object(self): ] mock_llm.get_parameters.return_value = mock_parameters - result = create_evolver_llm_dict(mock_llm) + result = create_llm_dict(mock_llm) expected = { "id": "llm_id_456", @@ -61,8 +61,8 @@ def test_create_evolver_llm_dict_with_llm_object(self): } assert result == expected - def test_create_evolver_llm_dict_with_llm_object_no_parameters(self): - """Test create_evolver_llm_dict with LLM object that has no parameters""" + def test_create_llm_dict_with_llm_object_no_parameters(self): + """Test create_llm_dict with LLM object that has no parameters""" # Create a mock LLM object mock_llm = Mock(spec=LLM) mock_llm.id = "llm_id_789" @@ -76,7 +76,7 @@ def test_create_evolver_llm_dict_with_llm_object_no_parameters(self): # Mock get_parameters to return None mock_llm.get_parameters.return_value = None - result = create_evolver_llm_dict(mock_llm) + result = create_llm_dict(mock_llm) expected = { "id": "llm_id_789", @@ -90,8 +90,8 @@ def test_create_evolver_llm_dict_with_llm_object_no_parameters(self): } assert result == expected - def test_create_evolver_llm_dict_with_llm_object_no_temperature(self): - """Test create_evolver_llm_dict with LLM object that has no temperature attribute""" + def test_create_llm_dict_with_llm_object_no_temperature(self): + """Test create_llm_dict with LLM object that has no temperature attribute""" # Create a mock LLM object without temperature mock_llm = Mock(spec=LLM) mock_llm.id = "llm_id_999" @@ -107,7 +107,7 @@ def test_create_evolver_llm_dict_with_llm_object_no_temperature(self): # Mock get_parameters to return None mock_llm.get_parameters.return_value = None - result = create_evolver_llm_dict(mock_llm) + result = create_llm_dict(mock_llm) expected = { "id": "llm_id_999", @@ -121,9 +121,9 @@ def test_create_evolver_llm_dict_with_llm_object_no_temperature(self): } assert result == expected - def test_create_evolver_llm_dict_with_empty_string(self): - """Test create_evolver_llm_dict with empty string""" - result = create_evolver_llm_dict("") + def test_create_llm_dict_with_empty_string(self): + """Test create_llm_dict with empty string""" + result = create_llm_dict("") expected = {"id": ""} assert result == expected From 3c2bda7270ec756a69ca6063d073e632dae03811 Mon Sep 17 00:00:00 2001 From: ahmetgunduz Date: Sun, 31 Aug 2025 13:27:16 +0000 Subject: [PATCH 2/2] from yamly method updated --- .../factories/team_agent_factory/utils.py | 40 ++-- aixplain/modules/agent/__init__.py | 9 +- aixplain/modules/team_agent/__init__.py | 15 +- .../team_agent/evolver_response_data.py | 1 - aixplain/utils/evolve_utils.py | 174 ------------------ 5 files changed, 35 insertions(+), 204 deletions(-) diff --git a/aixplain/factories/team_agent_factory/utils.py b/aixplain/factories/team_agent_factory/utils.py index db9f5d7b..a5dd43f1 100644 --- a/aixplain/factories/team_agent_factory/utils.py +++ b/aixplain/factories/team_agent_factory/utils.py @@ -244,11 +244,13 @@ def build_team_agent_from_yaml(yaml_code: str, llm_id: str, api_key: str, team_i return None team_config = yaml.safe_load(yaml_code) - agents_data = team_config["agents"] + agents_data = team_config.get("agents", []) tasks_data = team_config.get("tasks", []) - system_data = team_config["system"] if "system" in team_config else {"query": "", "name": "Test Team"} - team_name = system_data["name"] - + system_data = team_config.get("system", {"query": "", "name": "Test Team"}) + team_name = system_data.get("name", "") + team_description = system_data.get("description", "") + team_instructions = system_data.get("instructions", "") + llm = ModelFactory.get(llm_id) # Create agent mapping by name for easier task assignment agents_mapping = {} agent_objs = [] @@ -257,21 +259,18 @@ def build_team_agent_from_yaml(yaml_code: str, llm_id: str, api_key: str, team_i for agent_entry in agents_data: agent_name = list(agent_entry.keys())[0] agent_info = agent_entry[agent_name] - agent_instructions = agent_info["instructions"] - agent_goal = agent_info["goal"] - agent_backstory = agent_info["backstory"] - - description = f"You are an expert {agent_instructions}. {agent_backstory} Your primary goal is to {agent_goal}. Use your expertise to ensure the success of your tasks." + agent_instructions = agent_info.get("instructions", "") + agent_description = agent_info["description"] agent_name = agent_name.replace("_", " ") agent_name = f"{agent_name} agent" if not agent_name.endswith(" agent") else agent_name agent_obj = Agent( id="", name=agent_name, - description=description, - instructions=description, + description=agent_description, + instructions=agent_instructions, tasks=[], # Tasks will be assigned later tools=[parse_tool_from_yaml(tool) for tool in agent_info.get("tools", []) if tool != "language_model"], - llmId=llm_id, + llm=llm, ) agents_mapping[agent_name] = agent_obj agent_objs.append(agent_obj) @@ -279,16 +278,16 @@ def build_team_agent_from_yaml(yaml_code: str, llm_id: str, api_key: str, team_i # Parse tasks and assign them to the corresponding agents for task in tasks_data: for task_name, task_info in task.items(): - description = task_info["description"] - expected_output = task_info["expected_output"] + task_description = task_info.get("description", "") + expected_output = task_info.get("expected_output", "") dependencies = task_info.get("dependencies", []) - agent_name = task_info["agent"] + agent_name = task_info.get("agent", "") agent_name = agent_name.replace("_", " ") agent_name = f"{agent_name} agent" if not agent_name.endswith(" agent") else agent_name task_obj = AgentTask( name=task_name, - description=description, + description=task_description, expected_output=expected_output, dependencies=dependencies, ) @@ -303,17 +302,18 @@ def build_team_agent_from_yaml(yaml_code: str, llm_id: str, api_key: str, team_i for i, agent in enumerate(agent_objs): agent_objs[i] = AgentFactory.create( name=agent.name, - description=agent.instructions, + description=agent.description, instructions=agent.instructions, tools=agent.tools, - llm_id=llm_id, + llm=llm, tasks=agent.tasks, ) - return TeamAgentFactory.create( name=team_name, + description=team_description, + instructions=team_instructions, agents=agent_objs, - llm_id=llm_id, + llm=llm, api_key=api_key, use_mentalist=True, inspectors=[], diff --git a/aixplain/modules/agent/__init__.py b/aixplain/modules/agent/__init__.py index 095eb598..68007914 100644 --- a/aixplain/modules/agent/__init__.py +++ b/aixplain/modules/agent/__init__.py @@ -551,7 +551,7 @@ def from_dict(cls, data: Dict) -> "Agent": """ from aixplain.factories.agent_factory.utils import build_tool from aixplain.enums import AssetStatus - from aixplain.modules.agent_task import WorkflowTask + from aixplain.modules.agent import WorkflowTask # Extract tools from assets using proper tool building tools = [] @@ -805,7 +805,8 @@ def evolve( Returns: AgentResponse: Final response from the evolution process. """ - from aixplain.utils.evolve_utils import from_yaml, create_llm_dict + from aixplain.utils.evolve_utils import create_llm_dict + from aixplain.factories.team_agent_factory.utils import build_team_agent_from_yaml # Create EvolveParam from individual parameters evolve_parameters = EvolveParam( @@ -841,9 +842,11 @@ def evolve( if "current_code" in result_data and result_data["current_code"] is not None: if evolve_parameters.evolve_type == EvolveType.TEAM_TUNING: - result_data["evolved_agent"] = from_yaml( + result_data["evolved_agent"] = build_team_agent_from_yaml( result_data["current_code"], self.llm_id, + self.api_key, + self.id, ) elif evolve_parameters.evolve_type == EvolveType.INSTRUCTION_TUNING: self.instructions = result_data["current_code"] diff --git a/aixplain/modules/team_agent/__init__.py b/aixplain/modules/team_agent/__init__.py index 55b36bab..b5669ece 100644 --- a/aixplain/modules/team_agent/__init__.py +++ b/aixplain/modules/team_agent/__init__.py @@ -438,7 +438,6 @@ def poll(self, poll_url: Text, name: Text = "model_process") -> AgentResponse: evolved_agent = self current_code = resp_data.get("current_code", "") evolved_agent.description = current_code - evolved_agent.instructions = current_code evolved_agent.update() resp_data["evolved_agent"] = evolved_agent else: @@ -586,10 +585,10 @@ def from_dict(cls, data: Dict) -> "TeamAgent": Returns: TeamAgent instance """ - from aixplain.factories.agent_factory import AgentFactory from aixplain.factories.model_factory import ModelFactory from aixplain.enums import AssetStatus from aixplain.modules.team_agent import Inspector, InspectorTarget + from aixplain.modules.agent import Agent # Extract agents from agents list using proper agent loading agents = [] @@ -598,14 +597,15 @@ def from_dict(cls, data: Dict) -> "TeamAgent": if "assetId" in agent_data: try: # Load agent using AgentFactory - agent = AgentFactory.get(agent_data["assetId"]) + agent = Agent.from_dict(agent_data) agents.append(agent) except Exception as e: # Log warning but continue processing other agents import logging logging.warning(f"Failed to load agent {agent_data['assetId']}: {e}") - + else: + agents.append(Agent.from_dict(agent_data)) # Extract inspectors using proper model validation inspectors = [] if "inspectors" in data: @@ -864,7 +864,8 @@ def evolve( AgentResponse: Final response from the evolution process. """ from aixplain.enums import EvolveType - from aixplain.utils.evolve_utils import from_yaml, create_llm_dict + from aixplain.utils.evolve_utils import create_llm_dict + from aixplain.factories.team_agent_factory.utils import build_team_agent_from_yaml # Create EvolveParam from individual parameters evolve_parameters = EvolveParam( @@ -899,9 +900,11 @@ def evolve( current_code = result_data.get("current_code") if isinstance(result_data, dict) else result_data.current_code if current_code is not None: if evolve_parameters.evolve_type == EvolveType.TEAM_TUNING: - result_data["evolved_agent"] = from_yaml( + result_data["evolved_agent"] = build_team_agent_from_yaml( result_data["current_code"], self.llm_id, + self.api_key, + self.id, ) elif evolve_parameters.evolve_type == EvolveType.INSTRUCTION_TUNING: self.instructions = result_data["current_code"] diff --git a/aixplain/modules/team_agent/evolver_response_data.py b/aixplain/modules/team_agent/evolver_response_data.py index cd2499b5..06479e4e 100644 --- a/aixplain/modules/team_agent/evolver_response_data.py +++ b/aixplain/modules/team_agent/evolver_response_data.py @@ -29,7 +29,6 @@ def from_dict(cls, data: Dict[str, Any], llm_id: Text, api_key: Text) -> "Evolve yaml_code = data.get("current_code", "") evolved_team_agent = build_team_agent_from_yaml(yaml_code=yaml_code, llm_id=llm_id, api_key=api_key) - return cls( evolved_agent=evolved_team_agent, current_code=yaml_code, diff --git a/aixplain/utils/evolve_utils.py b/aixplain/utils/evolve_utils.py index 2b021bd2..437e1a31 100644 --- a/aixplain/utils/evolve_utils.py +++ b/aixplain/utils/evolve_utils.py @@ -1,10 +1,5 @@ -import yaml from typing import Union, Dict, Any, Optional, Text -from aixplain.enums import Function, Supplier -from aixplain.modules.agent import Agent -from aixplain.modules.team_agent import TeamAgent from aixplain.modules.model.llm_model import LLM -from aixplain.factories import AgentFactory, TeamAgentFactory def create_llm_dict(llm: Optional[Union[Text, LLM]]) -> Optional[Dict[str, Any]]: @@ -32,172 +27,3 @@ def create_llm_dict(llm: Optional[Union[Text, LLM]]) -> Optional[Dict[str, Any]] } else: return {"id": llm} - - -def generate_tools_from_str(tools: list) -> list: - obj_tools = [] - for tool in tools: - tool_name = tool.strip() - if tool_name == "translation": - obj_tools.append( - AgentFactory.create_model_tool( - function=Function.TRANSLATION, - supplier=Supplier.GOOGLE, - ) - ) - elif tool_name == "speech-recognition": - obj_tools.append( - AgentFactory.create_model_tool( - function=Function.SPEECH_RECOGNITION, - supplier=Supplier.GOOGLE, - ) - ) - elif tool_name == "text-to-speech": - obj_tools.append( - AgentFactory.create_model_tool( - function=Function.SPEECH_SYNTHESIS, - supplier=Supplier.GOOGLE, - ) - ) - elif tool_name == "serper_search": - obj_tools.append(AgentFactory.create_model_tool(model="65c51c556eb563350f6e1bb1")) - elif tool_name == "website_search": - obj_tools.append(AgentFactory.create_model_tool(model="6736411cf127849667606689")) - elif tool_name == "website_scrape": - obj_tools.append(AgentFactory.create_model_tool(model="6748e4746eb5633559668a15")) - else: - continue - return obj_tools - - -def from_yaml( - yaml_code: str, - llm_id: str, -) -> Union[TeamAgent, Agent]: - team_config = yaml.safe_load(yaml_code) - - agents_data = team_config["agents"] - tasks_data = team_config.get("tasks", []) - system_data = team_config["system"] if "system" in team_config else {"query": ""} - expected_output = system_data.get("expected_output") - team_name = system_data.get("name") - team_description = system_data.get("description", "") - team_instructions = system_data.get("instructions", "") - - # Create agent mapping by name for easier task assignment - agents_mapping = {} - agent_objs = [] - - # Parse agents - for agent_entry in agents_data: - # Handle different YAML structures - if isinstance(agent_entry, dict): - # Case 1: Standard structure - {agent_name: {instructions: ..., goal: ..., backstory: ...}} - for agent_name, agent_info in agent_entry.items(): - # Check if agent_info is a list (malformed YAML structure) - if isinstance(agent_info, list): - # Handle malformed structure where agent_info is a list - # This happens when YAML has unquoted keys that create nested structures - continue - elif isinstance(agent_info, dict): - agent_instructions = agent_info["instructions"] - agent_goal = agent_info["goal"] - agent_backstory = agent_info["backstory"] - - description = f"## ROLE\n{agent_instructions}\n\n## GOAL\n{agent_goal}\n\n## BACKSTORY\n{agent_backstory}" - agent_obj = AgentFactory.create( - name=agent_name.replace("_", " "), - description=description, - tasks=[], # Tasks will be assigned later - tools=generate_tools_from_str(agent_info.get("tools", [])), - llm_id=llm_id, - ) - agents_mapping[agent_name] = agent_obj - agent_objs.append(agent_obj) - elif isinstance(agent_entry, list): - # Case 2: Handle list structure (alternative YAML format) - for item in agent_entry: - if isinstance(item, dict): - for agent_name, agent_info in item.items(): - if isinstance(agent_info, dict): - agent_instructions = agent_info["instructions"] - agent_goal = agent_info["goal"] - agent_backstory = agent_info["backstory"] - - description = ( - f"## ROLE\n{agent_instructions}\n\n## GOAL\n{agent_goal}\n\n## BACKSTORY\n{agent_backstory}" - ) - agent_tools = generate_tools_from_str(agent_info.get("tools", [])) - agent_obj = AgentFactory.create( - name=agent_name.replace("_", " "), - description=description, - tools=agent_tools, - tasks=[], - llm_id=llm_id, - ) - agents_mapping[agent_name] = agent_obj - agent_objs.append(agent_obj) - - # Parse tasks and assign them to the corresponding agents - for task_entry in tasks_data: - # Handle different YAML structures for tasks - if isinstance(task_entry, dict): - # Case 1: Standard structure - {task_name: {description: ..., expected_output: ..., agent: ...}} - for task_name, task_info in task_entry.items(): - # Check if task_info is a list (malformed YAML structure) - if isinstance(task_info, list): - # Handle malformed structure where task_info is a list - continue - elif isinstance(task_info, dict): - description = task_info["description"] - expected_output = task_info["expected_output"] - dependencies = task_info.get("dependencies", []) - agent_name = task_info["agent"] - task_obj = AgentFactory.create_task( - name=task_name.replace("_", " "), - description=description, - expected_output=expected_output, - dependencies=dependencies, - ) - - # Assign the task to the corresponding agent - if agent_name in agents_mapping: - agent = agents_mapping[agent_name] - agent.tasks.append(task_obj) - else: - raise ValueError(f"Agent '{agent_name}' referenced in tasks not found.") - elif isinstance(task_entry, list): - # Case 2: Handle list structure (alternative YAML format) - for item in task_entry: - if isinstance(item, dict): - for task_name, task_info in item.items(): - if isinstance(task_info, dict): - description = task_info["description"] - expected_output = task_info["expected_output"] - dependencies = task_info.get("dependencies", []) - agent_name = task_info["agent"] - - task_obj = AgentFactory.create_task( - name=task_name.replace("_", " "), - description=description, - expected_output=expected_output, - dependencies=dependencies, - ) - - # Assign the task to the corresponding agent - if agent_name in agents_mapping: - agent = agents_mapping[agent_name] - agent.tasks.append(task_obj) - else: - raise ValueError(f"Agent '{agent_name}' referenced in tasks not found.") - - team = TeamAgentFactory.create( - name=team_name, - description=team_description, - instructions=team_instructions, - agents=agent_objs, - llm_id=llm_id, - use_mentalist=True, - inspectors=[], - ) - return team