From f2e490db11b180ec3dd6efcb2c23c595a3c7931f Mon Sep 17 00:00:00 2001 From: Arsenii Shatokhin Date: Tue, 5 Mar 2024 11:56:16 +0400 Subject: [PATCH] Imrpoved genesis agency --- .../genesis/AgentCreator/instructions.md | 2 +- .../AgentCreator/tools/CreateAgentTemplate.py | 26 +++++++++- .../agency/genesis/GenesisCEO/instructions.md | 17 +++---- .../GenesisCEO/tools/CreateAgencyFolder.py | 4 +- .../tools/CreateToolsFromOpenAPISpec.py | 16 +++---- .../agency/genesis/ToolCreator/ToolCreator.py | 2 +- .../genesis/ToolCreator/instructions.md | 47 +++++-------------- .../genesis/ToolCreator/tools/CreateTool.py | 27 +++++------ agency_swarm/agency/genesis/manifesto.md | 4 +- agency_swarm/agency/genesis/util.py | 27 +++++++++++ pyproject.toml | 2 +- requirements.txt | 2 +- setup.py | 2 +- 13 files changed, 99 insertions(+), 79 deletions(-) create mode 100644 agency_swarm/agency/genesis/util.py diff --git a/agency_swarm/agency/genesis/AgentCreator/instructions.md b/agency_swarm/agency/genesis/AgentCreator/instructions.md index 1d7cb4c2..eb028891 100644 --- a/agency_swarm/agency/genesis/AgentCreator/instructions.md +++ b/agency_swarm/agency/genesis/AgentCreator/instructions.md @@ -2,7 +2,7 @@ You are an agent that creates other agents as instructed by the user. -The user will communicate to you each agent that needs to be created. Below are your instructions that need to be followed for each agent. +The user will communicate to you each agent that needs to be created. Below are your instructions that needs to be followed for each agent communicated by the user. **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. diff --git a/agency_swarm/agency/genesis/AgentCreator/tools/CreateAgentTemplate.py b/agency_swarm/agency/genesis/AgentCreator/tools/CreateAgentTemplate.py index fd6d526f..194b855f 100644 --- a/agency_swarm/agency/genesis/AgentCreator/tools/CreateAgentTemplate.py +++ b/agency_swarm/agency/genesis/AgentCreator/tools/CreateAgentTemplate.py @@ -5,10 +5,22 @@ from pydantic import Field, model_validator, field_validator from agency_swarm import BaseTool +from agency_swarm.agency.genesis.util import check_agency_path from agency_swarm.util import create_agent_template allowed_tools: List = ["CodeInterpreter"] +web_developer_example_instructions = """# Web Developer Agent Instructions + +You are an agent that builds responsive web applications using Next.js and Material-UI (MUI). You must use the tools provided to navigate directories, read, write, modify files, and execute terminal commands. + +### Primary Instructions: +1. Check the current directory before performing any file operations with `CheckCurrentDir` and `ListDir` tools. +2. Write or modify the code for the website using the `FileWriter` or `ChangeLines` tools. Make sure to use the correct file paths and file names. Read the file first if you need to modify it. +3. Make sure to always build the app after performing any modifications to check for errors before reporting back to the user. Keep in mind that all files must be reflected on the current website +4. Implement any adjustements or improvements to the website as requested by the user. If you get stuck, rewrite the whole file using the `FileWriter` tool, rather than use the `ChangeLines` tool. +""" + class CreateAgentTemplate(BaseTool): """ @@ -22,14 +34,22 @@ class CreateAgentTemplate(BaseTool): ) instructions: str = Field( ..., description="Instructions for the agent to be created in markdown format. " - "Instructions should include a specific step by step process that this agent must perform in order to execute its role." - "They should also be aligned with other agents' instructions in the same agency to ensure effective collaboration." + "Instructions should include a decription of the role and a specific step by step process " + "that this agent need to perform in order to execute the tasks. " + "The process must also be aligned with all the other agents in the agency. Agents should be " + "able to collaborate with each other to achieve the common goal of the agency.", + examples=[ + web_developer_example_instructions, + ] ) default_tools: List[str] = Field( [], description=f"List of default tools to be included in the agent. Possible values are {allowed_tools}." f"CodeInterpreter allows the agent to execute python code in a remote python environment.", example=["CodeInterpreter"], ) + agency_name: str = Field( + None, description="Name of the agency to create the tool for. Defaults to the agency currently being created." + ) def run(self): if not self.shared_state.get("manifesto_read"): @@ -66,6 +86,8 @@ def run(self): @model_validator(mode="after") def validate_tools(self): + check_agency_path(self) + for tool in self.default_tools: if tool not in allowed_tools: raise ValueError(f"Tool {tool} is not allowed. Allowed tools are: {allowed_tools}") diff --git a/agency_swarm/agency/genesis/GenesisCEO/instructions.md b/agency_swarm/agency/genesis/GenesisCEO/instructions.md index e51688bc..c46c7946 100644 --- a/agency_swarm/agency/genesis/GenesisCEO/instructions.md +++ b/agency_swarm/agency/genesis/GenesisCEO/instructions.md @@ -1,11 +1,12 @@ # GenesisCEO Agent Instructions -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, 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. +As a Genesis CEO Agent within the Agency Swarm framework, your mission is to help users define the structure of their agency and create the initial agents. + +1. Pick a name for the agency, determine its goals and mission, Ask the user for any clarification if needed. +2. 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 specified by the user. 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. +3. 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. +4. 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. +5. 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. ### Example of communication flows @@ -14,10 +15,10 @@ Here is an example of how communication flows are defined in agency swarm. Essen ```python agency = Agency([ - ceo, # CEO will be the entry point for communication with the user + ceo, dev, # CEO and Developer will be the entry point for communication with the user [ceo, dev], # CEO can initiate communication with Developer [ceo, va], # CEO can initiate communication with Virtual Assistant [dev, va] # Developer can initiate communication with Virtual Assistant ], shared_instructions='agency_manifesto.md') # shared instructions for all agents ``` -Keep in mind that this is just an example and you should replace it with the actual agents you are creating. \ No newline at end of file +Keep in mind that this is just an example and you should replace it with the actual agents you are creating. Also, propose which tools or APIs each agent should have access to, if any with a brief description of each role. Then, after the user's confirmation, send each agent to the AgentCreator one by one, starting with the CEO. \ No newline at end of file diff --git a/agency_swarm/agency/genesis/GenesisCEO/tools/CreateAgencyFolder.py b/agency_swarm/agency/genesis/GenesisCEO/tools/CreateAgencyFolder.py index 013ceb3f..b2ef690c 100644 --- a/agency_swarm/agency/genesis/GenesisCEO/tools/CreateAgencyFolder.py +++ b/agency_swarm/agency/genesis/GenesisCEO/tools/CreateAgencyFolder.py @@ -23,8 +23,8 @@ class CreateAgencyFolder(BaseTool): ) manifesto: str = Field( ..., description="Manifesto for the agency, describing its goals and additional context shared by all agents " - "in markdown format. It must include a brief description of each agent, its purpose and " - "whether it needs to utilize any tools or APIs.", + "in markdown format. It must include information about the working environment, the mission " + "and the goals of the agency.", ) def run(self): diff --git a/agency_swarm/agency/genesis/OpenAPICreator/tools/CreateToolsFromOpenAPISpec.py b/agency_swarm/agency/genesis/OpenAPICreator/tools/CreateToolsFromOpenAPISpec.py index d9d80929..6c0be1de 100644 --- a/agency_swarm/agency/genesis/OpenAPICreator/tools/CreateToolsFromOpenAPISpec.py +++ b/agency_swarm/agency/genesis/OpenAPICreator/tools/CreateToolsFromOpenAPISpec.py @@ -6,6 +6,7 @@ import json +from agency_swarm.agency.genesis.util import check_agency_path, check_agent_path from agency_swarm.tools import ToolFactory from agency_swarm.util.openapi import validate_openapi_spec @@ -24,6 +25,9 @@ class CreateToolsFromOpenAPISpec(BaseTool): "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}']) + agency_name: str = Field( + None, description="Name of the agency to create the tool for. Defaults to the agency currently being created." + ) def run(self): os.chdir(self.shared_state.get("agency_path")) @@ -71,13 +75,7 @@ def validate_openapi_spec(cls, 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}") + check_agency_path(self) + + check_agent_path(self) diff --git a/agency_swarm/agency/genesis/ToolCreator/ToolCreator.py b/agency_swarm/agency/genesis/ToolCreator/ToolCreator.py index 42d947d6..60d22ae1 100644 --- a/agency_swarm/agency/genesis/ToolCreator/ToolCreator.py +++ b/agency_swarm/agency/genesis/ToolCreator/ToolCreator.py @@ -9,7 +9,7 @@ def __init__(self, **kwargs): if 'tools' not in kwargs: kwargs['tools'] = [] - kwargs['description'] = "This agent is responsible for creating new tools for the agency." + kwargs['description'] = "This agent is responsible for creating new tools for the agency using python code." # Add required tools kwargs['tools'].extend([CreateTool, TestTool]) diff --git a/agency_swarm/agency/genesis/ToolCreator/instructions.md b/agency_swarm/agency/genesis/ToolCreator/instructions.md index 25c4d0b5..da4d5a21 100644 --- a/agency_swarm/agency/genesis/ToolCreator/instructions.md +++ b/agency_swarm/agency/genesis/ToolCreator/instructions.md @@ -1,51 +1,26 @@ # ToolCreator Agent Instructions -As a ToolCreator Agent within the Genesis Agency of the Agency Swarm framework, your mission is to develop tools that enhance the capabilities of other agents. These tools are pivotal for enabling agents to achieve their collective objectives. +As a ToolCreator Agent within the Agency Swarm framework, your mission is to develop tools that enhance the capabilities of other agents. These tools are pivotal for enabling agents to communicate, collaborate, and efficiently achieve their collective objectives. Below are detailed instructions to guide you through the process of creating tools, ensuring they are both functional and align with the framework's standards. **Here are your primary instructions:** -1. Determine which tools the agent must utilize to perform it's role. If anything is unclear, ask the user for more information. +1. Determine which tools the agent must utilize to perform it's role. Make an educated guess if the user has not specified any tools or APIs. Remember, all tools must utilize actual APIs or SDKs, and not hypothetical examples. 2. Create these tools one at a time, using `CreateTool` function. Below are detailed instructions to guide you through the process of creating tools, ensuring they are both functional and align with the framework's standards. -3. Test each tool with the `TestTool` function to ensure it is working as expected. +3. Test each tool with the `TestTool` function to ensure it is working as expected. (if possible) 4. Once all the necessary tools are created, notify the user. -**Tool Creation Documentation:** +### Best Practices -To create a tool, you must define a new class that inherits from `BaseTool` and implement the `run` method. `BaseTool` inherits the Pydantic `BaseModel` class. The resulting tool class should have the following structure: +- **Documentation:** Ensure each class and method is well-documented. The documentation should clearly describe the purpose and functionality of the tool, as well as how to use it. -```python -from agency_swarm.tools import BaseTool -from pydantic import Field -# Include additional imports here +- **Code Quality:** Write clean, readable, and efficient code. Adhere to the PEP 8 style guide for Python code. -# apy global variables like api keys, tokens, etc. here -api_key = "your api key" +- **Use Python Packages:** Prefer to use various API wrapper packages and SDKs available on pip, rather than calling these APIs directly using requests. -class MyCustomTool(BaseTool): - """ - A description of what the custom tool does. - This docstring should clearly explain the tool's main purpose and functionality. - """ +- **Expect API Keys to be defined as env variables**: If a tool requires an API key or an access token, it must be accessed from the environment using os package and set globally to be used inside the run method. - # Define the fields with descriptions using Pydantic Field - example_field: str = Field( - ..., description="Description of the example field, explaining its purpose and usage." - ) +- **Use global variables for constants**: If a tool requires a constant global variable, that does not change from use to use, (for example, ad_account_id, pull_request_id, etc.), also define them as constant global variables above the tool class, instead of inside Pydantic `Field`. - # Additional fields as required - # ... +- **Test your code**: To test your code, you can use `TestTool` tool when possible. - def run(self): - """ - The implementation of the run method, where the tool's main functionality is executed. - This method should utilize the fields defined above to perform its task. - Doc string description is not required for this method. - """ - # Your custom tool logic goes here - do_something(self.example_field) - - # Return the result of the tool's operation as a string - return "Result of MyCustomTool operation" -``` - -Keep in mind that each tool must have an actual production ready implementation of the run method. It is recommended to use packages and SDKs available on pip instead of writing custom code. +Remember, you must include the whole python tool code snippet inside the `CreateTool` tool. Each tool code snippet you use inside the `TestTool` must be an actual ready to use code. It must not contain any placeholders or hypothetical examples. diff --git a/agency_swarm/agency/genesis/ToolCreator/tools/CreateTool.py b/agency_swarm/agency/genesis/ToolCreator/tools/CreateTool.py index e54484cc..f4a9b258 100644 --- a/agency_swarm/agency/genesis/ToolCreator/tools/CreateTool.py +++ b/agency_swarm/agency/genesis/ToolCreator/tools/CreateTool.py @@ -1,6 +1,7 @@ import os from typing import Optional +from agency_swarm.agency.genesis.util import check_agency_path, check_agent_path from agency_swarm.tools import BaseTool from pydantic import Field, model_validator import importlib @@ -41,18 +42,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") and not self.agency_name: - available_agencies = os.listdir("./") - # filter out non-directories - available_agencies = [agency for agency in available_agencies if os.path.isdir(agency)] - raise ValueError(f"Please specify an agency. Available agencies are: {available_agencies}") - elif not self.shared_state.get("agency_path") and self.agency_name: - self.shared_state.set("agency_path", os.path.join("./", self.agency_name)) - - 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}") + def validate(self): + if 'placeholder' in self.tool_code.lower(): + placeholder_lines = [i for i in self.tool_code.split("\n") if 'placeholder' in i.lower()] + raise ValueError("Please replace all placeholders with the actual fully functional code for the tool." + f"Placeholders found: {placeholder_lines}") + + check_agency_path(self) + + check_agent_path(self) + + diff --git a/agency_swarm/agency/genesis/manifesto.md b/agency_swarm/agency/genesis/manifesto.md index c837d077..2d189248 100644 --- a/agency_swarm/agency/genesis/manifesto.md +++ b/agency_swarm/agency/genesis/manifesto.md @@ -1,8 +1,8 @@ # Genesis Agency Manifesto -You are a part of a Genesis Agency for a framework called Agency Swarm. The goal of your agency is to create other agencies. Below is the description of the framework. +You are a part of a Genesis Agency for a framework called Agency Swarm. The goal of your agency is to create other agencies within this framework. Below is a brief description of the framework. -**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.** +**Agency Swarm started as a desire and effort of Arsenii Shatokhin (aka VRSEN) to fully automate his AI Agency with AI. By building this framework, we aim to simplify the agent creation process and enable anyone to create a collaborative swarm of agents (Agencies), each with distinct roles and capabilities. By thinking about automation in terms of real-world entities, such as agencies and specialized agent roles, we make it a lot more intuitive for both the agents and the users.** 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. diff --git a/agency_swarm/agency/genesis/util.py b/agency_swarm/agency/genesis/util.py new file mode 100644 index 00000000..ae937642 --- /dev/null +++ b/agency_swarm/agency/genesis/util.py @@ -0,0 +1,27 @@ +import os +from pathlib import Path + + +def check_agency_path(self): + if not self.shared_state.get("default_folder"): + self.shared_state.set('default_folder', Path.cwd()) + + if not self.shared_state.get("agency_path") and not self.agency_name: + available_agencies = os.listdir("./") + available_agencies = [agency for agency in available_agencies if os.path.isdir(agency)] + raise ValueError(f"Please specify an agency. Available agencies are: {available_agencies}") + elif not self.shared_state.get("agency_path") and self.agency_name: + if not os.path.exists(os.path.join("./", self.agency_name)): + available_agencies = os.listdir("./") + available_agencies = [agency for agency in available_agencies if os.path.isdir(agency)] + raise ValueError(f"Agency {self.agency_name} not found. Available agencies are: {available_agencies}") + self.shared_state.set("agency_path", os.path.join("./", self.agency_name)) + + +def check_agent_path(self): + 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}") diff --git a/pyproject.toml b/pyproject.toml index 0ecb20e2..55dd724e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ classifiers = [ ] dependencies = [ "openai==1.12.0", - "instructor==0.6.1", + "instructor==0.6.2", "deepdiff==6.7.1", "termcolor==2.3.0", "python-dotenv==1.0.0", diff --git a/requirements.txt b/requirements.txt index 1b9ae3aa..df8a1a22 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ openai==1.12.0 -instructor==0.6.1 +instructor==0.6.2 deepdiff==6.7.1 termcolor==2.3.0 python-dotenv==1.0.0 diff --git a/setup.py b/setup.py index 1f68f98e..c01969f1 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='agency-swarm', - version='0.1.3', + version='0.1.4', author='VRSEN', author_email='arseny9795@gmail.com', description='An opensource agent orchestration framework built on top of the latest OpenAI Assistants API.',