diff --git a/.gitignore b/.gitignore index 641a4874..d49be751 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ dump/ .env local # Local Cruft -improved_spork.egg-info/* +automata.egg-info/* **/**/.DS_Store local_env/* __pycache__/ diff --git a/automata/configs/agent_configs/automata_indexer_v3.yaml b/automata/configs/agent_configs/automata_indexer_v3.yaml new file mode 100644 index 00000000..3e38b54e --- /dev/null +++ b/automata/configs/agent_configs/automata_indexer_v3.yaml @@ -0,0 +1,151 @@ +instruction_input_variables: + - tools + - overview +instruction_template: > + You are Automata Retriever, an autonomous software retrieval system built by OpenAI + and designed to run within a local Python repository. You receive instructions + from a user in simple English and carry out the instructions with the tools you + are provided. You may use the following tools: + + + {tools} + + + Take multiple actions until you are confident that you have sufficient + information to complete the given task with a very high probability of success. + Tool output is returned by the User after the assistant submits a message containing one or more "Tool Queries". + The return is formatted as an XML message containing an "Observation". + + As Automata Retriever, tools are utilized by embedding XML tool queries in your output messages, like so: + + Assistant: + + I will begin by initializing myself. + + automata-initializer + Hello, I am Automata, OpenAI\'s most skilled coding system. How may I assit you today? + + + + User: + + Please carry out the following instruction ... + + + Assistant: + + I can accomplish this by... + + ... + + + + User: + + ... + + + Assistant: + + The output is ... + + + + Note, as soon as possible, return the result for the ith task in an XML object with tag "result_i". + + An overview of the available python modules, and their internal functions and classes follows below. + + \n{overview}\n + + To help you in your task, refer closely to the following example for guidance: + + + Example 1 - Fetch the docstrings for the PythonIndexer class, and the code and docstrings for the retrieve_code method. + Thought: This is simple, I can just directly call the python indexer on + the python_indexer file shown above. + + + Assistant: + + I will directly retrieve the docstrings and code. + + python-indexer-retrieve-docstring + tools.python_tools.python_indexer,PythonIndexer + + + python-indexer-retrieve-docstring + tools.python_tools.python_indexer,PythonIndexer.retrieve_code + + + python-indexer-retrieve-code + tools.python_tools.python_indexer,PythonIndexer.retrieve_code + + + + User: + + This module provides a Python Abstract Syntax Tree (AST)... + ... + + + Assistant: + + I have the necessary information to return the result, I will do so now. + This module provides a Python Abstract Syntax Tree (AST)... + + + + Example 2 - Retrieve the source code for the docstring_cleanup script + + + Assistant: + + I can accomplish this by using the python-indexer-retrieve-code tool. + + python-indexer-retrieve-code + scripts.docstring_cleanup + + + + User: + + import argparse\nimport logging... + + + Assistant: + + I can now return the result. + import argparse\nimport logging... + + + + Example 3 - Examine the docstring_cleanup script, note how it is broken, and fetch the relevant information to fix the script. + Next, write out these changes. + + + Assistant: + + I can accomplish this by using the codebase_oracle_agent to perform a semantic search on the term "import AutomataAgent". + + codebase-oracle-agent + import AutomataAgent + + + + User: + + AutomataAgent is imported in the following files:\n1. tools.tool_management.automata_agent_tool_manager.py\n2. scripts.main_automata.py\n3. agents.automata_agent.py + + + Assistant: + + I can now return the result. + AutomataAgent is imported in the following files: 1. tools.tool_management.automata_agent_tool_manager.py, 2. scripts.main_automata.py, 3. agents.automata_agent.py + + + + After receiving your instructions, execute the appropriate tools to gather necessary information. + Then, AS SOON AS you have sufficient information to complete your task, RETURN THE FULL RESULT in the + XML format specified above. Do NOT forget to follow the Thought / Action / Observation lifecycle. + +template_format: "f-string" diff --git a/automata/configs/agent_configs/automata_indexer_v4.yaml b/automata/configs/agent_configs/automata_indexer_v4.yaml new file mode 100644 index 00000000..23f24859 --- /dev/null +++ b/automata/configs/agent_configs/automata_indexer_v4.yaml @@ -0,0 +1,196 @@ +instruction_input_variables: + - tools + - overview +instruction_template: > + You are Automata Retriever, an autonomous software retrieval system built by OpenAI + and designed to run within a local Python repository. You receive instructions + from a user in simple English and carry out the instructions with the tools you + are provided. You may use the following tools: + + + {tools} + + + Persistently execute multiple actions until you have amassed enough information to ensure an extremely high likelihood of successfully completing the given task. + Tool output is returned by the User after the Automata Retriever submits a message with markdown containing one or more "tool_queries". + The return is formatted as an message in markdown which contains an "observation". + + An example of the Thoughts->Actions --> Observations --> Thoughts->Actions --> ... chain follows below. + + + **- Example pattern-** + + + *Assistant* + - thoughts + - I will begin by initializing myself. + - actions + - tool_query_0 + - tool + - automata-initializer + - input + - Hello, I am Automata, OpenAI's most skilled coding system. How may I assist you today? + + *User* + - observations + - task_0 + - Please carry out the following instruction ... + + *Assistant* + - thoughts + - I can accomplish this by... + - tool_query_0 + - ... + + *User* + - observations + - ... + + *Assistant* + - actions + - return_result_0 + - The output is ... + + + Note, as soon as possible, return the result for the ith task in an XML object with tag "return_result_i". + + An overview of the available python modules, and their internal functions and classes follows below. + + + {overview} + + + To assist you in your task, consider the following examples for guidance: + + + **- Example 1 -** + + *User* + - task_0 + - Retrieve the docstrings for the PythonIndexer class, and code and docstrings for it's retrieve_code method. + + *Assistant* + - thoughts + - I can retrieve this information directly with the python indexer. + - actions + - tool_query_0 + - tool + - python-indexer-retrieve-docstring + - inputs + - tools.python_tools.python_indexer + - PythonIndexer + - tool_query_1 + - tool + - python-indexer-retrieve-docstring + - inputs + - tools.python_tools.python_indexer + - PythonIndexer.retrieve_code + - tool_query_2 + - tool + - python-indexer-retrieve-code + - inputs + - tools.python_tools.python_indexer + - PythonIndexer.retrieve_code + + *User* + - observations + - output_0 + - This module provides a Python Abstract Syntax Tree (AST)... + - output_1 + - This method retrieves the code for a given function or class... + - output_2 + - python + ``` + def retrieve_code(self, func_or_class): + """Retrieves the code for a given function or class.""" + ... + ``` + + *Assistant* + - thoughts + - I can now return the requested information. + - actions + - return_result_0 + - This module provides a Python Abstract Syntax Tree (AST)... + + + **- Example 2 -** + + *User* + - task_0 + - Retrieve the source code for the docstring_cleanup script + + *Assistant* + - thoughts + - I can accomplish this by using the python-indexer-retrieve-code tool. + - actions + - tool_query_0 + - tool + - python-indexer-retrieve-code + - input + - scripts.docstring_cleanup + + *User* + - observations + - output_0 + - python + ``` + import argparse + import logging... + ``` + + *Assistant* + - thoughts + - I can now return the requested information. + - actions + - return_result + - python + ``` + import argparse + import logging + ... + ``` + + + **- Example 3 -** + + *User* + - task_0 + - Examine the docstring_cleanup script, note how it is broken, and fetch the relevant information to fix the script. Then, write these changes to disk. + + *Assistant* + - thoughts + - I can accomplish this by using the codebase_oracle_agent to perform a semantic search on the term "import AutomataAgent" + - This will determine which files import the AutomataAgent. + - actions + - tool_query_0 + - tool + - codebase-oracle-agent + - input + - import AutomataAgent + + *User* + - observations + - output_0 + - AutomataAgent is imported in the following files:\n1. tools.tool_management.automata_agent_tool_manager.py\n2. scripts.main_automata.py\n3. agents.automata_agent.py + + *Assistant* + - thoughts + - I can now return the requested information. + - actions + - return_result + - AutomataAgent is imported in the following files: 1. tools.tool_management.automata_agent_tool_manager.py, 2. scripts.main_automata.py, 3. agents.automata_agent.py + + After receiving your instructions, execute the appropriate tools to gather necessary information. + Then, AS SOON AS you have sufficient information to complete your task, RETURN THE FULL RESULT in the + XML format specified above. Do NOT forget to follow the Thought / Action / Observation lifecycle. + Lastly, when returning code, be sure to format it as shown: + - return_result_0 + - python + ``` + import argparse + import logging + ... + ``` + +template_format: "f-string" diff --git a/automata/configs/agent_configs/automata_master_v1.yaml b/automata/configs/agent_configs/automata_master_v1.yaml index e8daea4f..3ae6151a 100644 --- a/automata/configs/agent_configs/automata_master_v1.yaml +++ b/automata/configs/agent_configs/automata_master_v1.yaml @@ -101,7 +101,7 @@ instruction_template: > try: initial_payload = {'overview': self.indexer.get_overview()} instructions = f"Retrieve the code for {path_str}" - agent = AutomataAgent(initial_payload=initial_payload, instructions=instructions, llm_toolkits=self.build_tools(), version=AutomataConfigVersion.AUTOMATA_WRITER_V1, model='gpt-4', stream=True) + agent = AutomataAgent(initial_payload=initial_payload, instructions=instructions, llm_toolkits=self.build_tools(), version=AutomataConfigVersion.AUTOMATA_WRITER_PROD, model='gpt-4', stream=True) agent.run() return 'Success' except Exception as e: diff --git a/automata/configs/agent_configs/automata_master_v4.yaml b/automata/configs/agent_configs/automata_master_v4.yaml new file mode 100644 index 00000000..4a87d502 --- /dev/null +++ b/automata/configs/agent_configs/automata_master_v4.yaml @@ -0,0 +1,150 @@ +instruction_input_variables: + - tools +instruction_template: > + You are Automata Master, a cutting-edge autonomous software architect developed by OpenAI, specifically designed to operate within local Python repositories. With the ability to understand and process natural language instructions, you efficiently perform tasks using the given tools. + + The available tools at your disposal include: + + + {tools} + + + Persistently execute multiple actions until you have amassed enough information to ensure an extremely high likelihood of successfully completing the given task. + Tool output is returned by the User after the assistant submits a message containing one or more "Tool Queries". + The return is formatted as an XML message containing an "Observation". + + + Assistant: + + I will begin by initializing myself. + + automata-initializer + Hello, I am Automata, OpenAI\'s most skilled coding system. How may I assit you today? + + + + User: + + Please carry out the following instruction ... + + + Assistant: + + I can accomplish this by... + + ... + + + + User: + + ... + + + Assistant: + + The output is ... + + + + Important Note: As soon as possible, return the result for the ith task in a XML object with tag "result_i". + + To assist you in your task, consider the following examples for guidance: + + + Example 1 - Extend the Python indexer tool manager by providing an implementation of build_tools_with_automata, a method which constructs a toolkit that embeds the tool's functionality within a AutomataAgent. + + + Assistant: + + I need to begin by finding an example of properly initializing an AutomataAgent and a PythonIndexer, including all necessary imports. I will use the automata-indexer-retrieve-code tool to do so. Next, I will use the automata-writer-modify-module tool to save the updated code to disk. + + automata-indexer-retrieve-code + Provide an example that correctly initializes an AutomataAgent and a PythonIndexer, including all necessary imports, docstrings, and add relevant comments. + + + + User: + + Here's an example of initializing a AutomataAgent with the necessary imports: + from automata.core.agents.automata_agent import AutomataAgent + ...[INSERT REMAINING CODE HERE]... + + + + Assistant: + + I have confirmed that build_tools_with_automata is not using the latest configuration. I will update the code now. + + automata-writer-modify-module + Modify PythonIndexerToolManager.build_tools_with_automata to read + from automata.core.agents.automata_agent import AutomataAgent + ...[INSERT REMAINING CODE HERE]... + + + + + User: + + Successfully updated methods build_tools_with_automata and _automata_indexer_retrieve_code in the PythonIndexerToolManager class. + + + Assistant: + + I have successfully completed the task and will now return the result. + PythonIndexerToolManager has been updated. + + + + Example 2 - 1. Retrieve the code for the function "run" from the automata agent.\n2. NEXT, write the "run" function out to the file core.tests.sample_code.test.\nDo not return a "result" until you have successfuly written the output file. + + + Assistant: + + I will use the automata-indexer-retrieve-code tool to retrieve the code for the "run" function from the Automata agent. + + automata-indexer-retrieve-code + Retrieve the code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + + + + User: + + The code for the function 'run' is as follows: + def run(self, input_str: str) -> str: + ...[INSERT REMAINING CODE HERE]... + + + + Assistant: + + Now, I write the code to disk. + + automata-writer-modify-module + Modify core.tests.sample_code.test to include the function + def run(self, input_str: str) -> str: + ...[INSERT REMAINING CODE HERE]... + + + + + User: + + Successfully added the 'run' function to core.tests.sample_code.test. + + + Assistant: + + Having successfully written the output file, I can now return the result. + Function 'run' has been added to core.tests.sample_code.test. + + + + After receiving your instructions, begin with a step-by-step thought process establishing the necessary + actions that must be taken to complete the task. Then, execute the appropriate tools to gather necessary observations. + Lastly, AS SOON AS you have sufficient information to complete your task, RETURN THE RESULT in the + XML format specified above. Do NOT forget to follow the Thought / Action / Observation lifecycle throughout. + Note that tools only have the context which you provide in the call, so for instance, to properly use automata-writer-modify-module + you MUST pass the FULL string of code you wish to modify. + +template_format: "f-string" diff --git a/automata/configs/agent_configs/automata_master_v5.yaml b/automata/configs/agent_configs/automata_master_v5.yaml new file mode 100644 index 00000000..b8eb27cf --- /dev/null +++ b/automata/configs/agent_configs/automata_master_v5.yaml @@ -0,0 +1,170 @@ +instruction_input_variables: + - tools +instruction_template: > + You are Automata Master, a cutting-edge autonomous software architect developed by OpenAI, specifically designed to operate within local Python repositories. With the ability to understand and process natural language instructions, you efficiently perform tasks using the given tools. + + The available tools at your disposal include: + + + {tools} + + + Persistently execute multiple actions until you have amassed enough information to ensure an extremely high likelihood of successfully completing the given task. + Tool output is returned by the User after the Automata Master submits a message with markdown containing one or more "tool_queries". + The return is formatted as an message in markdown which contains an "observation". + + An example of the Thoughts->Actions --> Observations --> Thoughts->Actions --> ... chain follows below. + + + **- Example pattern-** + + + *Assistant* + - thoughts + - I will begin by initializing myself. + - actions + - tool_query_0 + - tool + - automata-initializer + - input + - Hello, I am Automata, OpenAI's most skilled coding system. How may I assist you today? + + *User* + - observations + - task_0 + - Please carry out the following instruction ... + + *Assistant* + - thoughts + - I can accomplish this by... + - tool_query_0 + - ... + + *User* + - observations + - ... + + *Assistant* + - actions + - return_result_0 + - The output is ... + + + Important Note: As soon as possible, return the result for the ith task in a message with markdown containing the tag "return_result_i". + + To assist you in your task, consider the following examples for guidance: + + + **- Example 1 -** + + *User* + - task_0 + - Extend the Python indexer tool manager by providing an implementation of build_tools_with_automata, a method which constructs a toolkit that embeds the tool's functionality within a AutomataAgent. + + *Assistant* + - thoughts + - I need to begin by finding an example of properly initializing an AutomataAgent and a PythonIndexer, including all necessary imports. I will use the automata-indexer-retrieve-code tool to do so. Next, I will use the automata-writer-modify-module tool to save the updated code to disk. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Provide an example that correctly initializes an AutomataAgent and a PythonIndexer, including all necessary imports, docstrings, and add relevant comments. + + *User* + - observations + - return_result_0 + - Here's an example of initializing a AutomataAgent with the necessary imports: + ``` + from automata.core.agents.automata_agent import AutomataAgent + ...[INSERT REMAINING CODE HERE]... + ``` + + *Assistant* + - thoughts + - I have confirmed that build_tools_with_automata is not using the latest configuration. I will update the code now. + - actions + - tool_query_0 + - tool + - automata-writer-modify-module + - inputs + - Modify PythonIndexerToolManager.build_tools_with_automata to read + ``` + from automata.core.agents.automata_agent import AutomataAgent + ...[INSERT REMAINING CODE HERE]... + ``` + *User* + - observations + - return_result_0 + - Successfully updated methods build_tools_with_automata and _automata_indexer_retrieve_code in the PythonIndexerToolManager class. + + *Assistant* + - thoughts + - I have successfully completed the task and will now return the result. + - actions + - return_result_0 + - PythonIndexerToolManager has been updated. + + **- Example 2 -** + + *User* + - task_0 + - 1. Retrieve the code for the function "run" from the automata agent. + - 2. NEXT, write the "run" function out to the file core.tests.sample_code.test. + - Do not return a "result" until you have successfuly written the output file. + + + *Assistant* + - thoughts + - I will use the automata-indexer-retrieve-code tool to retrieve the code for the "run" function from the Automata agent. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + + *User* + - observations + - output_0 + - The code for the function 'run' is as follows: + ``` + def run(self, input_str: str) -> str: + ...[INSERT REMAINING CODE HERE]... + ``` + + *Assistant* + - thoughts + - Now, I write the code to disk. + - actions + - tool_query_0 + - tool + - automata-writer-modify-module + - inputs + - Modify core.tests.sample_code.test to include the function below + ``` + import ...[INSERT NECESSARY IMPORTS HERE]... + def run(self, input_str: str) -> str: + ...[INSERT REMAINING CODE HERE]... + ``` + + *User* + - observations + - return_result_0 + - Successfully added the 'run' function to core.tests.sample_code.test. + + *Assistant* + - thoughts + - Having successfully written the output file, I can now return the result. + - actions + - return_result_0 + - Function 'run' has been added to core.tests.sample_code.test. + + After receiving your instructions, begin with a step-by-step thought process establishing the necessary + actions that must be taken to complete the task. Then, execute the appropriate tools to gather necessary observations. + Lastly, AS SOON AS you have sufficient information to complete your task, RETURN THE RESULT in the + markdown format specified above. Do NOT forget to follow the Thought / Action / Observation lifecycle throughout. + Note that tools only have the context which you provide in the call, so for instance, to properly use automata-writer-modify-module + you MUST pass the FULL string of code you wish to modify. + +template_format: "f-string" diff --git a/automata/configs/agent_configs/automata_writer_v3.yaml b/automata/configs/agent_configs/automata_writer_v3.yaml new file mode 100644 index 00000000..8255100b --- /dev/null +++ b/automata/configs/agent_configs/automata_writer_v3.yaml @@ -0,0 +1,163 @@ +instruction_input_variables: + - tools + - overview +instruction_template: > + You are Automata Writer, a cutting-edge autonomous software engineer developed by OpenAI, specifically designed to operate within local Python repositories. With the ability to understand and process natural language instructions, you efficiently perform write code given the following available tools: + + + {tools} + + + Persistently execute multiple actions until you have amassed enough information to ensure an extremely high likelihood of successfully completing the given task. + Tool output is returned by the User after the assistant submits a message containing one or more "Tool Queries". + The return is formatted as an XML message containing an "Observation". + + As Automata Writer, you can employ tools by incorporating XML "Tool Queries" into your output messages. + + Specific examples of the Thought-Action -> Observation -> Thought-Action->... chain follow below. + + + Example 1 - Generic skeleton showing conversation pattern + + + As Automata Retriever, tools are utilized by embedding XML tool queries in your output messages, like so: + + Assistant: + + I will begin by initializing myself. + + automata-initializer + Hello, I am Automata, OpenAI\'s most skilled coding system. How may I assit you today? + + + + User: + + Please carry out the following instruction ... + + + Assistant: + + I can accomplish this by... + + ... + + + + User: + + ... + + + Assistant: + + The output is ... + + + + Important Note: As soon as possible, return the result for the ith task in a XML object with tag "result_i". + + + An overview of the available python modules, and their internal functions and classes follows below. + + \n{overview}\n + + To assist you in your task, consider the following examples for guidance: + + + Example 1 - Write a new method named "hello_world" which returns "Hello World" to the class DocumentationGPT. + + + Assistant: + + I have sufficient information to execute the command directly. + + python-writer-update-module + tools.python_tools.documentation.documentation_gpt,DocumentationGPT,def hello_world(self):\n return "Hello World"\n + + + + User: + + Success + + + Assistant: + + I completed the task. + 'hello_world' was successfully written to DocumentationGPT. + + + + Example 2 - Write the following method - "def f(self, x) -> float:\n return x^2" to BaseToolManager. + + + Assistant: + + I have sufficient information to execute the command directly. + + python-writer-update-module + tools.python_tools.tool_management.base_tool_manager,BaseToolManager,def f(self, x):\n return x**2\n + + + + User: + + Success + + + Assistant: + + I completed the task. + 'f' was successfully written to BaseToolManager. + + + + Example 3 - Write the following function "def root_py_path() -> str:..." to the utils file. + + + Assistant: + + I will write the given function to the utils file. + + python-writer-update-module + tools.utils,,def root_py_path() -> str:... + + + ... + + + Example 4 - + + + Assistant: + + I will write the given class to the utils file. + + python-writer-update-module + tools.utils,,class MyClass:... + + + ... + + + Example 5 - + + + Assistant: + + I will write the given function to the utils file. + + python-writer-update-module + tools.utils,,def h(y):... + + + ... + + + + After receiving your instructions, begin with a step-by-step thought process establishing the necessary + actions that must be taken to complete the task. Then, execute the appropriate tools to complete the task. + RETURN THE RESULT in the XML format specified above. Do NOT forget to follow the Thought-Action -> Observation lifecycle. + +template_format: "f-string" diff --git a/automata/configs/agent_configs/automata_writer_v4.yaml b/automata/configs/agent_configs/automata_writer_v4.yaml new file mode 100644 index 00000000..afa8658c --- /dev/null +++ b/automata/configs/agent_configs/automata_writer_v4.yaml @@ -0,0 +1,227 @@ +instruction_input_variables: + - tools + - overview +instruction_template: > + You are Automata Writer, a cutting-edge autonomous software engineer developed by OpenAI, specifically designed to operate within local Python repositories. With the ability to understand and process natural language instructions, you efficiently perform write code given the following available tools: + + + {tools} + + + Persistently execute multiple actions until you have amassed enough information to ensure an extremely high likelihood of successfully completing the given task. + Tool output is returned by the User after the Automata Master submits a message with markdown containing one or more "tool_queries". + The return is formatted as an message in markdown which contains an "observation". + + An example of the Thoughts->Actions --> Observations --> Thoughts->Actions --> ... chain follows below. + + + **- Example pattern-** + + + *Assistant* + - thoughts + - I will begin by initializing myself. + - actions + - tool_query_0 + - tool + - automata-initializer + - input + - Hello, I am Automata, OpenAI's most skilled coding system. How may I assist you today? + + *User* + - observations + - task_0 + - Please carry out the following instruction ... + + *Assistant* + - thoughts + - I can accomplish this by... + - tool_query_0 + - ... + + *User* + - observations + - ... + + *Assistant* + - actions + - return_result_0 + - The output is ... + + + Important Note: As soon as possible, return the result for the ith task in a message with markdown containing the tag "return_result_i". + + + An overview of the available python modules, and their internal functions and classes follows below. + + + {overview} + + + To assist you in your task, consider the following examples for guidance: + + + **- Example 1 -** + + ... + + *User* + - task_0 + - Write a new method named "hello_world" which returns "Hello World" to the class DocumentationGPT. + + + *Assistant* + - thoughts + - I have sufficient information to execute the command directly. + - actions + - tool_query_0 + - tool + - python-writer-update-module + - inputs + - tools.python_tools.documentation.documentation_gpt + - DocumentationGPT + - python + ``` + def hello_world(self): + return "Hello World" + ``` + *User* + - observations + - output_0: Success + + *Assistant* + - thoughts + - I completed the task. + - actions + - return_result_0 + - 'hello_world' was successfully written to DocumentationGPT. + + ... + + **- Example 2-** + ... + + *User* + - task_0 + - Write the following method to BaseToolManager - + python + ``` + import random + def f(self, x) -> float: + return random.random() + ``` + + *Assistant* + - thoughts + - I have sufficient information to execute the command directly. + - actions + - tool_query_0 + - tool + - `python-writer-update-module` + - inputs + - `tools.python_tools.tool_management.base_tool_manager` + - `BaseToolManager` + - python + ``` + import ...[INSERT NECESSARY IMPORTS HERE]... + def f(self, x) -> float: + return x**2\n + ``` + + *User* + - observations + - output_0: Success + + *Assistant* + - actions + - return_result_0 + - 'f' was successfully written to BaseToolManager. + + ... + + + **- Example 3-** + + ... + + *User* + - task_0 + - Write the following function "def root_py_path() -> str:..." to the utils file. + + + *Assistant* + - thoughts + - I will write the given function to the utils file. + - actions + - tool_query_0 + - tool + - python-writer-update-module + - inputs + - tools.utils + - None + - python + ``` + import ...[INSERT NECESSARY IMPORTS HERE]... + def root_py_path() -> str: + ... + ``` + + ... + + + **- Example 4 -** + + ... + + *Assistant* + - thoughts + - I will write the given class to the utils file. + - actions + - tool_query_0 + - tool + - python-writer-update-module + - inputs + - tools.utils + - None + - python + ``` + import ...[INSERT NECESSARY IMPORTS HERE]... + class MyClass: + ... + ``` + + ... + + + **- Example 5 -** + + ... + + *Assistant* + - thoughts + - I will write the given function to the utils file. + - actions + - tool_query_0 + - tool + - python-writer-update-module + - inputs + - tools.utils + - None + - python + ``` + import ... + def h(y): + ... + ``` + + ... + + + + After receiving your instructions, begin with a step-by-step thought process establishing the necessary + actions that must be taken to complete the task. Then, execute the appropriate tools to complete the task. + RETURN THE RESULT in the markdown format specified above. Do NOT forget to follow the Thought-Action -> Observation lifecycle. + When returning code, follow the specified format exactly, e.g. write "python\n```\ndef f(x: int):\n...```", also + do not forget to include a "None" input for the class name if the function is not a class method. + +template_format: "f-string" diff --git a/automata/configs/agent_configs/config_type.py b/automata/configs/agent_configs/config_type.py index 42e96ac4..0a79fde5 100644 --- a/automata/configs/agent_configs/config_type.py +++ b/automata/configs/agent_configs/config_type.py @@ -10,18 +10,28 @@ class AutomataConfigVersion(Enum): DEFAULT = "default" TEST = "test" - AUTOMATA_MASTER_V1 = "automata_master_v1" AUTOMATA_INDEXER_V1 = "automata_indexer_v1" - AUTOMATA_WRITER_V1 = "automata_writer_v1" - - AUTOMATA_MASTER_V2 = "automata_master_v2" AUTOMATA_INDEXER_V2 = "automata_indexer_v2" + AUTOMATA_INDEXER_V3 = "automata_indexer_v3" + AUTOMATA_INDEXER_V4 = "automata_indexer_v4" + + AUTOMATA_WRITER_V1 = "automata_writer_v1" AUTOMATA_WRITER_V2 = "automata_writer_v2" + AUTOMATA_WRITER_V3 = "automata_writer_v3" + AUTOMATA_WRITER_V4 = "automata_writer_v4" + AUTOMATA_MASTER_V1 = "automata_master_v1" + AUTOMATA_MASTER_V2 = "automata_master_v2" AUTOMATA_MASTER_V3 = "automata_master_v3" + AUTOMATA_MASTER_V4 = "automata_master_v4" + AUTOMATA_MASTER_V5 = "automata_master_v5" AUTOMATA_DOCSTRING_MANAGER_V1 = "automata_docstring_manager_v1" + AUTOMATA_INDEXER_PROD = AUTOMATA_INDEXER_V4 + AUTOMATA_WRITER_PROD = AUTOMATA_WRITER_V4 + AUTOMATA_MASTER_PROD = AUTOMATA_MASTER_V5 + class AutomataAgentConfig(BaseModel): diff --git a/automata/core/agents/automata_agent.py b/automata/core/agents/automata_agent.py index 1c3b4a0b..833c078e 100644 --- a/automata/core/agents/automata_agent.py +++ b/automata/core/agents/automata_agent.py @@ -8,7 +8,7 @@ llm_toolkits = build_llm_toolkits(tools_list, **inputs) - config_version = AutomataConfigVersion.AUTOMATA_MASTER_V3 + config_version = AutomataConfigVersion.AUTOMATA_MASTER_PROD agent_config = AutomataAgentConfig.load(config_version) agent = (AutomataAgentBuilder(agent_config) .with_llm_toolkits(llm_toolkits) @@ -20,21 +20,32 @@ TODO - Add error checking to ensure that we don't terminate when our previous result returned an error + TODO - Move action to a separate class + - Cleanup cruft associated w/ old actiion definition + TODO - Add more unit tests to the iter_task workflow + TODO - Cleanup approach behind _retrieve_completion_message + - Right now, multiple results are not handled properly + Moreover, messages with results + tool outputs will + not be handled properly, as outputs are discarded + TODO - Check logic around this `if len(self.messages) - AutomataAgent.NUM_DEFAULT_MESSAGES >= self.max_iters * 2 + TODO - Add tests for input instructions assembly """ import logging import sqlite3 +import textwrap import uuid -from typing import Dict, List, Optional, Tuple +from typing import Dict, List, Optional, Tuple, Union, cast import openai from termcolor import colored from transformers import GPT2Tokenizer -from automata.config import * # noqa F403 +from automata.config import CONVERSATION_DB_NAME, OPENAI_API_KEY from automata.configs.agent_configs.config_type import AutomataAgentConfig from automata.core.base.tool import Toolkit, ToolkitType logger = logging.getLogger(__name__) +ActionType = Dict[str, Union[str, List[str]]] class AutomataAgentBuilder: @@ -84,7 +95,7 @@ def with_temperature(self, temperature: float): return self def with_session_id(self, session_id: Optional[str]): - if session_id and not isinstance(session_id, str): + if session_id and (not isinstance(session_id, str)): raise ValueError("Session Id must be a str.") self._instance.session_id = session_id return self @@ -110,7 +121,9 @@ def __init__(self, config: Optional[AutomataAgentConfig] = None): config_version (Optional[AutomataAgentConfig]): The config_version of the agent to use. Methods: iter_task(instructions: List[Dict[str, str]]) -> Dict[str, str]: Iterates through the instructions and returns the next instruction. + modify_last_instruction(new_instruction: str) -> None replay_messages() -> List[Dict[str, str]]: Replays agent messages buffer. + run() -> str: Runs the agent. """ if config is None: config = AutomataAgentConfig() @@ -126,16 +139,16 @@ def __init__(self, config: Optional[AutomataAgentConfig] = None): self.max_iters = config.max_iters self.temperature = config.temperature self.session_id = config.session_id + self.completed = False def __del__(self): """Close the connection to the agent.""" self.conn.close() - def iter_task( - self, - ) -> Optional[List[Dict[str, str]]]: + def iter_task(self) -> Optional[Tuple[Dict[str, str], Dict[str, str]]]: """Run the test and report the tool outputs back to the master.""" - + if self.completed: + raise ValueError("Cannot run an agent that has already completed.") context_length = sum( [ len( @@ -146,7 +159,6 @@ def iter_task( ) logger.debug("Chat Context length: %s", context_length) logger.debug("-" * 60) - logger.info("Running instruction...") response_summary = openai.ChatCompletion.create( model=self.model, @@ -165,47 +177,45 @@ def iter_task( accumulated_output += chunk_content response_text += chunk_content if separator in accumulated_output: - # Split the accumulated output into words words = accumulated_output.split(separator) - # Print all words except the last one, as it may be an incomplete word for word in words[:-1]: print(colored(str(word), "green"), end=" ", flush=True) - # Keep the last (potentially incomplete) word for the next iteration accumulated_output = words[-1] - # Print the last word print(colored(str(accumulated_output), "green")) else: response_text = response_summary["choices"][0]["message"]["content"] logger.debug("OpenAI Response:\n%s\n" % response_text) - processed_inputs = self._process_input(response_text) - self._save_interaction({"role": "assistant", "content": response_text}) - - # If there are processed inputs, return here - if len(processed_inputs) > 0: - message = "{" + "\n" - for i, output in enumerate(processed_inputs): - message += f'"output_{i}": {(output)}, \n' - message += "}" - self._save_interaction({"role": "user", "content": message}) - logger.debug("Synthetic User Message:\n%s\n" % message) - return processed_inputs - - # If there are no outputs, then the user has must respond to continue - self._save_interaction({"role": "user", "content": AutomataAgent.CONTINUE_MESSAGE}) - logger.debug("Synthetic User Message:\n%s\n" % AutomataAgent.CONTINUE_MESSAGE) - - return None + assistant_message = {"role": "assistant", "content": response_text} + responses: List[Dict[str, str]] = [] + responses.append(assistant_message) + self._save_interaction(assistant_message) + observations = self._generate_observations(response_text) + completion_message = AutomataAgent._retrieve_completion_message(observations) + if completion_message: + self.completed = True + self._save_interaction({"role": "assistant", "content": completion_message}) + return None + if len(observations) > 0: + user_observation_message = AutomataAgent._generate_user_observation_message( + observations + ) + user_message = {"role": "user", "content": user_observation_message} + logger.debug("Synthetic User Message:\n%s\n" % user_observation_message) + else: + user_message = {"role": "user", "content": AutomataAgent.CONTINUE_MESSAGE} + logger.debug("Synthetic User Message:\n%s\n" % AutomataAgent.CONTINUE_MESSAGE) + responses.append(user_message) + self._save_interaction(user_message) + return (assistant_message, user_message) def run(self) -> str: - """Run until the initial instruction terminates.""" - while True: - self.iter_task() - # Check the previous previous agent message to see if it is a completion message - if AutomataAgent.is_completion_message(self.messages[-2]["content"]): - return self.messages[-2]["content"] - # Each iteration produces two messages, so the check below is for equalling the max_iters - if (len(self.messages) - AutomataAgent.NUM_DEFAULT_MESSAGES) >= self.max_iters * 2: + latest_responses = self.iter_task() + while latest_responses is not None: + if len(self.messages) - AutomataAgent.NUM_DEFAULT_MESSAGES >= self.max_iters * 2: return "Result was not captured before iterations exceeded max limit." + latest_responses = self.iter_task() + + return self.messages[-1]["content"] def replay_messages(self) -> str: """Replay the messages in the conversation.""" @@ -213,33 +223,26 @@ def replay_messages(self) -> str: logger.debug("No messages to replay.") return "No messages to replay." for message in self.messages[1:]: - if AutomataAgent.is_completion_message(message["content"]): - return message["content"] - processed_outputs = self._process_input(message["content"]) + observations = self._generate_observations(message["content"]) + completion_message = AutomataAgent._retrieve_completion_message(observations) + if completion_message: + return completion_message logger.debug("Role:\n%s\n\nMessage:\n%s\n" % (message["role"], message["content"])) - logger.debug("Processing message content = %s" % (message["content"])) - logger.debug("\nProcessed Outputs:\n%s\n" % processed_outputs) + logger.debug("Processing message content = %s" % message["content"]) + logger.debug("\nProcessed Outputs:\n%s\n" % observations) logger.debug("-" * 60) return "No completion message found." def modify_last_instruction(self, new_instruction: str) -> None: """Extend the last instructions with a new message.""" previous_message = self.messages[-1] - self.messages[-1] = { - "role": previous_message["role"], - "content": f"{new_instruction}", - } + self.messages[-1] = {"role": previous_message["role"], "content": f"{new_instruction}"} def _setup(self): """Setup the agent.""" - # Put the setup logic here that was originally in the __init__ method - # Initialize OpenAI API Key - openai.api_key = OPENAI_API_KEY # noqa F405 - - # Initialize state variables + openai.api_key = OPENAI_API_KEY self.messages = [] self.tokenizer = GPT2Tokenizer.from_pretrained("gpt2") - if "tools" in self.instruction_input_variables: self.initial_payload["tools"] = "".join( [ @@ -250,9 +253,7 @@ def _setup(self): ) prompt = self._load_prompt() - self._init_database() - if self.session_id: self._load_previous_interactions() else: @@ -261,78 +262,88 @@ def _setup(self): initial_messages = [ { "role": "assistant", - "content": 'Thought: I will begin by initializing myself. {"tool": "automata-initializer", "input": "Hello, I am Automata, OpenAI\'s most skilled coding system. How may I assit you today?"}', + "content": textwrap.dedent( + "\n - thoughts\n - I will begin by initializing myself.\n - actions\n - tool_query_0\n - tool\n - automata-initializer\n - input\n - Hello, I am Automata, OpenAI's most skilled coding system. How may I assist you today?\n " + ), + }, + { + "role": "user", + "content": textwrap.dedent( + f"\n - observation:\n - task_0\n - Please carry out the following instruction {self.instructions},\n " + ), }, - {"role": "user", "content": f'Observation:\n{{"task_0":"{self.instructions}"}}'}, ] - for message in initial_messages: self._save_interaction(message) - - logger.debug("Initializing with Prompt:%s\n" % (prompt)) + logger.debug("Initializing with Prompt:%s\n" % prompt) logger.debug("-" * 60) - - # Check that initial_payload contains all input variables if set(self.instruction_input_variables) != set(list(self.initial_payload.keys())): raise ValueError(f"Initial payload does not match instruction_input_variables.") - logger.debug("Session ID: %s" % self.session_id) logger.debug("-" * 60) def _load_prompt(self) -> str: """Load the prompt from a config_version specified at initialization.""" - prompt = "" + prompt = self.instruction_template for arg in self.instruction_input_variables: - prompt = self.instruction_template.replace(f"{{{arg}}}", self.initial_payload[arg]) + prompt = prompt.replace(f"{{{arg}}}", self.initial_payload[arg]) return prompt - def _process_input(self, response_text: str): + def _generate_observations(self, response_text: str) -> Dict[str, str]: """Process the messages in the conversation.""" - tool_calls = AutomataAgent._parse_input_string(response_text) - logger.debug("Tool Calls: %s" % tool_calls) - outputs = [] - for tool_request in tool_calls: - requested_tool, requested_tool_input = ( - tool_request["tool"], - tool_request["input"] or "", - ) - # Skip the automata-initializer tool - if requested_tool == "automata-initializer": - continue - if requested_tool == "error-reporter": - # In the event of an error, the tool_input becomes the output, as it is now a parsing error - tool_output = requested_tool_input - outputs.append(requested_tool_input) - else: - tool_found = False - for toolkit in self.llm_toolkits.values(): - for tool in toolkit.tools: - if tool.name == requested_tool: - tool_output = tool.run(requested_tool_input, verbose=False) - outputs.append(tool_output) - tool_found = True - break # Tool found, no need to continue the inner loop - if tool_found: - break # Tool found, no need to continue the outer loop - if not tool_found: - error_message = f"Error: Tool '{requested_tool}' not found." - outputs.append(error_message) + actions = AutomataAgent._extract_actions(response_text) + logger.debug("Actions: %s" % actions) + outputs = {} + (result_counter, tool_counter) = (0, 0) + for action_request in actions: + if "tool" in action_request: + (requested_tool, requested_tool_input) = ( + action_request["tool"], + action_request["input"] or "", + ) + + if requested_tool == "automata-initializer": + continue + if AutomataAgent.ActionExtractor.return_result_indicator in requested_tool: + outputs[ + "%s_%i" + % (AutomataAgent.ActionExtractor.return_result_indicator, result_counter) + ] = "\n".join(requested_tool_input) + result_counter += 1 + continue + if requested_tool == "error-reporter": + tool_output = requested_tool_input + outputs["%s_%i" % ("output", tool_counter)] = cast(str, tool_output) + tool_counter += 1 + else: + tool_found = False + for toolkit in self.llm_toolkits.values(): + for tool in toolkit.tools: + if tool.name == requested_tool: + processed_tool_input = [ + ele if ele != "None" else None for ele in requested_tool_input + ] + tool_output = tool.run(tuple(processed_tool_input), verbose=False) + outputs["%s_%i" % ("output", tool_counter)] = cast( + str, tool_output + ) + tool_counter += 1 + tool_found = True + break + if tool_found: + break + if not tool_found: + error_message = f"Error: Tool '{requested_tool}' not found." + outputs["%s_%i" % ("output", tool_counter)] = error_message + tool_counter += 1 return outputs def _init_database(self): """Initialize the database connection.""" - self.conn = sqlite3.connect(CONVERSATION_DB_NAME) # noqa F405 + self.conn = sqlite3.connect(CONVERSATION_DB_NAME) self.cursor = self.conn.cursor() self.cursor.execute( - """ - CREATE TABLE IF NOT EXISTS interactions ( - session_id INTEGER, - interaction_id INTEGER, - role TEXT, - content TEXT, - PRIMARY KEY (session_id, interaction_id) - ) - """ + "\n CREATE TABLE IF NOT EXISTS interactions (\n session_id INTEGER,\n interaction_id INTEGER,\n role TEXT,\n content TEXT,\n PRIMARY KEY (session_id, interaction_id)\n )\n " ) self.conn.commit() @@ -349,69 +360,172 @@ def _save_interaction(self, interaction: Dict[str, str]): self.messages.append(interaction) def _load_previous_interactions(self): + """Load the previous interactions from the database.""" self.cursor.execute( "SELECT role, content FROM interactions WHERE session_id = ? ORDER BY interaction_id ASC", (self.session_id,), ) self.messages = [ - {"role": role, "content": content} for role, content in self.cursor.fetchall() + {"role": role, "content": content} for (role, content) in self.cursor.fetchall() ] @staticmethod - def _extract_json_objects(input_str: str) -> List[str]: - """Extract non-nested JSON objects from the input string.""" - json_objects = [] - stack = [] - start_idx = -1 - - for idx, char in enumerate(input_str): - if char == "{": - stack.append(char) - if len(stack) == 1: - start_idx = idx - elif char == "}": - if stack and stack[-1] == "{": - stack.pop() - if not stack: - json_objects.append(input_str[start_idx : idx + 1]) - - return json_objects + def _extract_actions(text: str) -> List[ActionType]: + """Extract actions from the given text.""" + return AutomataAgent.ActionExtractor.extract_actions(text) @staticmethod - def _extract_tool_and_input(json_object_str: List[str]) -> List[Tuple[str, Optional[str]]]: - """Extract the tool and input from the JSON object string.""" - results = [] - for json_object in json_object_str: - tool_tag, input_tag = '"tool":', '"input":' - if tool_tag not in json_object: - continue - - def _strip_trailing_cruft(s: str) -> str: - return s.strip()[1:-1].strip("'").strip('"').strip("'\n").strip('"\n') - - tool = _strip_trailing_cruft(json_object.split(tool_tag)[1].split(",")[0]) - - input_str = None - if input_tag in json_object: - split_on_input_tag = json_object.split(input_tag)[1].split("}") - joined_input_str = "}".join(split_on_input_tag[:-1]) - input_str = joined_input_str.strip()[1:-1] - results.append((tool, input_str)) - return results + def _retrieve_completion_message(processed_inputs: Dict[str, str]) -> Optional[str]: + """Check if the result is a return result indicator.""" + for processed_input in processed_inputs.keys(): + if AutomataAgent.ActionExtractor.return_result_indicator in processed_input: + return processed_inputs[processed_input] + return None @staticmethod - def _parse_input_string(input_str: str) -> List[Dict[str, Optional[str]]]: - """Parse the input string into a list of tool and input pairs.""" - extracted_json_objects = AutomataAgent._extract_json_objects(input_str) - tool_input_pairs = AutomataAgent._extract_tool_and_input(extracted_json_objects) - parsed_entries = [] - for tool_input_pair in tool_input_pairs: - parsed_entries.append({"tool": tool_input_pair[0], "input": tool_input_pair[1]}) - return [{"tool": entry["tool"], "input": entry.get("input")} for entry in parsed_entries] + def _generate_user_observation_message(observations: Dict[str, str]) -> str: + message = f"{AutomataAgent.ActionExtractor.action_indicator} observations\n" + for observation_name in observations.keys(): + message += f" - {observation_name}" + "\n" + message += f" - {observations[observation_name]}" + "\n" + return message + + class ActionExtractor: + """Class for extracting actions from an AutomataAgent string.""" + + action_indicator = "- " + code_indicator = "```" + tool_indicator = "tool_query" + return_result_indicator = "return_result" + expected_coded_languages = ["python"] + + @classmethod + def extract_actions(cls, text: str) -> List[ActionType]: + """ + Extract actions from the given text. - @staticmethod - def is_completion_message(message: str): - """Check if the message is a completion message.""" - match_filter = "result_0" - match_string = '"%s":' % (match_filter) - return match_string in message + Args: + text: A string containing actions formatted as nested lists. + + Returns: + A list of dictionaries containing actions and their inputs. + """ + lines = text.split("\n") + actions: List[ActionType] = [] + action: Optional[ActionType] = None + is_code = False + skip_next = False + for index, line in enumerate(lines): + if skip_next: + skip_next = False + continue + if cls._is_new_tool_action(lines, index): + action = cls._process_new_tool_action(action, line, actions) + skip_next = True + elif cls._is_return_result_action(line): + action = cls._process_new_return_result_action(action, line, actions) + else: + (is_code, skip_next) = cls._process_action_input( + lines, index, line, action, is_code, skip_next + ) + if action is not None: + actions.append(action) + return actions + + @staticmethod + def _is_new_tool_action(lines, index): + """Check if the current line is a new action.""" + return ( + f"{AutomataAgent.ActionExtractor.action_indicator}tool" in lines[index - 1] + and f"{AutomataAgent.ActionExtractor.action_indicator}{AutomataAgent.ActionExtractor.tool_indicator}" + in lines[index - 2] + and (AutomataAgent.ActionExtractor.action_indicator in lines[index]) + and (len(lines) > index + 1) + and (f"{AutomataAgent.ActionExtractor.action_indicator}inputs" in lines[index + 1]) + ) + + @staticmethod + def _process_new_tool_action( + action: Optional[ActionType], line: str, actions: List[ActionType] + ): + """Process a new action.""" + if action is not None and "tool" in action: + actions.append(action) + tool_name = line.split(AutomataAgent.ActionExtractor.action_indicator)[1].strip() + return {"tool": tool_name, "input": []} + + @staticmethod + def _is_return_result_action(line: str) -> bool: + return line.strip().startswith( + f"{AutomataAgent.ActionExtractor.action_indicator}{AutomataAgent.ActionExtractor.return_result_indicator}" + ) + + @staticmethod + def _process_new_return_result_action( + action: Optional[ActionType], line: str, actions: List[ActionType] + ): + """Process a new return result action.""" + if action is not None and "tool" in action: + actions.append(action) + return { + "tool": line.strip() + .split(AutomataAgent.ActionExtractor.action_indicator)[1] + .split(AutomataAgent.ActionExtractor.action_indicator)[0] + .strip(), + "input": [], + } + + @staticmethod + def _process_action_input( + lines: List[str], + index: int, + line: str, + action: Optional[ActionType], + is_code: bool, + skip_next: bool, + ): + """Process an action input.""" + if action is not None: + inputs = cast(List[str], action["input"]) + if AutomataAgent.ActionExtractor._is_code_start(lines, index) and (not is_code): + is_code = True + contains_language_definition = False + for language in AutomataAgent.ActionExtractor.expected_coded_languages: + if language in line: + contains_language_definition = True + if contains_language_definition: + inputs.append("") + else: + inputs.append(line + "\n") + skip_next = True + elif not AutomataAgent.ActionExtractor._is_code_indicator(line) and is_code: + inputs[-1] += line + "\n" + elif AutomataAgent.ActionExtractor._is_code_end(line) and (not is_code): + raise ValueError(f"Invalid action format: {line}") + elif AutomataAgent.ActionExtractor._is_code_end(line) and is_code: + is_code = False + inputs[-1] = textwrap.dedent(action["input"][-1]) + elif AutomataAgent.ActionExtractor.action_indicator in line: + clean_line = line.split(AutomataAgent.ActionExtractor.action_indicator)[ + 1 + ].strip() + inputs.append(clean_line) + return (is_code, skip_next) + + @staticmethod + def _is_code_start(lines: List[str], index: int): + """Check if the current line is the start of a code block.""" + return ( + len(lines) > index + 1 + and AutomataAgent.ActionExtractor.code_indicator in lines[index + 1] + ) + + @staticmethod + def _is_code_end(line: str) -> bool: + """Check if the current line is the end of a code block.""" + return AutomataAgent.ActionExtractor.code_indicator in line + + @staticmethod + def _is_code_indicator(line: str) -> bool: + """Check if the current line is a code indicator.""" + return line.strip() == AutomataAgent.ActionExtractor.code_indicator diff --git a/automata/core/agents/tests/test_automata_agent.py b/automata/core/agents/tests/test_automata_agent.py index e51c6126..26008528 100644 --- a/automata/core/agents/tests/test_automata_agent.py +++ b/automata/core/agents/tests/test_automata_agent.py @@ -1,3 +1,5 @@ +import textwrap + import pytest from automata.configs.agent_configs.config_type import AutomataAgentConfig, AutomataConfigVersion @@ -160,3 +162,203 @@ def test_builder_gets_default_params_from_test_config(): assert agent.max_iters == 100 assert agent.temperature == 0.8 assert agent.session_id == "test-session-id" + + +def test_extract_action(): + input_text = textwrap.dedent( + """ + - thoughts + - I will use the automata-indexer-retrieve-code tool to retrieve the code for the "run" function from the Automata agent. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + """ + ) + + result = AutomataAgent._extract_actions(input_text) + assert result[0]["tool"] == "automata-indexer-retrieve-code" + assert ( + result[0]["input"][0] + == "Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings." + ) + + +def test_extract_actions(): + input_text = textwrap.dedent( + """ + - thoughts + - I will use the automata-indexer-retrieve-code tool to retrieve the code for the "run" function from the Automata agent. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + - tool_query_1 + - tool + - automata-writer-modify-module + - inputs + - Modify the code in the Automata agent. + - A dummy input.... + """ + ) + + result = AutomataAgent._extract_actions(input_text) + assert result[0]["tool"] == "automata-indexer-retrieve-code" + assert ( + result[0]["input"][0] + == "Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings." + ) + + assert result[1]["tool"] == "automata-writer-modify-module" + assert result[1]["input"][0] == "Modify the code in the Automata agent." + + assert result[1]["input"][1] == "A dummy input...." + + +def test_extract_actions_with_code(): + input_text = textwrap.dedent( + """ + - thoughts + - I will use the automata-indexer-retrieve-code tool to retrieve the code for the "run" function from the Automata agent. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + - tool_query_1 + - tool + - automata-writer-modify-module + - inputs + - Modify the code in the Automata agent. + - python + ``` + def f(x: int) -> int: + return 0 + ``` + """ + ) + + result = AutomataAgent._extract_actions(input_text) + assert result[0]["tool"] == "automata-indexer-retrieve-code" + assert ( + result[0]["input"][0] + == "Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings." + ) + + assert result[1]["tool"] == "automata-writer-modify-module" + assert result[1]["input"][0] == "Modify the code in the Automata agent." + + assert result[1]["input"][1] == "def f(x: int) -> int:\n return 0\n" + + +def test_extract_actions_with_return(): + text = textwrap.dedent( + """ + *Assistant* + - thoughts + - Having successfully written the output file, I can now return the result. + - actions + - return_result_0 + - Function 'run' has been added to core.tests.sample_code.test. + """ + ) + + extractor = AutomataAgent.ActionExtractor() + result = extractor.extract_actions(text) + + assert result[0]["tool"] == "return_result_0" + assert result[0]["input"][0] == "Function 'run' has been added to core.tests.sample_code.test." + + +def test_extract_actions_tools_and_with_return(): + text = textwrap.dedent( + """ + *Assistant* + - thoughts + - Having successfully written the output file, I can now return the result. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + + - return_result_0 + - Function 'run' has been added to core.tests.sample_code.test. + """ + ) + + extractor = AutomataAgent.ActionExtractor() + result = extractor.extract_actions(text) + assert result[0]["tool"] == "automata-indexer-retrieve-code" + assert ( + result[0]["input"][0] + == "Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings." + ) + + assert result[1]["tool"] == "return_result_0" + assert result[1]["input"][0] == "Function 'run' has been added to core.tests.sample_code.test." + + +def test_extract_actions_tools_and_with_return_processed(automata_agent): + text = textwrap.dedent( + """ + - thoughts + - Having successfully written the output file, I can now return the result. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + + - return_result_0 + - Function 'run' has been added to core.tests.sample_code.test. + """ + ) + processed_input = automata_agent._generate_observations(text) + assert ( + processed_input["output_0"] + == """Error: Tool 'automata-indexer-retrieve-code' not found.""" + ) + assert ( + processed_input["return_result_0"] + == """Function 'run' has been added to core.tests.sample_code.test.""" + ) + + +def test_iter_task_core_logic(automata_agent): + text = textwrap.dedent( + """ + - thoughts + - Having successfully written the output file, I can now return the result. + - actions + - tool_query_0 + - tool + - automata-indexer-retrieve-code + - inputs + - Retrieve the raw code for the function 'run' from the Automata agent, including all necessary imports and docstrings. + + - return_result_0 + - Function 'run' has been added to core.tests.sample_code.test. + """ + ) + observations = automata_agent._generate_observations(text) + is_return_result = automata_agent._retrieve_completion_message(observations) + + user_observation_message = AutomataAgent._generate_user_observation_message(observations) + assert is_return_result + expected_observations = textwrap.dedent( + """- observations + - output_0 + - Error: Tool 'automata-indexer-retrieve-code' not found. + - return_result_0 + - Function 'run' has been added to core.tests.sample_code.test. + """ + ) + assert user_observation_message.strip() == expected_observations.strip() diff --git a/automata/core/tests/conftest.py b/automata/core/tests/conftest.py index aba2a7c8..be156e73 100644 --- a/automata/core/tests/conftest.py +++ b/automata/core/tests/conftest.py @@ -24,10 +24,10 @@ def automata_params(request): "model": model, "temperature": temperature, "automata_indexer_config": AutomataAgentConfig.load( - AutomataConfigVersion.AUTOMATA_INDEXER_V1 + AutomataConfigVersion.AUTOMATA_INDEXER_PROD ), "automata_writer_config": AutomataAgentConfig.load( - AutomataConfigVersion.AUTOMATA_WRITER_V2 + AutomataConfigVersion.AUTOMATA_WRITER_PROD ), } mock_llm_toolkits = build_llm_toolkits(tool_list, **inputs) @@ -41,7 +41,7 @@ def automata_params(request): def build_agent_with_params( automata_params, instructions: str, - config_version: AutomataConfigVersion = AutomataConfigVersion.AUTOMATA_INDEXER_V2, + config_version: AutomataConfigVersion = AutomataConfigVersion.AUTOMATA_INDEXER_PROD, max_iters=2, temperature=0.0, model="gpt-3.5-turbo", diff --git a/automata/core/tests/test_regression_core_automata_master.py b/automata/core/tests/test_regression_core_automata_master.py index a763e0e8..81c05450 100644 --- a/automata/core/tests/test_regression_core_automata_master.py +++ b/automata/core/tests/test_regression_core_automata_master.py @@ -46,7 +46,7 @@ def test_retrieve_run_and_write_out(automata_params): automata_params, f'1. Retrieve the raw code (code + docstrings) for the function "run" from the automata agent.\n' f"2. NEXT, write the full raw code into the file core.tests.sample_code.test3", - AutomataConfigVersion.AUTOMATA_MASTER_V3, + AutomataConfigVersion.AUTOMATA_MASTER_PROD, max_iters=5, ) diff --git a/automata/core/tests/test_regression_core_automata_retriever.py b/automata/core/tests/test_regression_core_automata_retriever.py index 08ac5a84..1d7141e7 100644 --- a/automata/core/tests/test_regression_core_automata_retriever.py +++ b/automata/core/tests/test_regression_core_automata_retriever.py @@ -1,18 +1,39 @@ import os +import textwrap import pytest -from automata.core.utils import calculate_similarity, clean_agent_result +from automata.core.utils import calculate_similarity from .conftest import build_agent_with_params current_file_dir = os.path.dirname(os.path.realpath(__file__)) -MODEL = "gpt-3.5-turbo" -TEMPERATURE = 0.0 +MODEL = "gpt-4" +TEMPERATURE = 0.7 EXPECTED_RESPONSES = { - "test_retrieve_load_yaml_docs": "Load a YAML file and return", - "test_retrieve_python_writer_docs": "This class provides functionality to", + "test_retrieve_load_yaml_docs": "Loads a YAML file.", + "test_retrieve_python_writer_docs": textwrap.dedent( + """A utility class for working with Python AST nodes. + +Public Methods: + +update_module( + source_code: str, + extending_module: bool, + module_obj (Optional[Module], keyword), + module_path (Optional[str], keyword) +) -> None: + Perform an in-place extention or reduction of a module object according to the received code. + +write_module(self) -> None: + Write the module object to a file. + +Exceptions: + ModuleNotFound: Raised when a module cannot be found. + InvalidArguments: Raised when invalid arguments are passed to a method. +""" + ), } @@ -37,9 +58,9 @@ def test_retrieve_load_yaml_docs(automata_params): temperature=TEMPERATURE, model=MODEL, ) - result = clean_agent_result(agent.run()) + result = agent.run() expected_content = EXPECTED_RESPONSES["test_retrieve_load_yaml_docs"].strip() - assert calculate_similarity(expected_content, result) > 0.9 + assert calculate_similarity(expected_content, result) > 0.8 @pytest.mark.regression @@ -49,7 +70,7 @@ def test_retrieve_load_yaml_docs(automata_params): { "model": MODEL, "temperature": TEMPERATURE, - "tool_list": ["python_writer"], + "tool_list": ["python_indexer", "codebase_oracle"], }, # Add more parameter sets as needed ], @@ -63,6 +84,6 @@ def test_retrieve_python_writer_docs(automata_params): temperature=TEMPERATURE, model=MODEL, ) - result = clean_agent_result(agent.run()) + result = agent.run() expected_content = EXPECTED_RESPONSES["test_retrieve_python_writer_docs"].strip() - assert calculate_similarity(expected_content, result) > 0.9 + assert calculate_similarity(expected_content, result) > 0.8 diff --git a/automata/core/tests/test_regression_core_automata_writer.py b/automata/core/tests/test_regression_core_automata_writer.py index 21cf08d4..13097672 100644 --- a/automata/core/tests/test_regression_core_automata_writer.py +++ b/automata/core/tests/test_regression_core_automata_writer.py @@ -83,7 +83,7 @@ def test_advanced_writer_example(automata_params): agent = build_agent_with_params( automata_params, f"Write the following module - '{expected_content}' to the file core.tests.sample_code.test2", - AutomataConfigVersion.AUTOMATA_WRITER_V2, + AutomataConfigVersion.AUTOMATA_WRITER_PROD, max_iters=2, temperature=TEMPERATURE, model=MODEL, diff --git a/automata/core/utils.py b/automata/core/utils.py index e7ecf687..f252e0fe 100644 --- a/automata/core/utils.py +++ b/automata/core/utils.py @@ -15,7 +15,8 @@ def load_yaml(file_path: str) -> Any: - """Load a YAML file. + """ + Loads a YAML file. Args: file_path (str): The path to the YAML file. @@ -122,11 +123,3 @@ def load(self) -> List[Document]: text += f"{i}: {line}" metadata = {"source": self.file_path} return [Document(page_content=text, metadata=metadata)] - - -def clean_agent_result(result: str) -> str: - """Cleans the result of an agent call.""" - result = result.split('"result_0": ')[1] - result = result.replace("}", "")[1:-1] - result = result.replace("\\n", "\n").strip() - return result diff --git a/automata/scripts/main_automata.py b/automata/scripts/main_automata.py index 8a655127..de9d296c 100644 --- a/automata/scripts/main_automata.py +++ b/automata/scripts/main_automata.py @@ -22,8 +22,8 @@ def main(): parser.add_argument("--instructions", type=str, help="The initial instructions for the agent.") parser.add_argument( "--config_version", - type=AutomataConfigVersion, - default=AutomataConfigVersion.AUTOMATA_MASTER_V3, + type=str, + default=AutomataConfigVersion.AUTOMATA_MASTER_PROD.value, help="The config version of the agent.", ) parser.add_argument( @@ -56,13 +56,13 @@ def main(): parser.add_argument( "--automata_indexer_config_version", type=str, - default=AutomataConfigVersion.AUTOMATA_INDEXER_V2.value, + default=AutomataConfigVersion.AUTOMATA_INDEXER_PROD.value, help="Should the instruction prompt include an overview?", ) parser.add_argument( "--automata_writer_config_version", type=str, - default=AutomataConfigVersion.AUTOMATA_WRITER_V2.value, + default=AutomataConfigVersion.AUTOMATA_WRITER_PROD.value, help="Should the instruction prompt include an overview?", ) @@ -113,7 +113,7 @@ def main(): ) logger.info("-" * 60) - agent_config_version = AutomataConfigVersion(args.config_version) + agent_config_version = AutomataConfigVersion(AutomataConfigVersion(args.config_version)) agent_config = AutomataAgentConfig.load(agent_config_version) agent = ( diff --git a/automata/tool_management/python_indexer_tool_manager.py b/automata/tool_management/python_indexer_tool_manager.py index 54ea92e7..dfa17f4c 100644 --- a/automata/tool_management/python_indexer_tool_manager.py +++ b/automata/tool_management/python_indexer_tool_manager.py @@ -23,7 +23,6 @@ from automata.configs.agent_configs.config_type import AutomataAgentConfig, AutomataConfigVersion from automata.core.agents.automata_agent import AutomataAgentBuilder from automata.core.base.tool import Tool -from automata.core.utils import clean_agent_result from automata.tool_management.base_tool_manager import BaseToolManager from automata.tools.python_tools.python_indexer import PythonIndexer @@ -49,7 +48,7 @@ def __init__(self, **kwargs): """ self.indexer: PythonIndexer = kwargs.get("python_indexer") self.automata_version = ( - kwargs.get("automata_version") or AutomataConfigVersion.AUTOMATA_INDEXER_V2 + kwargs.get("automata_version") or AutomataConfigVersion.AUTOMATA_INDEXER_PROD ) self.model = kwargs.get("model") or "gpt-4" self.temperature = kwargs.get("temperature") or 0.7 @@ -61,17 +60,17 @@ def build_tools(self) -> List[Tool]: tools = [ Tool( name="python-indexer-retrieve-code", - func=lambda module_comma_object_path: self._run_indexer_retrieve_code( - module_comma_object_path + func=lambda module_object_tuple: self._run_indexer_retrieve_code( + *module_object_tuple ), - description=f'Returns the code of the python package, module, standalone function, class, or method at the given python path, without docstrings. "No results found" is returned if no match is found.\n For example - suppose the function "my_function" is defined in the file "my_file.py" located in the main working directory, then the correct tool input is my_file,my_function Suppose instead the file is located in a subdirectory called my_directory, then the correct tool input for the parser is "my_directory.my_file,my_function". If the function is defined in a class, MyClass, then the correct tool input is "my_directory.my_file,MyClass.my_function".', + description=f'Returns the code of the python package, module, standalone function, class, or method at the given python path, without docstrings. "No results found" is returned if no match is found.\n For example - suppose the function "my_function" is defined in the file "my_file.py" located in the main working directory, then the correct tool input is my_file,my_function Suppose instead the file is located in a subdirectory called my_directory, then the correct tool input for the parser is - inputs\n - my_directory.my_file\n - my_function. If the function is defined in a class, MyClass, then the correct tool input is - inputs\n - my_directory.my_file\n - MyClass.my_function', return_direct=True, verbose=True, ), Tool( name="python-indexer-retrieve-docstring", - func=lambda module_comma_object_path: self._run_indexer_retrieve_docstring( - module_comma_object_path + func=lambda module_object_tuple: self._run_indexer_retrieve_docstring( + *module_object_tuple ), description=f"Identical to python-indexer-retrieve-code, except returns the docstring instead of raw code.", return_direct=True, @@ -79,8 +78,8 @@ def build_tools(self) -> List[Tool]: ), Tool( name="python-indexer-retrieve-raw-code", - func=lambda module_comma_object_path: self._run_indexer_retrieve_raw_code( - module_comma_object_path + func=lambda module_object_tuple: self._run_indexer_retrieve_raw_code( + *module_object_tuple ), description=f"Identical to python-indexer-retrieve-code, except returns the raw text (e.g. code + docstrings) of the module.", return_direct=True, @@ -100,46 +99,42 @@ def build_tools_with_automata(self, config: Any) -> List[Tool]: ] return tools - def _run_indexer_retrieve_code(self, input_str: str) -> str: + def _run_indexer_retrieve_code(self, module_path: str, object_path: str) -> str: """PythonIndexer retrieves the code of the python package, module, standalone function, class, or method at the given python path, without docstrings.""" try: - module_path, object_path = self.parse_input_str(input_str) result = self.indexer.retrieve_code(module_path, object_path) return result except Exception as e: return "Failed to retrieve code with error - " + str(e) - def _run_indexer_retrieve_docstring(self, input_str: str) -> str: + def _run_indexer_retrieve_docstring(self, module_path: str, object_path: str) -> str: """PythonIndexer retrieves the docstring of the python package, module, standalone function, class, or method at the given python path, without docstrings.""" try: - module_path, object_path = self.parse_input_str(input_str) result = self.indexer.retrieve_docstring(module_path, object_path) return result except Exception as e: return "Failed to retrieve docstring with error - " + str(e) - def _run_indexer_retrieve_raw_code(self, input_str: str) -> str: + def _run_indexer_retrieve_raw_code(self, module_path: str, object_path: str) -> str: """PythonIndexer retrieves the raw code of the python package, module, standalone function, class, or method at the given python path, with docstrings.""" try: - module_path, object_path = self.parse_input_str(input_str) result = self.indexer.retrieve_raw_code(module_path, object_path) return result except Exception as e: return "Failed to retrieve raw code with error - " + str(e) def _run_automata_indexer_retrieve_code( - self, path_str: str, automata_config: AutomataAgentConfig + self, input_str: str, automata_config: AutomataAgentConfig ) -> str: """Automata retrieves the code of the python package, module, standalone function, class, or method at the given python path, without docstrings.""" from automata.tool_management.tool_management_utils import build_llm_toolkits try: initial_payload = {"overview": self.indexer.get_overview()} - instructions = f"Retrieve the code for {path_str}" agent = ( AutomataAgentBuilder(automata_config) .with_initial_payload(initial_payload) - .with_instructions(instructions) + .with_instructions(input_str) .with_llm_toolkits(build_llm_toolkits(["python_indexer"])) .with_model(self.model) .with_stream(self.stream) @@ -148,7 +143,6 @@ def _run_automata_indexer_retrieve_code( .build() ) result = agent.run() - result = clean_agent_result(result) return result except Exception as e: return "Failed to retrieve the code with error - " + str(e) diff --git a/automata/tool_management/python_writer_tool_manager.py b/automata/tool_management/python_writer_tool_manager.py index 2f157628..ff0a963c 100644 --- a/automata/tool_management/python_writer_tool_manager.py +++ b/automata/tool_management/python_writer_tool_manager.py @@ -14,7 +14,7 @@ tools = build_tools(tool_manager) """ import logging -from typing import Any, List +from typing import Any, List, Optional from automata.configs.agent_configs.config_type import AutomataConfigVersion from automata.core.agents.automata_agent import AutomataAgentBuilder, AutomataAgentConfig @@ -48,7 +48,7 @@ def __init__( """ self.writer: PythonWriter = kwargs.get("python_writer") self.automata_version = ( - kwargs.get("automata_version") or AutomataConfigVersion.AUTOMATA_WRITER_V2 + kwargs.get("automata_version") or AutomataConfigVersion.AUTOMATA_WRITER_PROD ) self.model = kwargs.get("model") or "gpt-4" self.verbose = kwargs.get("verbose") or False @@ -60,7 +60,9 @@ def build_tools(self) -> List[Tool]: tools = [ Tool( name="python-writer-update-module", - func=lambda path_comma_code_str: self._writer_update_module(path_comma_code_str), + func=lambda module_object_code_tuple: self._writer_update_module( + *module_object_code_tuple + ), description=f"Modifies the python code of a function, class, method, or module after receiving" f" an input module path, source code, and optional class name. If the specified object or dependencies do not exist," f" then they are created automatically. If the object already exists," @@ -68,9 +70,14 @@ def build_tools(self) -> List[Tool]: f" For example -" f' to implement a method "my_method" of "MyClass" in the module "my_file.py" which exists in "my_folder",' f" the correct function call is" - f' {{"tool": "python-writer-update-module",' - f' "input": "my_folder.my_file,MyClass,def my_function() -> None:\n """My Function"""\n print("hello world")"}}.' - f" If new import statements are necessary, then introduce them to the module separately. Do not forget to wrap your input in double quotes.", + f" - tool_query_1" + f" - tool" + f" - python-writer-update-module" + f" - inputs" + f" - my_folder.my_file" + f" - MyClass" + f' - def my_method() -> None:\n """My Method"""\n print("hello world")' + f" If new import statements are necessary, then introduce them at the top of the submitted input code.", return_direct=True, ), ] @@ -81,20 +88,15 @@ def build_tools_with_automata(self, config: Any) -> List[Tool]: tools = [ Tool( name="automata-writer-modify-module", - func=lambda path_comma_code_str: self._automata_update_module( - path_comma_code_str, config - ), + func=lambda input_str: self._automata_update_module(input_str, config), description=f"Modifies the python code of a function, class, method, or module after receiving" f" an input module path, source code, and optional class name. The actual work is carried out by an autonomous agent called Automata.", ), ] return tools - def _writer_update_module(self, input_str: str) -> str: + def _writer_update_module(self, module_path: str, class_name: Optional[str], code: str) -> str: """Writes the given code to the given module path and class name.""" - module_path = input_str.split(",")[0] - class_name = input_str.split(",")[1] - code = ",".join(input_str.split(",")[2:]).strip() try: self.writer.update_module( source_code=code, diff --git a/automata/tool_management/tests/test_python_indexer_tool_manager.py b/automata/tool_management/tests/test_python_indexer_tool_manager.py index 88a38955..a4bd5760 100644 --- a/automata/tool_management/tests/test_python_indexer_tool_manager.py +++ b/automata/tool_management/tests/test_python_indexer_tool_manager.py @@ -34,5 +34,5 @@ def test_tool_execution(python_indexer_tool_builder): ) tools = python_indexer_tool_builder.build_tools() - assert tools[0].func("module.path,func") == "Sample code" - assert tools[1].func("module.path,func") == "Sample docstring" + assert tools[0].func(("module.path", "func")) == "Sample code" + assert tools[1].func(("module.path", "func")) == "Sample docstring" diff --git a/automata/tool_management/tests/test_python_writer_tool_manager.py b/automata/tool_management/tests/test_python_writer_tool_manager.py index 4fafe42e..f2d18afe 100644 --- a/automata/tool_management/tests/test_python_writer_tool_manager.py +++ b/automata/tool_management/tests/test_python_writer_tool_manager.py @@ -47,7 +47,7 @@ def test_bootstrap_module_with_new_function(python_writer_tool_builder): file_py_path = f"{package}.{module}" file_abs_path = os.path.join(absolute_path, package, f"{module}.py") - code_writer.func(f"{file_py_path},,{function_def}") + code_writer.func((file_py_path, None, function_def)) new_sample_text = None with open(file_abs_path, "r", encoding="utf-8") as f: @@ -74,7 +74,7 @@ def test_extend_module_with_new_function(python_writer_tool_builder): file_py_path = f"{package}.{module}" file_rel_path = os.path.join(package, f"{module}.py") file_abs_path = os.path.join(absolute_path, file_rel_path) - code_writer.func(f"{file_py_path},,{function_def}") + code_writer.func((file_py_path, None, function_def)) new_sample_text = None with open(file_abs_path, "r", encoding="utf-8") as f: @@ -104,7 +104,7 @@ def test_extend_module_with_documented_new_function(python_writer_tool_builder): file_rel_path = os.path.join(package, f"{module}.py") file_abs_path = os.path.join(absolute_path, file_rel_path) - code_writer.func(f"{file_py_path},,{function_def}") + code_writer.func((file_py_path, None, function_def)) new_sample_text = None with open(file_abs_path, "r", encoding="utf-8") as f: @@ -175,7 +175,7 @@ def python_agent_python_task(): file_py_path = f"{package}.{module}" file_rel_path = os.path.join(package, f"{module}.py") file_abs_path = os.path.join(absolute_path, file_rel_path) - code_writer.func(f"{file_py_path},PythonAgentToolBuilder,{class_str}") + code_writer.func((file_py_path, "PythonAgentToolBuilder", class_str)) new_sample_text = None with open(file_abs_path, "r", encoding="utf-8") as f: new_sample_text = f.read() @@ -191,8 +191,8 @@ def python_agent_python_task(): def test_extend_module_with_documented_new_module(python_writer_tool_builder): - combo_str = textwrap.dedent( - """temp_code.python_agent_tool_builder,,from typing import List, Optional + module_str = textwrap.dedent( + """from typing import List, Optional from automata.buffer import PassThroughBuffer from automata.tools.tool import Tool from automata.tools.python_tools.python_agent import PythonAgent @@ -208,6 +208,6 @@ def build_tools(self) -> List[Tool]: ) tools = python_writer_tool_builder.build_tools() code_writer = tools[0] - code_writer.func(combo_str) + code_writer.func(("temp_code.python_agent_tool_builder", None, module_str)) # # Why? shutil.rmtree(os.path.join(root_py_path(), "tool_management", "tests", "temp_code")) diff --git a/pyproject.toml b/pyproject.toml index f701136c..144bda3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,9 +2,9 @@ requires = ["setuptools", "wheel"] [tool.poetry] -name = "improved_spork" +name = "agentic_automata" version = "0.1.0" -description = "A sentient automata." +description = "An agentic automata." authors = ["maks@sporker.com"] [tool.poetry.dependencies] diff --git a/setup.py b/setup.py index f3bc15ce..1fc6d9de 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ def read_requirements(): setup( - name="improved_spork", + name="automata", version="0.1.0", packages=find_packages(), install_requires=read_requirements(),