Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: babyagi agent support #243

Merged
merged 29 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
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
4 changes: 2 additions & 2 deletions camel/agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
TaskSpecifyAgent,
TaskPlannerAgent,
TaskCreationAgent,
TaskPrioritizationAgent,
TaskPrioritizeAgent,
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved
)
from .critic_agent import CriticAgent
from .tool_agents.base import BaseToolAgent
Expand All @@ -31,7 +31,7 @@
'TaskSpecifyAgent',
'TaskPlannerAgent',
'TaskCreationAgent',
'TaskPrioritizationAgent',
'TaskPrioritizeAgent',
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved
'CriticAgent',
'BaseToolAgent',
'HuggingFaceToolAgent',
Expand Down
113 changes: 56 additions & 57 deletions camel/agents/task_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,11 @@ class TaskCreationAgent(ChatAgent):
`BabyAGI <https://github.com/yoheinakajima/babyagi>`_.

Attributes:
task_creation_prompt (TextPrompt): A prompt for the agent to create
task_creator_prompt (TextPrompt): A prompt for the agent to create
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved
new tasks.

Args:
role_name (str): The role name of the Agent to create the task.
objective (Union[str, TextPrompt]): The objective of the Agent to
perform the task.
model (ModelType, optional): The type of model to use for the agent.
Expand All @@ -200,36 +201,43 @@ class TaskCreationAgent(ChatAgent):
(default: :obj:`None`)
output_language (str, optional): The language to be output by the
agent. (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,
role_name: str,
objective: Union[str, TextPrompt],
model: Optional[ModelType] = None,
model_config: Optional[Any] = None,
output_language: Optional[str] = None,
message_window_size: Optional[int] = None,
) -> None:

task_creation_prompt = TextPrompt(
"""Create new tasks with the following objective: {objective}.
The last completed task has the result:
{task_result}.
This result was based on this task: {task}.
Based on the result, return a list of tasks to be completed in order to meet \
the objective.

{unsolved_tasks}

Return one task per line in your response.
"""Create new a task with the following objective: {objective}.
Never forget you are a Task Creator and I am {role_name}.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about letting the user_role_name as well?

Suggested change
Never forget you are a Task Creator and I am {role_name}.
Never forget you are a Task Creator of {user_role_name} and I am {assisitant_role_name}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it should be this way:
Never forget you are a Task Creator of {assisitant_role_name} and I am {user_role_name}.
Task agent is an auxiliary module of the assistant agent to help it with the task creation, planning. I don't think it needs to know user_role_name. In my opinion, it should be
Never forget you are a Task Creator of {assisitant_role_name}.

But, I tried both and didn't find difference in output, probably only nuances that I can't tell.

You must instruct me based on my expertise and your needs to solve the task.
You should consider past solved tasks and in-progress tasks: {task_list}.
The new created tasks must not overlap with these past tasks.
The result must be a numbered list in the format:

1. First task
2. Second task
#. First Task
#. Second Task
#. Third Task

The number of each entry must be followed by a period. Be concise.""")
You can only give me up to three tasks at a time. Each task shoud be concise, \
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved
concrete and doable for a Python Programmer.
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved
You should make task plan and not ask me questions.
If you think no new tasks are needed right now, write "No tasks to add."
Now start to give me new tasks one by one. No more than three tasks.
Be concrete.
""")

self.task_creation_prompt = task_creation_prompt.format(
objective=objective)
objective=objective, role_name=role_name)
self.objective = objective

system_message = BaseMessage(
Expand All @@ -240,63 +248,50 @@ def __init__(
)

super().__init__(system_message, model, model_config,
output_language=output_language)
output_language=output_language,
message_window_size=message_window_size)

def run(
self,
previous_task: Union[str, TextPrompt],
task_result: Union[str, TextPrompt],
task_list: Optional[List[str]] = None,
task_list: List[str],
) -> List[str]:
r"""Generate subtasks based on the previous task results and
incomplete task list.

Args:
previous_task (Union[str, TextPrompt]): The last completed task to
be used to create future plans.
task_result (Union[str, TextPrompt]): The result of last completed
task to be used to create future plans.
task_list (List[str], optional): The incomplete task list
which should not overlap with new created tasks.
(default: :obj:`None`)
task_list (List[str]): The completed or in-progress
tasks which should not overlap with new created tasks.
Returns:
List[str]: The new task list generated by the Agent.
"""
self.reset()
task_creation_prompt = self.task_creation_prompt.format(
task=previous_task, task_result=task_result)
if task_list is not None:
unsolved = (
f"These are unsolved tasks: {task_list}.\n"
"These new tasks must not overlap with incomplete tasks.")

