|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from collections import deque |
|
|
from typing import Dict, List, Optional |
|
|
|
|
|
from camel.agents import ( |
|
|
ChatAgent, |
|
|
TaskCreationAgent, |
|
|
TaskPrioritizationAgent, |
|
|
TaskSpecifyAgent, |
|
|
) |
|
|
from camel.agents.chat_agent import ChatAgentResponse |
|
|
from camel.generators import SystemMessageGenerator |
|
|
from camel.logger import get_logger |
|
|
from camel.messages import BaseMessage |
|
|
from camel.prompts import TextPrompt |
|
|
from camel.types import RoleType, TaskType |
|
|
|
|
|
logger = get_logger(__name__) |
|
|
|
|
|
|
|
|
class BabyAGI: |
|
|
r"""The BabyAGI Agent adapted from `"Task-driven Autonomous Agent" |
|
|
<https://github.com/yoheinakajima/babyagi>`_. |
|
|
|
|
|
Args: |
|
|
assistant_role_name (str): The name of the role played by the |
|
|
assistant. |
|
|
user_role_name (str): The name of the role played by the user. |
|
|
task_prompt (str, optional): A prompt for the task to be performed. |
|
|
(default: :obj:`""`) |
|
|
task_type (TaskType, optional): The type of task to perform. |
|
|
(default: :obj:`TaskType.AI_SOCIETY`) |
|
|
max_task_history (int): The maximum number of previous tasks |
|
|
information to include in the task agent. |
|
|
(default: :obj:10) |
|
|
assistant_agent_kwargs (Dict, optional): Additional arguments to pass |
|
|
to the assistant agent. (default: :obj:`None`) |
|
|
task_specify_agent_kwargs (Dict, optional): Additional arguments to |
|
|
pass to the task specify agent. (default: :obj:`None`) |
|
|
task_creation_agent_kwargs (Dict, optional): Additional arguments to |
|
|
pass to the task creation agent. (default: :obj:`None`) |
|
|
task_prioritization_agent_kwargs (Dict, optional): Additional arguments |
|
|
to pass to the task prioritization agent. (default: :obj:`None`) |
|
|
sys_msg_generator_kwargs (Dict, optional): Additional arguments to |
|
|
pass to the system message generator. (default: :obj:`None`) |
|
|
extend_task_specify_meta_dict (Dict, optional): A dict to extend the |
|
|
task specify meta dict with. (default: :obj:`None`) |
|
|
output_language (str, optional): The language to be output by the |
|
|
agents. (default: :obj:`None`) |
|
|
message_window_size (int, optional): The maximum number of previous |
|
|
messages to include in the context window. If `None`, no windowing |
|
|
is performed. (default: :obj:`None`) |
|
|
""" |
|
|
|
|
|
def __init__( |
|
|
self, |
|
|
assistant_role_name: str, |
|
|
user_role_name: str, |
|
|
task_prompt: str = "", |
|
|
task_type: TaskType = TaskType.AI_SOCIETY, |
|
|
max_task_history: int = 10, |
|
|
assistant_agent_kwargs: Optional[Dict] = None, |
|
|
task_specify_agent_kwargs: Optional[Dict] = None, |
|
|
task_creation_agent_kwargs: Optional[Dict] = None, |
|
|
task_prioritization_agent_kwargs: Optional[Dict] = None, |
|
|
sys_msg_generator_kwargs: Optional[Dict] = None, |
|
|
extend_task_specify_meta_dict: Optional[Dict] = None, |
|
|
output_language: Optional[str] = None, |
|
|
message_window_size: Optional[int] = None, |
|
|
) -> None: |
|
|
self.task_type = task_type |
|
|
self.task_prompt = task_prompt |
|
|
self.specified_task_prompt: TextPrompt |
|
|
self.init_specified_task_prompt( |
|
|
assistant_role_name, |
|
|
user_role_name, |
|
|
task_specify_agent_kwargs, |
|
|
extend_task_specify_meta_dict, |
|
|
output_language, |
|
|
) |
|
|
|
|
|
sys_msg_generator = SystemMessageGenerator( |
|
|
task_type=self.task_type, **(sys_msg_generator_kwargs or {}) |
|
|
) |
|
|
|
|
|
init_assistant_sys_msg = sys_msg_generator.from_dicts( |
|
|
meta_dicts=[ |
|
|
dict( |
|
|
assistant_role=assistant_role_name, |
|
|
user_role=user_role_name, |
|
|
task=self.specified_task_prompt, |
|
|
) |
|
|
], |
|
|
role_tuples=[ |
|
|
(assistant_role_name, RoleType.ASSISTANT), |
|
|
], |
|
|
) |
|
|
|
|
|
self.assistant_agent: ChatAgent |
|
|
self.assistant_sys_msg: Optional[BaseMessage] |
|
|
self.task_creation_agent: TaskCreationAgent |
|
|
self.task_prioritization_agent: TaskPrioritizationAgent |
|
|
self.init_agents( |
|
|
init_assistant_sys_msg[0], |
|
|
assistant_agent_kwargs, |
|
|
task_creation_agent_kwargs, |
|
|
task_prioritization_agent_kwargs, |
|
|
output_language, |
|
|
message_window_size, |
|
|
) |
|
|
|
|
|
self.subtasks: deque = deque([]) |
|
|
self.solved_subtasks: List[str] = [] |
|
|
self.MAX_TASK_HISTORY = max_task_history |
|
|
|
|
|
def init_specified_task_prompt( |
|
|
self, |
|
|
assistant_role_name: str, |
|
|
user_role_name: str, |
|
|
task_specify_agent_kwargs: Optional[Dict], |
|
|
extend_task_specify_meta_dict: Optional[Dict], |
|
|
output_language: Optional[str], |
|
|
): |
|
|
r"""Use a task specify agent to generate a specified task prompt. |
|
|
Generated specified task prompt will be used to replace original |
|
|
task prompt. If there is no task specify agent, specified task |
|
|
prompt will not be generated. |
|
|
|
|
|
Args: |
|
|
assistant_role_name (str): The name of the role played by the |
|
|
assistant. |
|
|
user_role_name (str): The name of the role played by the user. |
|
|
task_specify_agent_kwargs (Dict, optional): Additional arguments |
|
|
to pass to the task specify agent. |
|
|
extend_task_specify_meta_dict (Dict, optional): A dict to extend |
|
|
the task specify meta dict with. |
|
|
output_language (str, optional): The language to be output by the |
|
|
agents. |
|
|
""" |
|
|
task_specify_meta_dict = dict() |
|
|
if self.task_type in [TaskType.AI_SOCIETY, TaskType.MISALIGNMENT]: |
|
|
task_specify_meta_dict.update( |
|
|
dict( |
|
|
assistant_role=assistant_role_name, |
|
|
user_role=user_role_name, |
|
|
) |
|
|
) |
|
|
task_specify_meta_dict.update(extend_task_specify_meta_dict or {}) |
|
|
task_specify_agent = TaskSpecifyAgent( |
|
|
task_type=self.task_type, |
|
|
output_language=output_language, |
|
|
**(task_specify_agent_kwargs or {}), |
|
|
) |
|
|
self.specified_task_prompt = task_specify_agent.run( |
|
|
self.task_prompt, |
|
|
meta_dict=task_specify_meta_dict, |
|
|
) |
|
|
|
|
|
def init_agents( |
|
|
self, |
|
|
init_assistant_sys_msg: BaseMessage, |
|
|
assistant_agent_kwargs: Optional[Dict], |
|
|
task_creation_agent_kwargs: Optional[Dict], |
|
|
task_prioritization_agent_kwargs: Optional[Dict], |
|
|
output_language: Optional[str], |
|
|
message_window_size: Optional[int] = None, |
|
|
): |
|
|
r"""Initialize assistant and user agents with their system messages. |
|
|
|
|
|
Args: |
|
|
init_assistant_sys_msg (BaseMessage): Assistant agent's initial |
|
|
system message. |
|
|
assistant_agent_kwargs (Dict, optional): Additional arguments to |
|
|
pass to the assistant agent. |
|
|
task_creation_agent_kwargs (Dict, optional): Additional arguments |
|
|
to pass to the task creation agent. |
|
|
task_prioritization_agent_kwargs (Dict, optional): Additional |
|
|
arguments to pass to the task prioritization agent. |
|
|
output_language (str, optional): The language to be output by the |
|
|
agents. |
|
|
message_window_size (int, optional): The maximum number of previous |
|
|
messages to include in the context window. If `None`, no |
|
|
windowing is performed. (default: :obj:`None`) |
|
|
""" |
|
|
self.assistant_agent = ChatAgent( |
|
|
init_assistant_sys_msg, |
|
|
output_language=output_language, |
|
|
message_window_size=message_window_size, |
|
|
**(assistant_agent_kwargs or {}), |
|
|
) |
|
|
self.assistant_sys_msg = self.assistant_agent.system_message |
|
|
self.assistant_agent.reset() |
|
|
|
|
|
self.task_creation_agent = TaskCreationAgent( |
|
|
objective=self.specified_task_prompt, |
|
|
role_name=getattr(self.assistant_sys_msg, 'role_name', None) |
|
|
or "assistant", |
|
|
output_language=output_language, |
|
|
message_window_size=message_window_size, |
|
|
**(task_creation_agent_kwargs or {}), |
|
|
) |
|
|
self.task_creation_agent.reset() |
|
|
|
|
|
self.task_prioritization_agent = TaskPrioritizationAgent( |
|
|
objective=self.specified_task_prompt, |
|
|
output_language=output_language, |
|
|
message_window_size=message_window_size, |
|
|
**(task_prioritization_agent_kwargs or {}), |
|
|
) |
|
|
self.task_prioritization_agent.reset() |
|
|
|
|
|
def step(self) -> ChatAgentResponse: |
|
|
r"""BabyAGI agent would pull the first task from the task list, |
|
|
complete the task based on the context, then creates new tasks and |
|
|
re-prioritizes the task list based on the objective and the result of |
|
|
the previous task. It returns assistant message. |
|
|
|
|
|
Returns: |
|
|
ChatAgentResponse: it contains the resulting assistant message, |
|
|
whether the assistant agent terminated the conversation, |
|
|
and any additional assistant information. |
|
|
|
|
|
""" |
|
|
if not self.subtasks: |
|
|
new_subtask_list = self.task_creation_agent.run(task_list=[]) |
|
|
prioritized_subtask_list = self.task_prioritization_agent.run( |
|
|
new_subtask_list |
|
|
) |
|
|
self.subtasks = deque(prioritized_subtask_list) |
|
|
|
|
|
task_name = self.subtasks.popleft() |
|
|
assistant_msg_msg = BaseMessage.make_user_message( |
|
|
role_name=getattr(self.assistant_sys_msg, 'role_name', None) |
|
|
or "assistant", |
|
|
content=f"{task_name}", |
|
|
) |
|
|
|
|
|
assistant_response = self.assistant_agent.step(assistant_msg_msg) |
|
|
assistant_msg = assistant_response.msgs[0] |
|
|
|
|
|
self.solved_subtasks.append(task_name) |
|
|
past_tasks = self.solved_subtasks + list(self.subtasks) |
|
|
|
|
|
new_subtask_list = self.task_creation_agent.run( |
|
|
task_list=past_tasks[-self.MAX_TASK_HISTORY :] |
|
|
) |
|
|
|
|
|
if new_subtask_list: |
|
|
self.subtasks.extend(new_subtask_list) |
|
|
prioritized_subtask_list = self.task_prioritization_agent.run( |
|
|
task_list=list(self.subtasks)[-self.MAX_TASK_HISTORY :] |
|
|
) |
|
|
self.subtasks = deque(prioritized_subtask_list) |
|
|
else: |
|
|
logger.info("no new tasks") |
|
|
assistant_response.info['task_name'] = task_name |
|
|
assistant_response.info['subtasks'] = list(self.subtasks) |
|
|
if not self.subtasks: |
|
|
terminated = True |
|
|
assistant_response.info['termination_reasons'] = ( |
|
|
"All tasks are solved" |
|
|
) |
|
|
return ChatAgentResponse( |
|
|
msgs=[assistant_msg], |
|
|
terminated=terminated, |
|
|
info=assistant_response.info, |
|
|
) |
|
|
return ChatAgentResponse( |
|
|
msgs=[assistant_msg], |
|
|
terminated=assistant_response.terminated, |
|
|
info=assistant_response.info, |
|
|
) |
|
|
|