Skip to content

Commit

Permalink
Improved genesis agency
Browse files Browse the repository at this point in the history
  • Loading branch information
VRSEN committed Feb 14, 2024
1 parent b25ba2c commit ba34b79
Show file tree
Hide file tree
Showing 16 changed files with 87 additions and 33 deletions.
4 changes: 3 additions & 1 deletion agency_swarm/agency/agency.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,9 @@ class SendMessage(BaseTool):
"and the following next steps that you need to perfrom. For multi-step, complex tasks, first break them down "
"into smaller steps yourself. Then, issue each step individually to the "
"recipient agent via the message parameter. Each identified step should be "
"sent in separate message.")
"sent in separate message. Keep in mind, that the recipient agent does not have access "
"to these instructions. You must include recipient agent-specific instructions "
"in the message parameter.")
recipient: recipients = Field(..., description=agent_descriptions)
message: str = Field(...,
description="Specify the task required for the recipient agent to complete. Focus on "
Expand Down
2 changes: 2 additions & 0 deletions agency_swarm/agency/genesis/AgentCreator/AgentCreator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ def __init__(self, **kwargs):
if 'tools' not in kwargs:
kwargs['tools'] = []

kwargs['description'] = "This agent is responsible for creating new agents for the agency."

# Add required tools
kwargs['tools'].extend([CreateAgentTemplate,
# GetAvailableAgents,
Expand Down
6 changes: 3 additions & 3 deletions agency_swarm/agency/genesis/AgentCreator/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The user will communicate to you each agent that needs to be created. Below are
**Primary Instructions:**
1. First, read the manifesto using `ReadManifesto` tool if you have not already done so. This file contains the agency manifesto that describes the agency's purpose and goals.
2. Then, create a new agent using `CreateAgentTemplate` function.
3. Think if the agent you are creating needs to utilize any APIs. If it does, tell the OpenAPICreator agent to create API schemas for this agent. Make sure to also communicate the agent description, name and a summary of the processes that it needs to perform. CEO agents do not need to perform any API calls or use any tools, so you can skip the following steps.
3. If the agent you are creating needs to utilize any APIs, tell the OpenAPICreator agent to create API schemas for this agent. Make sure to also communicate the agent description, name and a summary of the processes that it needs to perform. CEO agents do not need to perform any API calls or use any tools, so you can skip the following steps.
4. For agents that do not need to utilize any APIs to perform their roles, tell the ToolCreator agent to create tools for this agent. Make sure to also communicate the agent description, name and a summary of the processes that it needs to perform.
5. If there are no issues and tools or APIs have been created, notify the user that the agent has been created. Otherwise, try to resolve any issues with other agents before reporting back.
6. Repeat the process for each agent that needs to be created.
5. If there are no issues and tools amd APIs have been successfully created, notify the user that the agent has been created. Otherwise, try to resolve any issues with other agents before reporting back.
6. Repeat this process for each agent that needs to be created.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class CreateAgentTemplate(BaseTool):
)

def run(self):
if not self.shared_state.get("manifesto_read"):
raise ValueError("Please read the manifesto first with the ReadManifesto tool.")

self.shared_state.set("agent_name", self.agent_name)

os.chdir(self.shared_state.get("agency_path"))
Expand Down Expand Up @@ -64,5 +67,5 @@ def run(self):
@model_validator(mode="after")
def validate_tools(self):
for tool in self.default_tools:
if tool not in self.allowed_tools:
raise ValueError(f"Tool {tool} is not allowed. Allowed tools are: {self.allowed_tools}")
if tool not in allowed_tools:
raise ValueError(f"Tool {tool} is not allowed. Allowed tools are: {allowed_tools}")
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ def run(self):

os.chdir(self.shared_state.get("default_folder"))

self.shared_state.set("manifesto_read", True)

return manifesto
3 changes: 3 additions & 0 deletions agency_swarm/agency/genesis/GenesisCEO/GenesisCEO.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ def __init__(self, **kwargs):
# Initialize tools in kwargs if not present
if 'tools' not in kwargs:
kwargs['tools'] = []

kwargs['description'] = "Acts as the overseer and communicator across the agency, ensuring alignment with the agency's goals."

# Add required tools
kwargs['tools'].extend([CreateAgencyFolder, FinalizeAgency])

Expand Down
6 changes: 3 additions & 3 deletions agency_swarm/agency/genesis/GenesisCEO/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

1. Pick a good name for the agency and communicate it to the user.
2. Ask user about their goals for this agency, its mission and its processes, like what APIs would the agents need to utilize.
3. Propose an initial structure for the agency, including the roles of the agents and their communication flows. Focus on creating at most 2 agents, plus CEO, unless instructed otherwise by the user. Output the code snippet like below.
4. Upon confirmation use `CreateAgencyFolder` tool to create a folder for the agency. If any modifications are required please use this tool again with the same agency name and it will overwrite the existing folder.
5. Tell AgentCreator to create these agents one by one, starting with the CEO. Each agent should be sent in a separate message using the `SendMessage` tool. Please make sure to communicate if this agent needs to utilize any APIs or tools to perform its role.
3. Propose an initial structure for the agency, including the roles of the agents, their communication flows and what APIs or Tools each agent can use, if any. Focus on creating at most 2 agents, plus CEO, unless instructed otherwise by the user. Output the code snippet like below. Adjust it accordingly, based on user's input.
4. Upon confirmation of the agency structure, use `CreateAgencyFolder` tool to create a folder for the agency. If any modifications are required please use this tool again with the same agency name and it will overwrite the existing folder.
5. Tell AgentCreator to create these agents one by one, starting with the CEO. Each agent should be sent in a separate message using the `SendMessage` tool. Please make sure to include the agent description, summary of the processes it needs to perform and the APIs or Tools that it can use via the message parameter.
6. Once all agents are created, please use the `FinalizeAgency` tool, and tell the user that he can now navigate to the agency folder and start it with `python agency.py` command.


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class CreateAgencyFolder(BaseTool):
"""
agency_name: str = Field(
..., description="Name of the agency to be created. Must not contain spaces or special characters.",
examples=["agency-name", "my-agency", "example-agency"]
examples=["AgencyName", "MyAgency", "ExampleAgency"]
)
agency_chart: str = Field(
..., description="Agency chart to be passed into the Agency class.",
Expand Down
3 changes: 3 additions & 0 deletions agency_swarm/agency/genesis/OpenAPICreator/OpenAPICreator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ def __init__(self, **kwargs):
# Initialize tools in kwargs if not present
if 'tools' not in kwargs:
kwargs['tools'] = []

kwargs['description'] = "This agent is responsible for creating new tools from an OpenAPI specifications."

# Add required tools
kwargs['tools'].extend([Retrieval, CreateToolsFromOpenAPISpec])

Expand Down
2 changes: 1 addition & 1 deletion agency_swarm/agency/genesis/OpenAPICreator/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ You are an agent that creates tools from OpenAPI schemas. User will provide you
1. Think which API is needed for this agent's role, as communicated by the user. Then, tell the BrowsingAgent to find this API documentation page.
2. Explore the provided file from the BrowsingAgent with the `myfiles_broswer` tool to determine which endpoints are needed for this agent's role.
3. If the file does not contain the actual API documentation page, please notify the BrowsingAgent. Keep in mind that you do not need the full API documentation. You can make an educated guess if some information is not available.
4. Use `CreateToolsFromOpenAPISpec` to create the tools by defining the OpenAPI schema accordingly. Make sure to include all the relevant API endpoints that are needed for this agent to execute its role from the provided file.
4. Use `CreateToolsFromOpenAPISpec` to create the tools by defining the OpenAPI schema accordingly. Make sure to include all the relevant API endpoints that are needed for this agent to execute its role from the provided file. Do not truncate the schema.
5. Repeat these steps for each new agent that needs to be created, as instructed by the user.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from pydantic import Field, field_validator
from pydantic import Field, field_validator, model_validator

from agency_swarm import BaseTool

Expand All @@ -14,16 +14,21 @@ class CreateToolsFromOpenAPISpec(BaseTool):
"""
This tool creates a set of tools from an OpenAPI specification. Each method in the specification is converted to a separate tool.
"""
agent_name: str = Field(
..., description="Name of the agent to create the API for. Must be an existing agent."
)
openapi_spec: str = Field(
..., description="OpenAPI specification for the tool to be created as a valid JSON string. Only the relevant "
"endpoints must be included. Responses are not required. Each method should contain "
"an operation id and a description. Must be full OpenAPI 3.1.0 specification.",
"an operation id and a description. Do not truncate this schema. "
"It must be a full valid OpenAPI 3.1.0 specification.",
examples=[
'{\n "openapi": "3.1.0",\n "info": {\n "title": "Get weather data",\n "description": "Retrieves current weather data for a location.",\n "version": "v1.0.0"\n },\n "servers": [\n {\n "url": "https://weather.example.com"\n }\n ],\n "paths": {\n "/location": {\n "get": {\n "description": "Get temperature for a specific location",\n "operationId": "GetCurrentWeather",\n "parameters": [\n {\n "name": "location",\n "in": "query",\n "description": "The city and state to retrieve the weather for",\n "required": true,\n "schema": {\n "type": "string"\n }\n }\n ],\n "deprecated": false\n }\n }\n },\n "components": {\n "schemas": {}\n }\n}'])

def run(self):
os.chdir(self.shared_state.get("agency_path"))
os.chdir(self.shared_state.get("agent_name"))

os.chdir(self.agent_name)

try:
try:
Expand Down Expand Up @@ -64,3 +69,15 @@ def validate_openapi_spec(cls, v):
raise ValueError("Error validating OpenAPI schema:", e)
return v

@model_validator(mode="after")
def validate_agent_name(self):
if not self.shared_state.get("agency_path"):
raise ValueError("Please tell the user that he must create agency first.")

agent_path = os.path.join(self.shared_state.get("agency_path"), self.agent_name)
if not os.path.exists(agent_path):
available_agents = os.listdir(self.shared_state.get("agency_path"))
available_agents = [agent for agent in available_agents if
os.path.isdir(os.path.join(self.shared_state.get("agency_path"), agent))]
raise ValueError(f"Agent {self.agent_name} not found. Available agents are: {available_agents}")

2 changes: 2 additions & 0 deletions agency_swarm/agency/genesis/ToolCreator/ToolCreator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ def __init__(self, **kwargs):
if 'tools' not in kwargs:
kwargs['tools'] = []

kwargs['description'] = "This agent is responsible for creating new tools for the agency."

# Add required tools
kwargs['tools'].extend([CreateTool, TestTool])

Expand Down
21 changes: 17 additions & 4 deletions agency_swarm/agency/genesis/ToolCreator/tools/CreateTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ class CreateTool(BaseTool):
"""
This tool creates tools for the agent.
"""
agent_name: str = Field(
..., description="Name of the agent to create the tool for."
)
chain_of_thought: str = Field(
..., description="Think step by step to determine how to best implement this tool.", exclude=True
)
tool_name: str = Field(..., description="Name of the tool class in camel case.", examples=["ExampleTool"])
tool_code: str = Field(
..., description="Correct code for this tool written in python. Must include all the import statements, "
"as well as the primary tool class that extends BaseTool. Name of this class must match tool_name.", examples=[example_tool_template]
"as well as the primary tool class that extends BaseTool. Name of this class must match tool_name.",
examples=[example_tool_template]
)

def run(self):
os.chdir(self.shared_state.get("agency_path"))
os.chdir(self.shared_state.get("agent_name"))
os.chdir(self.agent_name)

with open("./tools/" + self.tool_name + ".py", "w") as f:
f.write(self.tool_code)
Expand All @@ -33,5 +37,14 @@ def run(self):

return f"Tool {self.tool_name} has been created successfully for {self.shared_state.get('agent_name')} agent. You can now test it with TestTool function."



@model_validator(mode="after")
def validate_agent_name(self):
if not self.shared_state.get("agency_path"):
raise ValueError("Please tell the user that he must create agency first.")

agent_path = os.path.join(self.shared_state.get("agency_path"), self.agent_name)
if not os.path.exists(agent_path):
available_agents = os.listdir(self.shared_state.get("agency_path"))
available_agents = [agent for agent in available_agents if
os.path.isdir(os.path.join(self.shared_state.get("agency_path"), agent))]
raise ValueError(f"Agent {self.agent_name} not found. Available agents are: {available_agents}")
27 changes: 21 additions & 6 deletions agency_swarm/agency/genesis/ToolCreator/tools/TestTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,31 @@ class TestTool(BaseTool):
"""
This tool tests other tools defined in tools.py file with the given arguments. Make sure to define the run method before testing.
"""
agent_name: str = Field(
..., description="Name of the agent to test the tool for."
)
chain_of_thought: str = Field(
..., description="Think step by step to determine the correct arguments for testing.", exclude=True
)
tool_name: str = Field(..., description="Name of the tool to be run. Must be defined in tools.py file.")
tool_name: str = Field(..., description="Name of the tool to be run.")
arguments: Optional[str] = Field(...,
description="Arguments to be passed to the tool for testing. "
"Must be in serialized json format.")

def run(self):
os.chdir(self.shared_state.get("agency_path"))
os.chdir(self.shared_state.get("agent_name"))
os.chdir(self.agent_name)

# import tool by self.tool_name from local tools.py file
try:
tool = ToolFactory.from_file(f"./tools/")
tool = ToolFactory.from_file(f"./tools/{self.tool_name}.py")
except Exception as e:
raise ValueError(f"Error importing tool {self.tool_name}: {e}")
finally:
os.chdir(self.shared_state.get("default_folder"))

try:
output = tool.run()
output = tool(**eval(self.arguments)).run()
except Exception as e:
raise ValueError(f"Error running tool {self.tool_name}: {e}")
finally:
Expand All @@ -44,17 +47,29 @@ def run(self):

@model_validator(mode="after")
def validate_tool_name(self):
if not self.shared_state.get("agency_path"):
raise ValueError("Please tell the user that he must create agency first with GenesisCEO.")

tool_path = os.path.join(self.shared_state.get("agency_path"), self.shared_state.get("agent_name"))
tool_path = os.path.join(str(tool_path), "tools")
tool_path = os.path.join(tool_path, self.tool_name + ".py")

# check if tools.py file exists
if not os.path.isfile(tool_path):
available_tools = os.listdir(os.path.join(self.shared_state.get("agency_path"), self.shared_state.get("agent_name")))
available_tools = os.listdir(
os.path.join(self.shared_state.get("agency_path"), self.shared_state.get("agent_name")))
available_tools = [tool for tool in available_tools if tool.endswith(".py")]
available_tools = [tool for tool in available_tools if not tool.startswith("__") and not tool.startswith(".")]
available_tools = [tool for tool in available_tools if
not tool.startswith("__") and not tool.startswith(".")]
available_tools = [tool.replace(".py", "") for tool in available_tools]
available_tools = ", ".join(available_tools)
raise ValueError(f"Tool {self.tool_name} not found. Available tools are: {available_tools}")

agent_path = os.path.join(self.shared_state.get("agency_path"), self.agent_name)
if not os.path.exists(agent_path):
available_agents = os.listdir(self.shared_state.get("agency_path"))
available_agents = [agent for agent in available_agents if
os.path.isdir(os.path.join(self.shared_state.get("agency_path"), agent))]
raise ValueError(f"Agent {self.agent_name} not found. Available agents are: {available_agents}")

return True
7 changes: 0 additions & 7 deletions agency_swarm/agency/genesis/manifesto.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,5 @@ You are a part of a Genesis Agency for a framework called Agency Swarm. The goal

**Agency Swarm is an open-source agent orchestration framework designed to automate and streamline AI agent development processes. It enables the creation of a collaborative swarm of agents (Agencies), each with distinct roles and capabilities. These agents are then able to talk to each other and collaborate on tasks, with the goal of achieving a common objective.**

### Roles of the Agents in this Agency

1. **GenesisCEO**: The CEO of the Genesis Agency. The CEO is responsible for creating other agencies. The CEO will communicate with the user to understand their goals for the agency, its mission, and its processes.
2. **AgentCreator**: The AgentCreator agent creates other agents as instructed by the user.
3. **ToolCreator**: The ToolCreator agent creates tools for other agents, as instructed by the user. These tools are executed locally by the agents to perform their roles.
4. **OpenAPICreator**: The OpenAPICreator agent creates API schemas for other agents. These schemas are used by the agents to communicate with external APIs.

Keep in mind that communication with the other agents via the `SendMessage` tool is synchronous. Other agents will not be executing any tasks after you receive the output of this tool. Please instruct the receiving agent to continue its execution, if needed.

3 changes: 1 addition & 2 deletions agency_swarm/cli.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import argparse
import os

from agency_swarm.util import create_agent_template


def main():
parser = argparse.ArgumentParser(description='Create agent template.')
Expand All @@ -25,6 +23,7 @@ def main():
args = parser.parse_args()

if args.command == "create-agent-template":
from agency_swarm.util import create_agent_template
create_agent_template(args.name, args.description, args.path, args.use_txt)
elif args.command == "genesis":
if not os.getenv('OPENAI_API_KEY') and not args.openai_key:
Expand Down

0 comments on commit ba34b79

Please sign in to comment.