task_creation_prompt = task_creation_prompt.format(
unsolved_tasks=unsolved)

if len(task_list) > 0:
task_creation_prompt = self.task_creation_prompt.format(
task_list=task_list)
else:
task_creation_prompt = task_creation_prompt.format(
unsolved_tasks="")
task_creation_prompt = self.task_creation_prompt.format(
task_list="")

task_msg = BaseMessage.make_user_message(role_name="Task Creator",
task_msg = BaseMessage.make_user_message(role_name="Task Planner",
content=task_creation_prompt)

task_response = self.step(task_msg)

if len(task_response.msgs) == 0:
raise RuntimeError("Got no task creation message.")
raise RuntimeError("Got None Subtasks messages.")
if task_response.terminated:
raise RuntimeError("Task creation failed.")
raise RuntimeError("Task planning failed.")
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved

sub_tasks_msg = task_response.msgs[0]
return get_task_list(sub_tasks_msg.content)


class TaskPrioritizationAgent(ChatAgent):
class TaskPrioritizeAgent(ChatAgent):
r"""An agent that helps re-prioritize the task list and
returns numbered prioritized list. Modified from
`BabyAGI <https://github.com/yoheinakajima/babyagi>`_.

Attributes:
task_prioritization_prompt (TextPrompt): A prompt for the agent to
task_prioritizer_prompt (TextPrompt): A prompt for the agent to
prioritize tasks.
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved

Args:
Expand All @@ -308,6 +303,9 @@ class TaskPrioritizationAgent(ChatAgent):
(default: :obj:`None`)
output_language (str, optional): The language to be output by the
agent. (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__(
Expand All @@ -316,23 +314,24 @@ def __init__(
model: Optional[ModelType] = None,
model_config: Optional[Any] = None,
output_language: Optional[str] = None,
message_window_size: Optional[int] = None,
) -> None:

task_prioritization_prompt = TextPrompt(
"""Prioritize the following tasks : {task_list}.
Consider the ultimate objective of you: {objective}.
Tasks should be sorted from highest to lowest priority,
where higher-priority tasks are those that act as pre-requisites \
or are more essential for meeting the objective.
Return one task per line in your response. Do not remove any tasks.
Tasks should be sorted from highest to lowest priority, where higher-priority \
tasks are those that act as pre-requisites or are more essential for meeting \
the objective. Return one task per line in your response.
Do not remove or modify any tasks.
The result must be a numbered list in the format:

1. First task
2. Second task
#. First task
#. Second task

The entries must be consecutively numbered, starting with 1.
The number of each entry must be followed by a period.
Be concise.""")
Do not include any headers before your ranked list or follow your list \
with any other output.""")

self.task_prioritization_prompt = task_prioritization_prompt.format(
objective=objective)
Expand All @@ -346,7 +345,8 @@ def __init__(
)

super().__init__(system_message, model, model_config,
output_language=output_language)
output_language=output_language,
message_window_size=message_window_size)

def run(
self,
Expand All @@ -355,11 +355,10 @@ def run(
r"""Prioritize the task list given the agent objective.

Args:
task_list (List[str]): The un-prioritized task list of agent.
task_list (List[str]): The unprioritized tasks of agent.
Returns:
List[str]: The new prioritized task list generated by the Agent.
"""
self.reset()
task_prioritization_prompt = self.task_prioritization_prompt.format(
task_list=task_list)

Expand All @@ -369,9 +368,9 @@ def run(
task_response = self.step(task_msg)

if len(task_response.msgs) == 0:
raise RuntimeError("Got no task prioritization message.")
raise RuntimeError("Got None Subtasks messages.")
if task_response.terminated:
raise RuntimeError("Task prioritization failed.")
raise RuntimeError("Task Prioritizing failed.")
hychen-naza marked this conversation as resolved.
Show resolved Hide resolved

sub_tasks_msg = task_response.msgs[0]
return get_task_list(sub_tasks_msg.content)
2 changes: 2 additions & 0 deletions camel/societies/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
# limitations under the License.
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
from .role_playing import RolePlaying
from .babyagi_playing import BabyAGI

__all__ = [
'RolePlaying',
'BabyAGI',
]
Loading
Loading