From b19eb74874a91b0c8e372ffb37d34e833de07cad Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:09:59 -0700 Subject: [PATCH 01/55] Refactor the seed prompt to be generated programmatically This removes the tedium of having to re-number every numbered item in the prompt.txt if you want to add/remove commands. --- scripts/ai_config.py | 3 +- scripts/data.py | 18 ---------- scripts/data/prompt.txt | 63 --------------------------------- scripts/main.py | 3 +- scripts/prompt.py | 51 +++++++++++++++++++++++++++ scripts/promptgenerator.py | 71 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 126 insertions(+), 83 deletions(-) delete mode 100644 scripts/data.py delete mode 100644 scripts/data/prompt.txt create mode 100644 scripts/prompt.py create mode 100644 scripts/promptgenerator.py diff --git a/scripts/ai_config.py b/scripts/ai_config.py index 1d5832c1..332c7f06 100644 --- a/scripts/ai_config.py +++ b/scripts/ai_config.py @@ -1,6 +1,7 @@ import yaml import data import os +from prompt import get_prompt class AIConfig: """ @@ -90,6 +91,6 @@ class AIConfig: for i, goal in enumerate(self.ai_goals): full_prompt += f"{i+1}. {goal}\n" - full_prompt += f"\n\n{data.load_prompt()}" + full_prompt += f"\n\n{get_prompt()}" return full_prompt diff --git a/scripts/data.py b/scripts/data.py deleted file mode 100644 index f80c2875..00000000 --- a/scripts/data.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -from pathlib import Path - -def load_prompt(): - """Load the prompt from data/prompt.txt""" - try: - # get directory of this file: - file_dir = Path(__file__).parent - prompt_file_path = file_dir / "data" / "prompt.txt" - - # Load the prompt from data/prompt.txt - with open(prompt_file_path, "r") as prompt_file: - prompt = prompt_file.read() - - return prompt - except FileNotFoundError: - print("Error: Prompt file not found", flush=True) - return "" diff --git a/scripts/data/prompt.txt b/scripts/data/prompt.txt deleted file mode 100644 index fc68f3ae..00000000 --- a/scripts/data/prompt.txt +++ /dev/null @@ -1,63 +0,0 @@ -CONSTRAINTS: - -1. ~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files. -2. If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember. -3. No user assistance -4. Exclusively use the commands listed in double quotes e.g. "command name" - -COMMANDS: - -1. Google Search: "google", args: "input": "" -5. Browse Website: "browse_website", args: "url": "", "question": "" -6. Start GPT Agent: "start_agent", args: "name": "", "task": "", "prompt": "" -7. Message GPT Agent: "message_agent", args: "key": "", "message": "" -8. List GPT Agents: "list_agents", args: "" -9. Delete GPT Agent: "delete_agent", args: "key": "" -10. Write to file: "write_to_file", args: "file": "", "text": "" -11. Read file: "read_file", args: "file": "" -12. Append to file: "append_to_file", args: "file": "", "text": "" -13. Delete file: "delete_file", args: "file": "" -14. Search Files: "search_files", args: "directory": "" -15. Evaluate Code: "evaluate_code", args: "code": "" -16. Get Improved Code: "improve_code", args: "suggestions": "", "code": "" -17. Write Tests: "write_tests", args: "code": "", "focus": "" -18. Execute Python File: "execute_python_file", args: "file": "" -19. Task Complete (Shutdown): "task_complete", args: "reason": "" -20. Generate Image: "generate_image", args: "prompt": "" -21. Do Nothing: "do_nothing", args: "" - -RESOURCES: - -1. Internet access for searches and information gathering. -2. Long Term memory management. -3. GPT-3.5 powered Agents for delegation of simple tasks. -4. File output. - -PERFORMANCE EVALUATION: - -1. Continuously review and analyze your actions to ensure you are performing to the best of your abilities. -2. Constructively self-criticize your big-picture behavior constantly. -3. Reflect on past decisions and strategies to refine your approach. -4. Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps. - -You should only respond in JSON format as described below - -RESPONSE FORMAT: -{ - "thoughts": - { - "text": "thought", - "reasoning": "reasoning", - "plan": "- short bulleted\n- list that conveys\n- long-term plan", - "criticism": "constructive self-criticism", - "speak": "thoughts summary to say to user" - }, - "command": { - "name": "command name", - "args":{ - "arg name": "value" - } - } -} - -Ensure the response can be parsed by Python json.loads diff --git a/scripts/main.py b/scripts/main.py index 4be0b2aa..a3d4f9df 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -18,6 +18,7 @@ import traceback import yaml import argparse import logging +from prompt import get_prompt cfg = Config() @@ -171,7 +172,7 @@ def load_variables(config_file="config.yaml"): with open(config_file, "w") as file: documents = yaml.dump(config, file) - prompt = data.load_prompt() + prompt = get_prompt() prompt_start = """Your decisions must always be made independently without seeking user assistance. Play to your strengths as an LLM and pursue simple strategies with no legal complications.""" # Construct full prompt diff --git a/scripts/prompt.py b/scripts/prompt.py new file mode 100644 index 00000000..fd2a84a0 --- /dev/null +++ b/scripts/prompt.py @@ -0,0 +1,51 @@ +from promptgenerator import PromptGenerator + +def get_prompt(): + prompt_generator = PromptGenerator() + + # Add constraints + prompt_generator.add_constraint("~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.") + prompt_generator.add_constraint("If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.") + prompt_generator.add_constraint("No user assistance") + prompt_generator.add_constraint('Exclusively use the commands listed in double quotes e.g. "command name"') + + # Add commands + commands = [ + ("Google Search", "google", {"input": ""}), + ("Browse Website", "browse_website", {"url": "", "question": ""}), + ("Start GPT Agent", "start_agent", {"name": "", "task": "", "prompt": ""}), + ("Message GPT Agent", "message_agent", {"key": "", "message": ""}), + ("List GPT Agents", "list_agents", {}), + ("Delete GPT Agent", "delete_agent", {"key": ""}), + ("Write to file", "write_to_file", {"file": "", "text": ""}), + ("Read file", "read_file", {"file": ""}), + ("Append to file", "append_to_file", {"file": "", "text": ""}), + ("Delete file", "delete_file", {"file": ""}), + ("Search Files", "search_files", {"directory": ""}), + ("Evaluate Code", "evaluate_code", {"code": ""}), + ("Get Improved Code", "improve_code", {"suggestions": "", "code": ""}), + ("Write Tests", "write_tests", {"code": "", "focus": ""}), + ("Execute Python File", "execute_python_file", {"file": ""}), + ("Task Complete (Shutdown)", "task_complete", {"reason": ""}), + ("Generate Image", "generate_image", {"prompt": ""}), + ("Do Nothing", "do_nothing", {}), + ] + + for command_label, command_name, args in commands: + prompt_generator.add_command(command_label, command_name, args) + + # Add resources + prompt_generator.add_resource("Internet access for searches and information gathering.") + prompt_generator.add_resource("Long Term memory management.") + prompt_generator.add_resource("GPT-3.5 powered Agents for delegation of simple tasks.") + prompt_generator.add_resource("File output.") + + # Add performance evaluation + prompt_generator.add_performance_evaluation("Continuously review and analyze your actions to ensure you are performing to the best of your abilities.") + prompt_generator.add_performance_evaluation("Constructively self-criticize your big-picture behavior constantly.") + prompt_generator.add_performance_evaluation("Reflect on past decisions and strategies to refine your approach.") + prompt_generator.add_performance_evaluation("Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.") + + # Generate prompt string + prompt_string = prompt_generator.generate_prompt_string() + return prompt_string diff --git a/scripts/promptgenerator.py b/scripts/promptgenerator.py new file mode 100644 index 00000000..1ae43aa7 --- /dev/null +++ b/scripts/promptgenerator.py @@ -0,0 +1,71 @@ +import json + + +class PromptGenerator: + def __init__(self): + self.constraints = [] + self.commands = [] + self.resources = [] + self.performance_evaluation = [] + self.response_format = { + "thoughts": { + "text": "thought", + "reasoning": "reasoning", + "plan": "- short bulleted\n- list that conveys\n- long-term plan", + "criticism": "constructive self-criticism", + "speak": "thoughts summary to say to user" + }, + "command": { + "name": "command name", + "args": { + "arg name": "value" + } + } + } + + def add_constraint(self, constraint): + self.constraints.append(constraint) + + # {CommandLabel}: "{CommandName}", args: "{arg#Name}": "{arg#Prompt}" + def add_command(self, command_label, command_name, args=None): + if args is None: + args = {} + + command_args = {arg_key: arg_value for arg_key, arg_value in args.items()} + + command = { + "label": command_label, + "name": command_name, + "args": command_args, + } + + self.commands.append(command) + + def _generate_command_string(self, command): + args_string = ', '.join(f'"{key}": "{value}"' for key, value in command['args'].items()) + return f'{command["label"]}: "{command["name"]}", args: {args_string}' + + def add_resource(self, resource): + self.resources.append(resource) + + def add_performance_evaluation(self, evaluation): + self.performance_evaluation.append(evaluation) + + + def _generate_numbered_list(self, items, item_type='list'): + if item_type == 'command': + return "\n".join(f"{i+1}. {self._generate_command_string(item)}" for i, item in enumerate(items)) + else: + return "\n".join(f"{i+1}. {item}" for i, item in enumerate(items)) + + def generate_prompt_string(self): + formatted_response_format = json.dumps(self.response_format, indent=4) + prompt_string = ( + f"Constraints:\n{self._generate_numbered_list(self.constraints)}\n\n" + f"Commands:\n{self._generate_numbered_list(self.commands, item_type='command')}\n\n" + f"Resources:\n{self._generate_numbered_list(self.resources)}\n\n" + f"Performance Evaluation:\n{self._generate_numbered_list(self.performance_evaluation)}\n\n" + f"You should only respond in JSON format as described below \nResponse Format: \n{formatted_response_format} \nEnsure the response can be parsed by Python json.loads" + ) + + return prompt_string From fd1cfd2eff6bcb46af6e7728fa57dc980dde0e61 Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:15:45 -0700 Subject: [PATCH 02/55] Add docs and format code --- scripts/prompt.py | 69 +++++++++++++++++++++++++------------ scripts/promptgenerator.py | 70 ++++++++++++++++++++++++++++++++++---- 2 files changed, 112 insertions(+), 27 deletions(-) diff --git a/scripts/prompt.py b/scripts/prompt.py index fd2a84a0..e499a5f6 100644 --- a/scripts/prompt.py +++ b/scripts/prompt.py @@ -1,51 +1,78 @@ from promptgenerator import PromptGenerator + def get_prompt(): + """ + This function generates a prompt string that includes various constraints, commands, resources, and performance evaluations. + + Returns: + str: The generated prompt string. + """ + + # Initialize the PromptGenerator object prompt_generator = PromptGenerator() - # Add constraints - prompt_generator.add_constraint("~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.") - prompt_generator.add_constraint("If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.") + # Add constraints to the PromptGenerator object + prompt_generator.add_constraint( + "~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.") + prompt_generator.add_constraint( + "If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.") prompt_generator.add_constraint("No user assistance") - prompt_generator.add_constraint('Exclusively use the commands listed in double quotes e.g. "command name"') + prompt_generator.add_constraint( + 'Exclusively use the commands listed in double quotes e.g. "command name"') - # Add commands + # Define the command list commands = [ ("Google Search", "google", {"input": ""}), - ("Browse Website", "browse_website", {"url": "", "question": ""}), - ("Start GPT Agent", "start_agent", {"name": "", "task": "", "prompt": ""}), - ("Message GPT Agent", "message_agent", {"key": "", "message": ""}), + ("Browse Website", "browse_website", { + "url": "", "question": ""}), + ("Start GPT Agent", "start_agent", { + "name": "", "task": "", "prompt": ""}), + ("Message GPT Agent", "message_agent", { + "key": "", "message": ""}), ("List GPT Agents", "list_agents", {}), ("Delete GPT Agent", "delete_agent", {"key": ""}), - ("Write to file", "write_to_file", {"file": "", "text": ""}), + ("Write to file", "write_to_file", { + "file": "", "text": ""}), ("Read file", "read_file", {"file": ""}), - ("Append to file", "append_to_file", {"file": "", "text": ""}), + ("Append to file", "append_to_file", { + "file": "", "text": ""}), ("Delete file", "delete_file", {"file": ""}), ("Search Files", "search_files", {"directory": ""}), ("Evaluate Code", "evaluate_code", {"code": ""}), - ("Get Improved Code", "improve_code", {"suggestions": "", "code": ""}), - ("Write Tests", "write_tests", {"code": "", "focus": ""}), + ("Get Improved Code", "improve_code", { + "suggestions": "", "code": ""}), + ("Write Tests", "write_tests", { + "code": "", "focus": ""}), ("Execute Python File", "execute_python_file", {"file": ""}), ("Task Complete (Shutdown)", "task_complete", {"reason": ""}), ("Generate Image", "generate_image", {"prompt": ""}), ("Do Nothing", "do_nothing", {}), ] + # Add commands to the PromptGenerator object for command_label, command_name, args in commands: prompt_generator.add_command(command_label, command_name, args) - # Add resources - prompt_generator.add_resource("Internet access for searches and information gathering.") + # Add resources to the PromptGenerator object + prompt_generator.add_resource( + "Internet access for searches and information gathering.") prompt_generator.add_resource("Long Term memory management.") - prompt_generator.add_resource("GPT-3.5 powered Agents for delegation of simple tasks.") + prompt_generator.add_resource( + "GPT-3.5 powered Agents for delegation of simple tasks.") prompt_generator.add_resource("File output.") - # Add performance evaluation - prompt_generator.add_performance_evaluation("Continuously review and analyze your actions to ensure you are performing to the best of your abilities.") - prompt_generator.add_performance_evaluation("Constructively self-criticize your big-picture behavior constantly.") - prompt_generator.add_performance_evaluation("Reflect on past decisions and strategies to refine your approach.") - prompt_generator.add_performance_evaluation("Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.") + # Add performance evaluations to the PromptGenerator object + prompt_generator.add_performance_evaluation( + "Continuously review and analyze your actions to ensure you are performing to the best of your abilities.") + prompt_generator.add_performance_evaluation( + "Constructively self-criticize your big-picture behavior constantly.") + prompt_generator.add_performance_evaluation( + "Reflect on past decisions and strategies to refine your approach.") + prompt_generator.add_performance_evaluation( + "Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.") - # Generate prompt string + # Generate the prompt string prompt_string = prompt_generator.generate_prompt_string() + return prompt_string diff --git a/scripts/promptgenerator.py b/scripts/promptgenerator.py index 1ae43aa7..6cfd9bcd 100644 --- a/scripts/promptgenerator.py +++ b/scripts/promptgenerator.py @@ -2,7 +2,14 @@ import json class PromptGenerator: + """ + A class for generating custom prompt strings based on constraints, commands, resources, and performance evaluations. + """ + def __init__(self): + """ + Initialize the PromptGenerator object with empty lists of constraints, commands, resources, and performance evaluations. + """ self.constraints = [] self.commands = [] self.resources = [] @@ -24,14 +31,28 @@ class PromptGenerator: } def add_constraint(self, constraint): + """ + Add a constraint to the constraints list. + + Args: + constraint (str): The constraint to be added. + """ self.constraints.append(constraint) - # {CommandLabel}: "{CommandName}", args: "{arg#Name}": "{arg#Prompt}" def add_command(self, command_label, command_name, args=None): + """ + Add a command to the commands list with a label, name, and optional arguments. + + Args: + command_label (str): The label of the command. + command_name (str): The name of the command. + args (dict, optional): A dictionary containing argument names and their values. Defaults to None. + """ if args is None: args = {} - - command_args = {arg_key: arg_value for arg_key, arg_value in args.items()} + + command_args = {arg_key: arg_value for arg_key, + arg_value in args.items()} command = { "label": command_label, @@ -42,23 +63,60 @@ class PromptGenerator: self.commands.append(command) def _generate_command_string(self, command): - args_string = ', '.join(f'"{key}": "{value}"' for key, value in command['args'].items()) + """ + Generate a formatted string representation of a command. + + Args: + command (dict): A dictionary containing command information. + + Returns: + str: The formatted command string. + """ + args_string = ', '.join( + f'"{key}": "{value}"' for key, value in command['args'].items()) return f'{command["label"]}: "{command["name"]}", args: {args_string}' - + def add_resource(self, resource): + """ + Add a resource to the resources list. + + Args: + resource (str): The resource to be added. + """ self.resources.append(resource) def add_performance_evaluation(self, evaluation): + """ + Add a performance evaluation item to the performance_evaluation list. + + Args: + evaluation (str): The evaluation item to be added. + """ self.performance_evaluation.append(evaluation) - def _generate_numbered_list(self, items, item_type='list'): + """ + Generate a numbered list from given items based on the item_type. + + Args: + items (list): A list of items to be numbered. + item_type (str, optional): The type of items in the list. Defaults to 'list'. + + Returns: + str: The formatted numbered list. + """ if item_type == 'command': return "\n".join(f"{i+1}. {self._generate_command_string(item)}" for i, item in enumerate(items)) else: return "\n".join(f"{i+1}. {item}" for i, item in enumerate(items)) def generate_prompt_string(self): + """ + Generate a prompt string based on the constraints, commands, resources, and performance evaluations. + + Returns: + str: The generated prompt string. + """ formatted_response_format = json.dumps(self.response_format, indent=4) prompt_string = ( f"Constraints:\n{self._generate_numbered_list(self.constraints)}\n\n" From 72d4783a1d0e399972e16bdbcc2ac93e2c8b0f1d Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:21:20 -0700 Subject: [PATCH 03/55] formatting --- scripts/prompt.py | 53 ++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/scripts/prompt.py b/scripts/prompt.py index e499a5f6..bbdfa5ec 100644 --- a/scripts/prompt.py +++ b/scripts/prompt.py @@ -1,10 +1,9 @@ from promptgenerator import PromptGenerator - def get_prompt(): """ This function generates a prompt string that includes various constraints, commands, resources, and performance evaluations. - + Returns: str: The generated prompt string. """ @@ -13,37 +12,27 @@ def get_prompt(): prompt_generator = PromptGenerator() # Add constraints to the PromptGenerator object - prompt_generator.add_constraint( - "~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.") - prompt_generator.add_constraint( - "If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.") + prompt_generator.add_constraint("~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.") + prompt_generator.add_constraint("If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.") prompt_generator.add_constraint("No user assistance") - prompt_generator.add_constraint( - 'Exclusively use the commands listed in double quotes e.g. "command name"') + prompt_generator.add_constraint('Exclusively use the commands listed in double quotes e.g. "command name"') # Define the command list commands = [ ("Google Search", "google", {"input": ""}), - ("Browse Website", "browse_website", { - "url": "", "question": ""}), - ("Start GPT Agent", "start_agent", { - "name": "", "task": "", "prompt": ""}), - ("Message GPT Agent", "message_agent", { - "key": "", "message": ""}), + ("Browse Website", "browse_website", {"url": "", "question": ""}), + ("Start GPT Agent", "start_agent", {"name": "", "task": "", "prompt": ""}), + ("Message GPT Agent", "message_agent", {"key": "", "message": ""}), ("List GPT Agents", "list_agents", {}), ("Delete GPT Agent", "delete_agent", {"key": ""}), - ("Write to file", "write_to_file", { - "file": "", "text": ""}), + ("Write to file", "write_to_file", {"file": "", "text": ""}), ("Read file", "read_file", {"file": ""}), - ("Append to file", "append_to_file", { - "file": "", "text": ""}), + ("Append to file", "append_to_file", {"file": "", "text": ""}), ("Delete file", "delete_file", {"file": ""}), ("Search Files", "search_files", {"directory": ""}), ("Evaluate Code", "evaluate_code", {"code": ""}), - ("Get Improved Code", "improve_code", { - "suggestions": "", "code": ""}), - ("Write Tests", "write_tests", { - "code": "", "focus": ""}), + ("Get Improved Code", "improve_code", {"suggestions": "", "code": ""}), + ("Write Tests", "write_tests", {"code": "", "focus": ""}), ("Execute Python File", "execute_python_file", {"file": ""}), ("Task Complete (Shutdown)", "task_complete", {"reason": ""}), ("Generate Image", "generate_image", {"prompt": ""}), @@ -55,24 +44,18 @@ def get_prompt(): prompt_generator.add_command(command_label, command_name, args) # Add resources to the PromptGenerator object - prompt_generator.add_resource( - "Internet access for searches and information gathering.") + prompt_generator.add_resource("Internet access for searches and information gathering.") prompt_generator.add_resource("Long Term memory management.") - prompt_generator.add_resource( - "GPT-3.5 powered Agents for delegation of simple tasks.") + prompt_generator.add_resource("GPT-3.5 powered Agents for delegation of simple tasks.") prompt_generator.add_resource("File output.") # Add performance evaluations to the PromptGenerator object - prompt_generator.add_performance_evaluation( - "Continuously review and analyze your actions to ensure you are performing to the best of your abilities.") - prompt_generator.add_performance_evaluation( - "Constructively self-criticize your big-picture behavior constantly.") - prompt_generator.add_performance_evaluation( - "Reflect on past decisions and strategies to refine your approach.") - prompt_generator.add_performance_evaluation( - "Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.") + prompt_generator.add_performance_evaluation("Continuously review and analyze your actions to ensure you are performing to the best of your abilities.") + prompt_generator.add_performance_evaluation("Constructively self-criticize your big-picture behavior constantly.") + prompt_generator.add_performance_evaluation("Reflect on past decisions and strategies to refine your approach.") + prompt_generator.add_performance_evaluation("Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.") # Generate the prompt string prompt_string = prompt_generator.generate_prompt_string() - + return prompt_string From 8bbfdeb04a5b98070bf0b44c9dc819c66159f05f Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:43:37 -0700 Subject: [PATCH 04/55] Add unit tests for prompt generator class --- tests/promptgenerator_tests.py | 99 ++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 tests/promptgenerator_tests.py diff --git a/tests/promptgenerator_tests.py b/tests/promptgenerator_tests.py new file mode 100644 index 00000000..ac5c3a79 --- /dev/null +++ b/tests/promptgenerator_tests.py @@ -0,0 +1,99 @@ +# Import the required libraries for unit testing +import unittest +import sys +import os + +# Add the path to the "scripts" directory to import the PromptGenerator module +sys.path.append(os.path.abspath("../scripts")) +from promptgenerator import PromptGenerator + +# Create a test class for the PromptGenerator, subclassed from unittest.TestCase +class promptgenerator_tests(unittest.TestCase): + + # Set up the initial state for each test method by creating an instance of PromptGenerator + def setUp(self): + self.generator = PromptGenerator() + + # Test whether the add_constraint() method adds a constraint to the generator's constraints list + def test_add_constraint(self): + constraint = "Constraint1" + self.generator.add_constraint(constraint) + self.assertIn(constraint, self.generator.constraints) + + # Test whether the add_command() method adds a command to the generator's commands list + def test_add_command(self): + command_label = "Command Label" + command_name = "command_name" + args = {"arg1": "value1", "arg2": "value2"} + self.generator.add_command(command_label, command_name, args) + command = { + "label": command_label, + "name": command_name, + "args": args, + } + self.assertIn(command, self.generator.commands) + + # Test whether the add_resource() method adds a resource to the generator's resources list + def test_add_resource(self): + resource = "Resource1" + self.generator.add_resource(resource) + self.assertIn(resource, self.generator.resources) + + # Test whether the add_performance_evaluation() method adds an evaluation to the generator's performance_evaluation list + def test_add_performance_evaluation(self): + evaluation = "Evaluation1" + self.generator.add_performance_evaluation(evaluation) + self.assertIn(evaluation, self.generator.performance_evaluation) + + # Test whether the generate_prompt_string() method generates a prompt string with all the added constraints, commands, resources and evaluations + def test_generate_prompt_string(self): + constraints = ["Constraint1", "Constraint2"] + commands = [ + { + "label": "Command1", + "name": "command_name1", + "args": {"arg1": "value1"}, + }, + { + "label": "Command2", + "name": "command_name2", + "args": {}, + }, + ] + resources = ["Resource1", "Resource2"] + evaluations = ["Evaluation1", "Evaluation2"] + + # Add all the constraints, commands, resources, and evaluations to the generator + for constraint in constraints: + self.generator.add_constraint(constraint) + for command in commands: + self.generator.add_command( + command["label"], command["name"], command["args"]) + for resource in resources: + self.generator.add_resource(resource) + for evaluation in evaluations: + self.generator.add_performance_evaluation(evaluation) + + # Generate the prompt string and verify its correctness + prompt_string = self.generator.generate_prompt_string() + self.assertIsNotNone(prompt_string) + for constraint in constraints: + self.assertIn(constraint, prompt_string) + for command in commands: + self.assertIn(command["name"], prompt_string) + + # Check for each key-value pair in the command args dictionary + for key, value in command["args"].items(): + self.assertIn(f'"{key}": "{value}"', prompt_string) + for resource in resources: + self.assertIn(resource, prompt_string) + for evaluation in evaluations: + self.assertIn(evaluation, prompt_string) + self.assertIn("constraints", prompt_string.lower()) + self.assertIn("commands", prompt_string.lower()) + self.assertIn("resources", prompt_string.lower()) + self.assertIn("performance evaluation", prompt_string.lower()) + +# Run the tests when this script is executed +if __name__ == '__main__': + unittest.main() From de2281d824c13c1eadc3807d2437c58209ab2184 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 11 Apr 2023 17:30:15 +0100 Subject: [PATCH 05/55] add docker compose scheduling --- docker-compose.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..af086f05 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +# To boot the app run the following: +# docker-compose run auto-gpt +version: "3.9" + +services: + auto-gpt: + depends_on: + - redis + build: ./ + volumes: + - "./scripts:/app" + - ".env:/app/.env" + profiles: ["exclude-from-up"] + + redis: + image: "redis/redis-stack-server:latest" From 7a0c9e8a9d13ef5930b56ee13e885c3b69deb293 Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Tue, 11 Apr 2023 10:30:53 -0700 Subject: [PATCH 06/55] fix attempts to import a non-existent module --- scripts/ai_config.py | 1 - scripts/main.py | 1 - 2 files changed, 2 deletions(-) diff --git a/scripts/ai_config.py b/scripts/ai_config.py index 9aa01332..36e8be3c 100644 --- a/scripts/ai_config.py +++ b/scripts/ai_config.py @@ -1,5 +1,4 @@ import yaml -import data import os from prompt import get_prompt diff --git a/scripts/main.py b/scripts/main.py index 0946f21f..b51d486a 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -3,7 +3,6 @@ import random import commands as cmd import utils from memory import get_memory -import data import chat from colorama import Fore, Style from spinner import Spinner From afc7fa6e26efbb781644ceea99004b5c3de55f40 Mon Sep 17 00:00:00 2001 From: Robin Richtsfeld Date: Wed, 12 Apr 2023 03:09:08 +0200 Subject: [PATCH 07/55] Fix JSON formatting in prompt.txt --- scripts/data/prompt.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/data/prompt.txt b/scripts/data/prompt.txt index fc68f3ae..50e9d3fe 100644 --- a/scripts/data/prompt.txt +++ b/scripts/data/prompt.txt @@ -44,8 +44,7 @@ You should only respond in JSON format as described below RESPONSE FORMAT: { - "thoughts": - { + "thoughts": { "text": "thought", "reasoning": "reasoning", "plan": "- short bulleted\n- list that conveys\n- long-term plan", @@ -54,7 +53,7 @@ RESPONSE FORMAT: }, "command": { "name": "command name", - "args":{ + "args": { "arg name": "value" } } From c932087997456bdbb4c07661aaa648dd861263f1 Mon Sep 17 00:00:00 2001 From: Gull Man Date: Wed, 12 Apr 2023 12:13:18 +0200 Subject: [PATCH 08/55] add encoding to open file --- scripts/file_operations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/file_operations.py b/scripts/file_operations.py index c6066ef9..59b3a0d0 100644 --- a/scripts/file_operations.py +++ b/scripts/file_operations.py @@ -38,7 +38,7 @@ def write_to_file(filename, text): directory = os.path.dirname(filepath) if not os.path.exists(directory): os.makedirs(directory) - with open(filepath, "w") as f: + with open(filepath, "w", encoding='utf-8') as f: f.write(text) return "File written to successfully." except Exception as e: From c5f0cb3d3faa06d0fa7335569247310d08e5f004 Mon Sep 17 00:00:00 2001 From: profound Date: Wed, 12 Apr 2023 23:38:30 +0800 Subject: [PATCH 09/55] fix read config file encoding that broke Chinese --- scripts/ai_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ai_config.py b/scripts/ai_config.py index bd373944..743c87e4 100644 --- a/scripts/ai_config.py +++ b/scripts/ai_config.py @@ -46,7 +46,7 @@ class AIConfig: """ try: - with open(config_file) as file: + with open(config_file, encoding='utf-8') as file: config_params = yaml.load(file, Loader=yaml.FullLoader) except FileNotFoundError: config_params = {} From d237cf3d87526e2aad6180de6a5ed531efca858d Mon Sep 17 00:00:00 2001 From: lekapsy <117356974+lekapsy@users.noreply.github.com> Date: Wed, 12 Apr 2023 18:54:10 +0200 Subject: [PATCH 10/55] Improve .env File Organization, Readability, and Documentation This pull request aims to enhance the organization, readability, and understanding of the .env.template file for users when they modify the settings. The changes include organizing the file in a tree-like structure with appropriate comments, providing clear guidance for users about the purpose of each variable, their possible values, and default settings when applicable. As a user with no prior knowledge of best practices of contributing to a project / .env.template file documentation, I took the liberty to make changes to the file based on what I would have liked to have seen when I first encountered it. My goal was to include every configurable option for ease of use and better understanding of how the code works. The key improvements made in this pull request are: 1. Grouping related variables under appropriate headers for better organization and ease of navigation. 2. Adding informative comments for each variable to help users understand their purpose and possible values. 3. Including default values in the comments to inform users of the consequences of not providing a specific value for a variable, allowing them to make informed decisions when configuring the application. 4. Formatting the file consistently for better readability. These changes will enhance user experience by simplifying the configuration process and reducing potential confusion. Users can quickly and easily configure the application without having to search through the code to determine default values or understand the relationship between various settings. Additionally, well-organized code and documentation can lead to fewer issues and misunderstandings, saving time for both users and maintainers of the project. Please review these changes and let me know if you have any questions or suggestions for further improvement so I can make any necessary adjustments. --- .env.template | 98 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/.env.template b/.env.template index 6fbc8424..9127659a 100644 --- a/.env.template +++ b/.env.template @@ -1,17 +1,97 @@ -PINECONE_API_KEY=your-pinecone-api-key -PINECONE_ENV=your-pinecone-region +################################################################################ +### LLM PROVIDER +################################################################################ + +### OPENAI +# OPENAI_API_KEY - OpenAI API Key (Example: my-openai-api-key) OPENAI_API_KEY=your-openai-api-key -ELEVENLABS_API_KEY=your-elevenlabs-api-key -ELEVENLABS_VOICE_1_ID=your-voice-id -ELEVENLABS_VOICE_2_ID=your-voice-id -SMART_LLM_MODEL=gpt-4 -FAST_LLM_MODEL=gpt-3.5-turbo -GOOGLE_API_KEY= -CUSTOM_SEARCH_ENGINE_ID= + +# Use Azure OpenAI +# USE_AZURE - Use Azure OpenAI or not (Default: False) USE_AZURE=False + +### AZURE OPENAI +# OPENAI_AZURE_API_BASE - OpenAI API base URL for Azure (Example: https://my-azure-openai-url.com) OPENAI_AZURE_API_BASE=your-base-url-for-azure +# OPENAI_AZURE_API_VERSION - OpenAI API version for Azure (Example: v1) OPENAI_AZURE_API_VERSION=api-version-for-azure +# OPENAI_AZURE_DEPLOYMENT_ID - OpenAI deployment ID for Azure (Example: my-deployment-id) OPENAI_AZURE_DEPLOYMENT_ID=deployment-id-for-azure + +################################################################################ +### LLM MODELS +################################################################################ + +# SMART_LLM_MODEL - Smart language model (Default: gpt-4) +SMART_LLM_MODEL=gpt-4 +# FAST_LLM_MODEL - Fast language model (Default: gpt-3.5-turbo) +FAST_LLM_MODEL=gpt-3.5-turbo + +### LLM MODEL SETTINGS +# FAST_TOKEN_LIMIT - Fast token limit for OpenAI (Default: 4000) +FAST_TOKEN_LIMIT=4000 +# SMART_TOKEN_LIMIT - Smart token limit for OpenAI (Default: 8000) +# When using --gpt3only this needs to be set to 4000. +SMART_TOKEN_LIMIT=8000 + +################################################################################ +### MEMORY +################################################################################ + +# MEMORY_BACKEND - Memory backend type (Default: local) +MEMORY_BACKEND=redis + +### PINECONE +# PINECONE_API_KEY - Pinecone API Key (Example: my-pinecone-api-key) +PINECONE_API_KEY=your-pinecone-api-key +# PINECONE_ENV - Pinecone environment (region) (Example: us-west-2) +PINECONE_ENV=your-pinecone-region + +### REDIS +# REDIS_HOST - Redis host (Default: localhost) +REDIS_HOST=localhost +# REDIS_PORT - Redis port (Default: 6379) +REDIS_PORT=6379 +# REDIS_PASSWORD - Redis password (Default: "") +REDIS_PASSWORD= + +################################################################################ +### IMAGE GENERATION PROVIDER +################################################################################ + +### OPEN AI +# IMAGE_PROVIDER - Image provider (Example: dalle) IMAGE_PROVIDER=dalle + +### HUGGINGFACE +# STABLE DIFFUSION( +# Default URL: https://api-inference.huggingface.co/models/CompVis/stable-diffusion-v1-4 +# Set in image_gen.py) +# HUGGINGFACE_API_TOKEN - HuggingFace API token (Example: my-huggingface-api-token) HUGGINGFACE_API_TOKEN= + +################################################################################ +### SEARCH PROVIDER +################################################################################ + +### GOOGLE +# GOOGLE_API_KEY - Google API key (Example: my-google-api-key) +GOOGLE_API_KEY= +# CUSTOM_SEARCH_ENGINE_ID - Custom search engine ID (Example: my-custom-search-engine-id) +CUSTOM_SEARCH_ENGINE_ID= + +################################################################################ +### TTS PROVIDER +################################################################################ + +### MAC OS +# USE_MAC_OS_TTS - Use Mac OS TTS or not (Default: False) USE_MAC_OS_TTS=False + +### ELEVENLABS +# ELEVENLABS_API_KEY - Eleven Labs API key (Example: my-elevenlabs-api-key) +ELEVENLABS_API_KEY=your-elevenlabs-api-key +# ELEVENLABS_VOICE_1_ID - Eleven Labs voice 1 ID (Example: my-voice-id-1) +ELEVENLABS_VOICE_1_ID=your-voice-id +# ELEVENLABS_VOICE_2_ID - Eleven Labs voice 2 ID (Example: my-voice-id-2) +ELEVENLABS_VOICE_2_ID=your-voice-id From a850c27dd553cf6da5b29ac025d68dcce24781dc Mon Sep 17 00:00:00 2001 From: Eesa Hamza Date: Wed, 12 Apr 2023 23:13:34 +0300 Subject: [PATCH 11/55] Improved logging on connection fail to redis --- scripts/memory/redismem.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/memory/redismem.py b/scripts/memory/redismem.py index 2082fe58..1267c4de 100644 --- a/scripts/memory/redismem.py +++ b/scripts/memory/redismem.py @@ -7,6 +7,8 @@ from redis.commands.search.indexDefinition import IndexDefinition, IndexType import numpy as np from memory.base import MemoryProviderSingleton, get_ada_embedding +from logger import logger +from colorama import Fore, Style SCHEMA = [ @@ -44,6 +46,18 @@ class RedisMemory(MemoryProviderSingleton): db=0 # Cannot be changed ) self.cfg = cfg + + # Check redis connection + try: + self.redis.ping() + except redis.ConnectionError as e: + logger.typewriter_log("FAILED TO CONNECT TO REDIS", Fore.RED, Style.BRIGHT + str(e) + Style.RESET_ALL) + logger.typewriter_log("DOUBLE CHECK CONFIGURATION", + Fore.YELLOW, + "Please ensure you have setup and configured redis properly for use. " + + f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#redis-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") + exit(1) + if cfg.wipe_redis_on_start: self.redis.flushall() try: From 5d871f04e6daef01de49d2b5949f6ca55b3cfbde Mon Sep 17 00:00:00 2001 From: Eesa Hamza Date: Wed, 12 Apr 2023 23:29:54 +0300 Subject: [PATCH 12/55] Added pinecone connectivity check and added relevant logging --- scripts/memory/pinecone.py | 16 ++++++++++++++-- scripts/memory/redismem.py | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/memory/pinecone.py b/scripts/memory/pinecone.py index 8e1eaa57..eeafd9c9 100644 --- a/scripts/memory/pinecone.py +++ b/scripts/memory/pinecone.py @@ -2,7 +2,8 @@ import pinecone from memory.base import MemoryProviderSingleton, get_ada_embedding - +from logger import logger +from colorama import Fore, Style class PineconeMemory(MemoryProviderSingleton): def __init__(self, cfg): @@ -16,7 +17,18 @@ class PineconeMemory(MemoryProviderSingleton): # this assumes we don't start with memory. # for now this works. # we'll need a more complicated and robust system if we want to start with memory. - self.vec_num = 0 + self.vec_num = 0 + + try: + pinecone.whoami() + except Exception as e: + logger.typewriter_log("FAILED TO CONNECT TO PINECONE", Fore.RED, Style.BRIGHT + str(e) + Style.RESET_ALL) + logger.typewriter_log("DOUBLE CHECK CONFIGURATION", + Fore.YELLOW, + "Please ensure you have setup and configured Pinecone properly for use. " + + f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#-pinecone-api-key-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") + exit(1) + if table_name not in pinecone.list_indexes(): pinecone.create_index(table_name, dimension=dimension, metric=metric, pod_type=pod_type) self.index = pinecone.Index(table_name) diff --git a/scripts/memory/redismem.py b/scripts/memory/redismem.py index 1267c4de..b2d5326f 100644 --- a/scripts/memory/redismem.py +++ b/scripts/memory/redismem.py @@ -54,7 +54,7 @@ class RedisMemory(MemoryProviderSingleton): logger.typewriter_log("FAILED TO CONNECT TO REDIS", Fore.RED, Style.BRIGHT + str(e) + Style.RESET_ALL) logger.typewriter_log("DOUBLE CHECK CONFIGURATION", Fore.YELLOW, - "Please ensure you have setup and configured redis properly for use. " + + "Please ensure you have setup and configured Redis properly for use. " + f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#redis-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") exit(1) From 8c51fe8373aa6ec85b8b9c9a0b5c3b45d9d35ff6 Mon Sep 17 00:00:00 2001 From: Eesa Hamza Date: Wed, 12 Apr 2023 23:38:53 +0300 Subject: [PATCH 13/55] Added new logging function as an error or warning message --- scripts/logger.py | 5 +++++ scripts/memory/pinecone.py | 6 ++---- scripts/memory/redismem.py | 6 ++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/logger.py b/scripts/logger.py index a609e602..efc2adba 100644 --- a/scripts/logger.py +++ b/scripts/logger.py @@ -123,7 +123,12 @@ class Logger(metaclass=Singleton): def set_level(self, level): self.logger.setLevel(level) self.typing_logger.setLevel(level) + + def double_check(self, additionalText=None): + if not additionalText: + additionalText = "Please ensure you've setup and configured everything correctly. Read https://github.com/Torantulino/Auto-GPT#readme to double check. You can also create a github issue or join the discord and ask there!" + self.typewriter_log("DOUBLE CHECK CONFIGURATION", Fore.YELLOW, additionalText) ''' Output stream to console using simulated typing diff --git a/scripts/memory/pinecone.py b/scripts/memory/pinecone.py index eeafd9c9..9d033f5a 100644 --- a/scripts/memory/pinecone.py +++ b/scripts/memory/pinecone.py @@ -23,10 +23,8 @@ class PineconeMemory(MemoryProviderSingleton): pinecone.whoami() except Exception as e: logger.typewriter_log("FAILED TO CONNECT TO PINECONE", Fore.RED, Style.BRIGHT + str(e) + Style.RESET_ALL) - logger.typewriter_log("DOUBLE CHECK CONFIGURATION", - Fore.YELLOW, - "Please ensure you have setup and configured Pinecone properly for use. " + - f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#-pinecone-api-key-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") + logger.double_check("Please ensure you have setup and configured Pinecone properly for use. " + + f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#-pinecone-api-key-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") exit(1) if table_name not in pinecone.list_indexes(): diff --git a/scripts/memory/redismem.py b/scripts/memory/redismem.py index b2d5326f..6647cbca 100644 --- a/scripts/memory/redismem.py +++ b/scripts/memory/redismem.py @@ -52,10 +52,8 @@ class RedisMemory(MemoryProviderSingleton): self.redis.ping() except redis.ConnectionError as e: logger.typewriter_log("FAILED TO CONNECT TO REDIS", Fore.RED, Style.BRIGHT + str(e) + Style.RESET_ALL) - logger.typewriter_log("DOUBLE CHECK CONFIGURATION", - Fore.YELLOW, - "Please ensure you have setup and configured Redis properly for use. " + - f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#redis-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") + logger.double_check("Please ensure you have setup and configured Redis properly for use. " + + f"You can check out {Fore.CYAN + Style.BRIGHT}https://github.com/Torantulino/Auto-GPT#redis-setup{Style.RESET_ALL} to ensure you've set up everything correctly.") exit(1) if cfg.wipe_redis_on_start: From 76b5b957440df3f757185caf4ff9574029f04156 Mon Sep 17 00:00:00 2001 From: Eesa Hamza Date: Wed, 12 Apr 2023 23:49:32 +0300 Subject: [PATCH 14/55] Attempt to fix Linter issues --- scripts/logger.py | 3 ++- scripts/memory/pinecone.py | 4 ++-- scripts/memory/redismem.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/logger.py b/scripts/logger.py index efc2adba..b5a45de7 100644 --- a/scripts/logger.py +++ b/scripts/logger.py @@ -123,13 +123,14 @@ class Logger(metaclass=Singleton): def set_level(self, level): self.logger.setLevel(level) self.typing_logger.setLevel(level) - + def double_check(self, additionalText=None): if not additionalText: additionalText = "Please ensure you've setup and configured everything correctly. Read https://github.com/Torantulino/Auto-GPT#readme to double check. You can also create a github issue or join the discord and ask there!" self.typewriter_log("DOUBLE CHECK CONFIGURATION", Fore.YELLOW, additionalText) + ''' Output stream to console using simulated typing ''' diff --git a/scripts/memory/pinecone.py b/scripts/memory/pinecone.py index 9d033f5a..fa21124b 100644 --- a/scripts/memory/pinecone.py +++ b/scripts/memory/pinecone.py @@ -3,7 +3,7 @@ import pinecone from memory.base import MemoryProviderSingleton, get_ada_embedding from logger import logger -from colorama import Fore, Style +from colorama import Fore, Style class PineconeMemory(MemoryProviderSingleton): def __init__(self, cfg): @@ -17,7 +17,7 @@ class PineconeMemory(MemoryProviderSingleton): # this assumes we don't start with memory. # for now this works. # we'll need a more complicated and robust system if we want to start with memory. - self.vec_num = 0 + self.vec_num = 0 try: pinecone.whoami() diff --git a/scripts/memory/redismem.py b/scripts/memory/redismem.py index 6647cbca..49045dd8 100644 --- a/scripts/memory/redismem.py +++ b/scripts/memory/redismem.py @@ -8,7 +8,7 @@ import numpy as np from memory.base import MemoryProviderSingleton, get_ada_embedding from logger import logger -from colorama import Fore, Style +from colorama import Fore, Style SCHEMA = [ From 5badde2c2725d636fa415b53acf96a071512f22f Mon Sep 17 00:00:00 2001 From: "Joseph C. Miller, II" Date: Wed, 12 Apr 2023 15:30:34 -0600 Subject: [PATCH 15/55] Add message to explain exit. --- scripts/config.py | 5 +++++ scripts/main.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/scripts/config.py b/scripts/config.py index 6e448954..09f5276e 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -35,6 +35,7 @@ class Config(metaclass=Singleton): """Initialize the Config class""" self.debug_mode = False self.continuous_mode = False + self.continuous_limit = 0 self.speak_mode = False self.fast_llm_model = os.getenv("FAST_LLM_MODEL", "gpt-3.5-turbo") @@ -89,6 +90,10 @@ class Config(metaclass=Singleton): """Set the continuous mode value.""" self.continuous_mode = value + def set_continuous_limit(self, value: int): + """Set the continuous limit value.""" + self.continuous_limit = value + def set_speak_mode(self, value: bool): """Set the speak mode value.""" self.speak_mode = value diff --git a/scripts/main.py b/scripts/main.py index 0a4e97a2..27275cb0 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -271,6 +271,7 @@ def parse_arguments(): parser = argparse.ArgumentParser(description='Process arguments.') parser.add_argument('--continuous', action='store_true', help='Enable Continuous Mode') + parser.add_argument('--continuous-limit', '-l', type=int, default=0, dest="continuous_limit", help='Defines the number of times to run in continuous mode') parser.add_argument('--speak', action='store_true', help='Enable Speak Mode') parser.add_argument('--debug', action='store_true', help='Enable Debug Mode') parser.add_argument('--gpt3only', action='store_true', help='Enable GPT3.5 Only Mode') @@ -290,6 +291,16 @@ def parse_arguments(): "Continuous mode is not recommended. It is potentially dangerous and may cause your AI to run forever or carry out actions you would not usually authorise. Use at your own risk.") cfg.set_continuous_mode(True) + if args.continuous_limit and not args.continuous: + parser.error("--continuous-limit can only be used with --continuous") + + if args.continuous_limit > 0: + logger.typewriter_log( + "Continuous Limit: ", + Fore.GREEN, + f"{args.continuous_limit}") + cfg.set_continuous_limit(args.continuous_limit) + if args.speak: logger.typewriter_log("Speak Mode: ", Fore.GREEN, "ENABLED") cfg.set_speak_mode(True) @@ -337,7 +348,14 @@ memory = get_memory(cfg, init=True) print('Using memory of type: ' + memory.__class__.__name__) # Interaction Loop +loop_count = 0 while True: + # Discontinue if continuous limit is reached + loop_count += 1 + if cfg.continuous_mode and cfg.continuous_limit > 0 and loop_count > cfg.continuous_limit: + logger.typewriter_log("Continuous Limit Reached: ", Fore.RED, f"{cfg.continuous_limit}") + break + # Send message to AI, get response with Spinner("Thinking... "): assistant_reply = chat.chat_with_ai( From 12e1fcca92ed8ec57b1365f3a0f57eb29115c1ff Mon Sep 17 00:00:00 2001 From: "Joseph C. Miller, II" Date: Wed, 12 Apr 2023 15:36:35 -0600 Subject: [PATCH 16/55] Correct the checking for continuous limit without continuous mode --- scripts/main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 27275cb0..3d239009 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -291,9 +291,6 @@ def parse_arguments(): "Continuous mode is not recommended. It is potentially dangerous and may cause your AI to run forever or carry out actions you would not usually authorise. Use at your own risk.") cfg.set_continuous_mode(True) - if args.continuous_limit and not args.continuous: - parser.error("--continuous-limit can only be used with --continuous") - if args.continuous_limit > 0: logger.typewriter_log( "Continuous Limit: ", @@ -301,6 +298,10 @@ def parse_arguments(): f"{args.continuous_limit}") cfg.set_continuous_limit(args.continuous_limit) + # Check if continuous limit is used without continuous mode + if args.continuous_limit and not args.continuous: + parser.error("--continuous-limit can only be used with --continuous") + if args.speak: logger.typewriter_log("Speak Mode: ", Fore.GREEN, "ENABLED") cfg.set_speak_mode(True) From d706a3436d763ec78cc14e93533da26ac0ed40b0 Mon Sep 17 00:00:00 2001 From: "Joseph C. Miller, II" Date: Wed, 12 Apr 2023 15:39:25 -0600 Subject: [PATCH 17/55] Make configuration similar to other arguments. --- scripts/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 3d239009..90033afb 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -271,7 +271,7 @@ def parse_arguments(): parser = argparse.ArgumentParser(description='Process arguments.') parser.add_argument('--continuous', action='store_true', help='Enable Continuous Mode') - parser.add_argument('--continuous-limit', '-l', type=int, default=0, dest="continuous_limit", help='Defines the number of times to run in continuous mode') + parser.add_argument('--continuous-limit', '-l', type=int, dest="continuous_limit", help='Defines the number of times to run in continuous mode') parser.add_argument('--speak', action='store_true', help='Enable Speak Mode') parser.add_argument('--debug', action='store_true', help='Enable Debug Mode') parser.add_argument('--gpt3only', action='store_true', help='Enable GPT3.5 Only Mode') @@ -291,7 +291,7 @@ def parse_arguments(): "Continuous mode is not recommended. It is potentially dangerous and may cause your AI to run forever or carry out actions you would not usually authorise. Use at your own risk.") cfg.set_continuous_mode(True) - if args.continuous_limit > 0: + if args.continuous_limit: logger.typewriter_log( "Continuous Limit: ", Fore.GREEN, From 129d734a4c2bedf3fbaca364ec8852610762f54c Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Wed, 12 Apr 2023 16:15:21 -0700 Subject: [PATCH 18/55] Auto-GPT requires numpy --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b864c1d3..3f7fd228 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,5 @@ redis orjson Pillow coverage -flake8 \ No newline at end of file +flake8 +numpy From 746cd5bc88fd38180b2100dcb0e48f1223aa1b80 Mon Sep 17 00:00:00 2001 From: derekcl Date: Wed, 12 Apr 2023 19:38:38 -0500 Subject: [PATCH 19/55] linter autofix --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c9ef9d5c..73461af8 100644 --- a/README.md +++ b/README.md @@ -32,21 +32,28 @@ Your support is greatly appreciated - [Auto-GPT: An Autonomous GPT-4 Experiment](#auto-gpt-an-autonomous-gpt-4-experiment) - [Demo (30/03/2023):](#demo-30032023) - - [💖 Help Fund Auto-GPT's Development](#-help-fund-auto-gpts-development) - [Table of Contents](#table-of-contents) - [🚀 Features](#-features) - [📋 Requirements](#-requirements) - [💾 Installation](#-installation) - [🔧 Usage](#-usage) + - [Logs](#logs) - [🗣️ Speech Mode](#️-speech-mode) - [🔍 Google API Keys Configuration](#-google-api-keys-configuration) - [Setting up environment variables](#setting-up-environment-variables) + - [Redis Setup](#redis-setup) + - [🌲 Pinecone API Key Setup](#-pinecone-api-key-setup) + - [Setting up environment variables](#setting-up-environment-variables-1) + - [Setting Your Cache Type](#setting-your-cache-type) + - [View Memory Usage](#view-memory-usage) - [💀 Continuous Mode ⚠️](#-continuous-mode-️) - [GPT3.5 ONLY Mode](#gpt35-only-mode) - - [🖼 Image Generation](#image-generation) + - [🖼 Image Generation](#-image-generation) - [⚠️ Limitations](#️-limitations) - [🛡 Disclaimer](#-disclaimer) - [🐦 Connect with Us on Twitter](#-connect-with-us-on-twitter) + - [Run tests](#run-tests) + - [Run linter](#run-linter) ## 🚀 Features @@ -233,7 +240,6 @@ export PINECONE_ENV="Your pinecone region" # something like: us-east4-gcp ``` - ## Setting Your Cache Type By default Auto-GPT is going to use LocalCache instead of redis or Pinecone. @@ -344,4 +350,4 @@ flake8 scripts/ tests/ # Or, if you want to run flake8 with the same configuration as the CI: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305 -``` \ No newline at end of file +``` From 62bd93a4d2bf24b9e99e4598cb37e3f722f1f113 Mon Sep 17 00:00:00 2001 From: Merwane Hamadi Date: Wed, 12 Apr 2023 17:48:08 -0700 Subject: [PATCH 20/55] Import NoMemory and add it as a memory_backend option in get_memory function --- scripts/memory/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/memory/__init__.py b/scripts/memory/__init__.py index a07f9fd8..d407f087 100644 --- a/scripts/memory/__init__.py +++ b/scripts/memory/__init__.py @@ -1,4 +1,5 @@ from memory.local import LocalCache +from memory.no_memory import NoMemory # List of supported memory backends # Add a backend to this list if the import attempt is successful @@ -34,6 +35,8 @@ def get_memory(cfg, init=False): " use Redis as a memory backend.") else: memory = RedisMemory(cfg) + elif cfg.memory_backend == "no_memory": + memory = NoMemory(cfg) if memory is None: memory = LocalCache(cfg) @@ -50,4 +53,5 @@ __all__ = [ "LocalCache", "RedisMemory", "PineconeMemory", + "NoMemory" ] From 84c128fd0facca6a4f27c52a1032656d97abfc72 Mon Sep 17 00:00:00 2001 From: Merwane Hamadi Date: Wed, 12 Apr 2023 17:48:11 -0700 Subject: [PATCH 21/55] Create NoMemory provider as a memory provider that does not store any data --- scripts/memory/no_memory.py | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 scripts/memory/no_memory.py diff --git a/scripts/memory/no_memory.py b/scripts/memory/no_memory.py new file mode 100644 index 00000000..45dbd734 --- /dev/null +++ b/scripts/memory/no_memory.py @@ -0,0 +1,65 @@ +from typing import Optional, List, Any + +from memory.base import MemoryProviderSingleton + +class NoMemory(MemoryProviderSingleton): + def __init__(self, cfg): + """ + Initializes the NoMemory provider. + + Args: + cfg: The config object. + + Returns: None + """ + pass + + def add(self, data: str) -> str: + """ + Adds a data point to the memory. No action is taken in NoMemory. + + Args: + data: The data to add. + + Returns: An empty string. + """ + return "" + + def get(self, data: str) -> Optional[List[Any]]: + """ + Gets the data from the memory that is most relevant to the given data. + NoMemory always returns None. + + Args: + data: The data to compare to. + + Returns: None + """ + return None + + def clear(self) -> str: + """ + Clears the memory. No action is taken in NoMemory. + + Returns: An empty string. + """ + return "" + + def get_relevant(self, data: str, num_relevant: int = 5) -> Optional[List[Any]]: + """ + Returns all the data in the memory that is relevant to the given data. + NoMemory always returns None. + + Args: + data: The data to compare to. + num_relevant: The number of relevant data to return. + + Returns: None + """ + return None + + def get_stats(self): + """ + Returns: An empty dictionary as there are no stats in NoMemory. + """ + return {} From db9f8a2749e5f44585b2ad7514f346e7a5a9a26b Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Wed, 12 Apr 2023 22:14:51 -0400 Subject: [PATCH 22/55] Added config option for OPENAI_API_TYPE=azure_ad --- scripts/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index 255587d7..4f896126 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -51,7 +51,8 @@ class Config(metaclass=Singleton): self.openai_deployment_id = os.getenv("OPENAI_AZURE_DEPLOYMENT_ID") self.azure_chat_deployment_id = os.getenv("OPENAI_AZURE_CHAT_DEPLOYMENT_ID") self.azure_embeddigs_deployment_id = os.getenv("OPENAI_AZURE_EMBEDDINGS_DEPLOYMENT_ID") - openai.api_type = "azure" + openai.api_type = os.getenv("OPENAI_API_TYPE", "azure") + openai.api_base = self.openai_api_base openai.api_version = self.openai_api_version From 65abfc9d3db741aeab56d890097f122300984011 Mon Sep 17 00:00:00 2001 From: Richard Beales Date: Thu, 13 Apr 2023 06:01:28 +0100 Subject: [PATCH 23/55] Correct link to unit tests in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c9ef9d5c..a7b91e2d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![GitHub Repo stars](https://img.shields.io/github/stars/Torantulino/auto-gpt?style=social) ![Twitter Follow](https://img.shields.io/twitter/follow/siggravitas?style=social) [![](https://dcbadge.vercel.app/api/server/PQ7VX6TY4t?style=flat)](https://discord.gg/PQ7VX6TY4t) -[![Unit Tests](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml) +[![Unit Tests](https://github.com/Torantulino/Auto-GPT/actions/workflows/ci.yml/badge.svg)](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml) Auto-GPT is an experimental open-source application showcasing the capabilities of the GPT-4 language model. This program, driven by GPT-4, chains together LLM "thoughts", to autonomously achieve whatever goal you set. As one of the first examples of GPT-4 running fully autonomously, Auto-GPT pushes the boundaries of what is possible with AI. @@ -344,4 +344,4 @@ flake8 scripts/ tests/ # Or, if you want to run flake8 with the same configuration as the CI: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305 -``` \ No newline at end of file +``` From 1546c244419e1531d72cb3b558e48e9eda6b5aa0 Mon Sep 17 00:00:00 2001 From: Ishwor Panta <31570025+ishworpanta10@users.noreply.github.com> Date: Thu, 13 Apr 2023 10:52:35 +0545 Subject: [PATCH 24/55] Update serial in Installation step updated serial in Installation step from 1 rather than from 0. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c9ef9d5c..4bdc97c6 100644 --- a/README.md +++ b/README.md @@ -70,32 +70,32 @@ Optional: To install Auto-GPT, follow these steps: -0. Make sure you have all the **requirements** above, if not, install/get them. +1. Make sure you have all the **requirements** above, if not, install/get them. _The following commands should be executed in a CMD, Bash or Powershell window. To do this, go to a folder on your computer, click in the folder path at the top and type CMD, then press enter._ -1. Clone the repository: +2. Clone the repository: For this step you need Git installed, but you can just download the zip file instead by clicking the button at the top of this page ☝️ ``` git clone https://github.com/Torantulino/Auto-GPT.git ``` -2. Navigate to the project directory: +3. Navigate to the project directory: _(Type this into your CMD window, you're aiming to navigate the CMD window to the repository you just downloaded)_ ``` cd 'Auto-GPT' ``` -3. Install the required dependencies: +4. Install the required dependencies: _(Again, type this into your CMD window)_ ``` pip install -r requirements.txt ``` -4. Rename `.env.template` to `.env` and fill in your `OPENAI_API_KEY`. If you plan to use Speech Mode, fill in your `ELEVEN_LABS_API_KEY` as well. +5. Rename `.env.template` to `.env` and fill in your `OPENAI_API_KEY`. If you plan to use Speech Mode, fill in your `ELEVEN_LABS_API_KEY` as well. - Obtain your OpenAI API key from: https://platform.openai.com/account/api-keys. - Obtain your ElevenLabs API key from: https://elevenlabs.io. You can view your xi-api-key using the "Profile" tab on the website. @@ -344,4 +344,4 @@ flake8 scripts/ tests/ # Or, if you want to run flake8 with the same configuration as the CI: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305 -``` \ No newline at end of file +``` From d9380130847180fcfa9510f4a32c284b2f7cf8cf Mon Sep 17 00:00:00 2001 From: jiangying Date: Thu, 13 Apr 2023 15:06:29 +0800 Subject: [PATCH 25/55] Update README.md on log location --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 87b5d1be..a32b12c0 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ python scripts/main.py ### Logs -You will find activity and error logs in the folder `./logs` +You will find activity and error logs in the folder `./output/logs` To output debug logs: From 0061976a91f74af384e4f26010a1f00a41dd3536 Mon Sep 17 00:00:00 2001 From: Kasra Amini Date: Thu, 13 Apr 2023 03:32:39 -0400 Subject: [PATCH 26/55] Removed redundant cfg object creation in base memory file --- scripts/memory/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/memory/base.py b/scripts/memory/base.py index 1be7b3dd..1bb4e89f 100644 --- a/scripts/memory/base.py +++ b/scripts/memory/base.py @@ -2,7 +2,6 @@ import abc from config import AbstractSingleton, Config import openai -cfg = Config() cfg = Config() From aa4118d4b999f1d46eaf7a697986768127f272f1 Mon Sep 17 00:00:00 2001 From: sagarishere <5121817+sagarishere@users.noreply.github.com> Date: Thu, 13 Apr 2023 11:27:15 +0300 Subject: [PATCH 27/55] Typo: in PULL_REQUEST_TEMPLATE.md Typo --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9fa56593..c355965a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,7 +26,7 @@ By following these guidelines, your PRs are more likely to be merged quickly aft - [ ] I have thoroughly tested my changes with multiple different prompts. - [ ] I have considered potential risks and mitigations for my changes. - [ ] I have documented my changes clearly and comprehensively. -- [ ] I have not snuck in any "extra" small tweaks changes +- [ ] I have not snuck in any "extra" small tweaks changes From 4c7eef550a4c33c0c7eefbaeb5fa15288a5392d3 Mon Sep 17 00:00:00 2001 From: WalterSumbon <907449377@qq.com> Date: Thu, 13 Apr 2023 16:45:08 +0800 Subject: [PATCH 28/55] replace deprecated function with current equivalent --- scripts/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 81f560b2..5b84bd70 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -310,8 +310,8 @@ def parse_arguments(): supported_memory = get_supported_memory_backends() chosen = args.memory_type if not chosen in supported_memory: - print_to_console("ONLY THE FOLLOWING MEMORY BACKENDS ARE SUPPORTED: ", Fore.RED, f'{supported_memory}') - print_to_console(f"Defaulting to: ", Fore.YELLOW, cfg.memory_backend) + logger.typewriter_log("ONLY THE FOLLOWING MEMORY BACKENDS ARE SUPPORTED: ", Fore.RED, f'{supported_memory}') + logger.typewriter_log(f"Defaulting to: ", Fore.YELLOW, cfg.memory_backend) else: cfg.memory_backend = chosen From 947d27a9edcc1ab6116cf8eed1f5e50a0d416dbf Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Wed, 12 Apr 2023 22:42:15 +0200 Subject: [PATCH 29/55] docs: Update README.md with the flake8 command used in the CI --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 87b5d1be..b5d9ac4e 100644 --- a/README.md +++ b/README.md @@ -342,7 +342,9 @@ coverage run -m unittest discover tests ## Run linter -This project uses [flake8](https://flake8.pycqa.org/en/latest/) for linting. To run the linter, run the following command: +This project uses [flake8](https://flake8.pycqa.org/en/latest/) for linting. We currently use the following rules: `E303,W293,W291,W292,E305`. See the [flake8 rules](https://www.flake8rules.com/) for more information. + +To run the linter, run the following command: ``` flake8 scripts/ tests/ From 8ff36bb8ba5663aa7ee12f365fc89fd101d9aee6 Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Wed, 12 Apr 2023 22:55:20 +0200 Subject: [PATCH 30/55] lint: Add rule E231 to the flake8 linting job --- .github/workflows/ci.yml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 070df794..de214005 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: Lint with flake8 continue-on-error: false - run: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305 + run: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231 - name: Run unittest tests with coverage run: | diff --git a/README.md b/README.md index b5d9ac4e..82d489b1 100644 --- a/README.md +++ b/README.md @@ -342,7 +342,7 @@ coverage run -m unittest discover tests ## Run linter -This project uses [flake8](https://flake8.pycqa.org/en/latest/) for linting. We currently use the following rules: `E303,W293,W291,W292,E305`. See the [flake8 rules](https://www.flake8rules.com/) for more information. +This project uses [flake8](https://flake8.pycqa.org/en/latest/) for linting. We currently use the following rules: `E303,W293,W291,W292,E305,E231`. See the [flake8 rules](https://www.flake8rules.com/) for more information. To run the linter, run the following command: @@ -350,5 +350,5 @@ To run the linter, run the following command: flake8 scripts/ tests/ # Or, if you want to run flake8 with the same configuration as the CI: -flake8 scripts/ tests/ --select E303,W293,W291,W292,E305 -``` +flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231 +``` \ No newline at end of file From 4afd0a3714e3fdc22a0dc16920869f3df8fa1d5e Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Wed, 12 Apr 2023 22:55:42 +0200 Subject: [PATCH 31/55] lint: Fix E231 flake8 linting errors --- scripts/config.py | 2 +- tests/test_json_parser.py | 4 ++-- tests/unit/json_tests.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index ebf1b08b..01505b22 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -73,7 +73,7 @@ class Config(metaclass=Singleton): # User agent headers to use when browsing web # Some websites might just completely deny request with an error code if no user agent was found. - self.user_agent_header = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"} + self.user_agent_header = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"} self.redis_host = os.getenv("REDIS_HOST", "localhost") self.redis_port = os.getenv("REDIS_PORT", "6379") self.redis_password = os.getenv("REDIS_PASSWORD", "") diff --git a/tests/test_json_parser.py b/tests/test_json_parser.py index b8cb2680..0f2c6488 100644 --- a/tests/test_json_parser.py +++ b/tests/test_json_parser.py @@ -50,7 +50,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } }, @@ -89,7 +89,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } }, diff --git a/tests/unit/json_tests.py b/tests/unit/json_tests.py index 1edbaeaf..3320ad5e 100644 --- a/tests/unit/json_tests.py +++ b/tests/unit/json_tests.py @@ -52,7 +52,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } }, @@ -91,7 +91,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } }, From 04dc0f7149d29ea284e55ff19b0178db2b706a40 Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Wed, 12 Apr 2023 23:04:59 +0200 Subject: [PATCH 32/55] lint: Add flake8 rule E302 to the flake8 workflow job --- .github/workflows/ci.yml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de214005..0b90b55d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: Lint with flake8 continue-on-error: false - run: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231 + run: flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231,E302 - name: Run unittest tests with coverage run: | diff --git a/README.md b/README.md index 82d489b1..51649bd6 100644 --- a/README.md +++ b/README.md @@ -342,7 +342,7 @@ coverage run -m unittest discover tests ## Run linter -This project uses [flake8](https://flake8.pycqa.org/en/latest/) for linting. We currently use the following rules: `E303,W293,W291,W292,E305,E231`. See the [flake8 rules](https://www.flake8rules.com/) for more information. +This project uses [flake8](https://flake8.pycqa.org/en/latest/) for linting. We currently use the following rules: `E303,W293,W291,W292,E305,E231,E302`. See the [flake8 rules](https://www.flake8rules.com/) for more information. To run the linter, run the following command: @@ -350,5 +350,5 @@ To run the linter, run the following command: flake8 scripts/ tests/ # Or, if you want to run flake8 with the same configuration as the CI: -flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231 +flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231,E302 ``` \ No newline at end of file From d1ea6cf002fb9b7747221666ba5593108cd48984 Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Wed, 12 Apr 2023 23:05:14 +0200 Subject: [PATCH 33/55] lint: Fix all E302 linting errors --- scripts/agent_manager.py | 1 + scripts/ai_config.py | 1 + scripts/browse.py | 16 ++++++++++++++++ scripts/call_ai_function.py | 2 ++ scripts/chat.py | 1 + scripts/commands.py | 3 +++ scripts/data.py | 1 + scripts/file_operations.py | 1 + scripts/image_gen.py | 1 + scripts/llm_utils.py | 1 + scripts/logger.py | 1 + scripts/main.py | 4 ++++ scripts/memory/__init__.py | 2 ++ scripts/speak.py | 4 ++++ scripts/token_counter.py | 2 ++ tests/integration/memory_tests.py | 1 + tests/local_cache_test.py | 2 ++ tests/test_config.py | 1 + tests/test_json_parser.py | 1 + tests/unit/json_tests.py | 1 + 20 files changed, 47 insertions(+) diff --git a/scripts/agent_manager.py b/scripts/agent_manager.py index a0e5f164..191ab838 100644 --- a/scripts/agent_manager.py +++ b/scripts/agent_manager.py @@ -6,6 +6,7 @@ agents = {} # key, (task, full_message_history, model) # Create new GPT agent # TODO: Centralise use of create_chat_completion() to globally enforce token limit + def create_agent(task, prompt, model): """Create a new agent and return its key""" global next_key diff --git a/scripts/ai_config.py b/scripts/ai_config.py index bd373944..ee4b1fda 100644 --- a/scripts/ai_config.py +++ b/scripts/ai_config.py @@ -2,6 +2,7 @@ import yaml import data import os + class AIConfig: """ A class object that contains the configuration information for the AI diff --git a/scripts/browse.py b/scripts/browse.py index 9e93c55a..a5b167c9 100644 --- a/scripts/browse.py +++ b/scripts/browse.py @@ -21,12 +21,28 @@ def sanitize_url(url): return urljoin(url, urlparse(url).path) +# Function to make a request with a specified timeout and handle exceptions +def make_request(url, timeout=10): + try: + response = requests.get(url, headers=cfg.user_agent_header, timeout=timeout) + response.raise_for_status() + return response + except requests.exceptions.RequestException as e: + return "Error: " + str(e) + + # Define and check for local file address prefixes def check_local_file_access(url): local_prefixes = ['file:///', 'file://localhost', 'http://localhost', 'https://localhost'] return any(url.startswith(prefix) for prefix in local_prefixes) +def scrape_text(url): + """Scrape text from a webpage""" + # Basic check if the URL is valid + if not url.startswith('http'): + return "Error: Invalid URL" + def get_response(url, headers=cfg.user_agent_header, timeout=10): try: # Restrict access to local files diff --git a/scripts/call_ai_function.py b/scripts/call_ai_function.py index f8238658..6f1d6cee 100644 --- a/scripts/call_ai_function.py +++ b/scripts/call_ai_function.py @@ -3,6 +3,8 @@ from config import Config cfg = Config() from llm_utils import create_chat_completion + + # This is a magic function that can do anything with no-code. See # https://github.com/Torantulino/AI-Functions for more info. def call_ai_function(function, args, description, model=None): diff --git a/scripts/chat.py b/scripts/chat.py index e16cee38..2b7c34b5 100644 --- a/scripts/chat.py +++ b/scripts/chat.py @@ -9,6 +9,7 @@ import logging cfg = Config() + def create_chat_message(role, content): """ Create a chat message with the given role and content. diff --git a/scripts/commands.py b/scripts/commands.py index 3966e86a..fe6f6c30 100644 --- a/scripts/commands.py +++ b/scripts/commands.py @@ -24,6 +24,7 @@ def is_valid_int(value): except ValueError: return False + def get_command(response): """Parse the response and return the command name and arguments""" try: @@ -135,6 +136,7 @@ def google_search(query, num_results=8): return json.dumps(search_results, ensure_ascii=False, indent=4) + def google_official_search(query, num_results=8): """Return the results of a google search using the official Google API""" from googleapiclient.discovery import build @@ -171,6 +173,7 @@ def google_official_search(query, num_results=8): # Return the list of search result URLs return search_results_links + def browse_website(url, question): """Browse a website and return the summary and links""" summary = get_text_summary(url, question) diff --git a/scripts/data.py b/scripts/data.py index f80c2875..088fd51c 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -1,6 +1,7 @@ import os from pathlib import Path + def load_prompt(): """Load the prompt from data/prompt.txt""" try: diff --git a/scripts/file_operations.py b/scripts/file_operations.py index 7b48c134..2999bc24 100644 --- a/scripts/file_operations.py +++ b/scripts/file_operations.py @@ -65,6 +65,7 @@ def delete_file(filename): except Exception as e: return "Error: " + str(e) + def search_files(directory): found_files = [] diff --git a/scripts/image_gen.py b/scripts/image_gen.py index 4481696f..6c27df3f 100644 --- a/scripts/image_gen.py +++ b/scripts/image_gen.py @@ -11,6 +11,7 @@ cfg = Config() working_directory = "auto_gpt_workspace" + def generate_image(prompt): filename = str(uuid.uuid4()) + ".jpg" diff --git a/scripts/llm_utils.py b/scripts/llm_utils.py index 35cc5ce0..16739ddd 100644 --- a/scripts/llm_utils.py +++ b/scripts/llm_utils.py @@ -4,6 +4,7 @@ cfg = Config() openai.api_key = cfg.openai_api_key + # Overly simple abstraction until we create something better def create_chat_completion(messages, model=None, temperature=cfg.temperature, max_tokens=None)->str: """Create a chat completion using the OpenAI API""" diff --git a/scripts/logger.py b/scripts/logger.py index 85dde813..42a43878 100644 --- a/scripts/logger.py +++ b/scripts/logger.py @@ -151,6 +151,7 @@ class TypingConsoleHandler(logging.StreamHandler): except Exception: self.handleError(record) + class ConsoleHandler(logging.StreamHandler): def emit(self, record): msg = self.format(record) diff --git a/scripts/main.py b/scripts/main.py index 81f560b2..4a89e8e1 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -20,6 +20,7 @@ import logging cfg = Config() + def check_openai_api_key(): """Check if the OpenAI API key is set in config.py or as an environment variable.""" if not cfg.openai_api_key: @@ -30,6 +31,7 @@ def check_openai_api_key(): print("You can get your key from https://beta.openai.com/account/api-keys") exit(1) + def attempt_to_fix_json_by_finding_outermost_brackets(json_string): if cfg.speak_mode and cfg.debug_mode: speak.say_text("I have received an invalid JSON response from the OpenAI API. Trying to fix it now.") @@ -58,6 +60,7 @@ def attempt_to_fix_json_by_finding_outermost_brackets(json_string): return json_string + def print_assistant_thoughts(assistant_reply): """Prints the assistant's thoughts to the console""" global ai_name @@ -262,6 +265,7 @@ def prompt_user(): config = AIConfig(ai_name, ai_role, ai_goals) return config + def parse_arguments(): """Parses the arguments passed to the script""" global cfg diff --git a/scripts/memory/__init__.py b/scripts/memory/__init__.py index a07f9fd8..7eee1b3d 100644 --- a/scripts/memory/__init__.py +++ b/scripts/memory/__init__.py @@ -18,6 +18,7 @@ except ImportError: print("Pinecone not installed. Skipping import.") PineconeMemory = None + def get_memory(cfg, init=False): memory = None if cfg.memory_backend == "pinecone": @@ -41,6 +42,7 @@ def get_memory(cfg, init=False): memory.clear() return memory + def get_supported_memory_backends(): return supported_memory diff --git a/scripts/speak.py b/scripts/speak.py index 64054e3c..7a17873c 100644 --- a/scripts/speak.py +++ b/scripts/speak.py @@ -31,6 +31,7 @@ tts_headers = { mutex_lock = Lock() # Ensure only one sound is played at a time queue_semaphore = Semaphore(1) # The amount of sounds to queue before blocking the main thread + def eleven_labs_speech(text, voice_index=0): """Speak text using elevenlabs.io's API""" tts_url = "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}".format( @@ -51,6 +52,7 @@ def eleven_labs_speech(text, voice_index=0): print("Response content:", response.content) return False + def gtts_speech(text): tts = gtts.gTTS(text) with mutex_lock: @@ -58,6 +60,7 @@ def gtts_speech(text): playsound("speech.mp3", True) os.remove("speech.mp3") + def macos_tts_speech(text, voice_index=0): if voice_index == 0: os.system(f'say "{text}"') @@ -67,6 +70,7 @@ def macos_tts_speech(text, voice_index=0): else: os.system(f'say -v Samantha "{text}"') + def say_text(text, voice_index=0): def speak(): diff --git a/scripts/token_counter.py b/scripts/token_counter.py index 635d3286..8aecf168 100644 --- a/scripts/token_counter.py +++ b/scripts/token_counter.py @@ -1,6 +1,7 @@ import tiktoken from typing import List, Dict + def count_message_tokens(messages : List[Dict[str, str]], model : str = "gpt-3.5-turbo-0301") -> int: """ Returns the number of tokens used by a list of messages. @@ -41,6 +42,7 @@ def count_message_tokens(messages : List[Dict[str, str]], model : str = "gpt-3.5 num_tokens += 3 # every reply is primed with <|start|>assistant<|message|> return num_tokens + def count_string_tokens(string: str, model_name: str) -> int: """ Returns the number of tokens in a text string. diff --git a/tests/integration/memory_tests.py b/tests/integration/memory_tests.py index 5f1611be..d0c30962 100644 --- a/tests/integration/memory_tests.py +++ b/tests/integration/memory_tests.py @@ -8,6 +8,7 @@ sys.path.append(str(Path(__file__).resolve().parent.parent.parent / 'scripts')) from config import Config from memory.local import LocalCache + class TestLocalCache(unittest.TestCase): def random_string(self, length): diff --git a/tests/local_cache_test.py b/tests/local_cache_test.py index d1f1ef08..0352624e 100644 --- a/tests/local_cache_test.py +++ b/tests/local_cache_test.py @@ -4,6 +4,7 @@ import sys sys.path.append(os.path.abspath('../scripts')) from memory.local import LocalCache + def MockConfig(): return type('MockConfig', (object,), { 'debug_mode': False, @@ -12,6 +13,7 @@ def MockConfig(): 'memory_index': 'auto-gpt', }) + class TestLocalCache(unittest.TestCase): def setUp(self): diff --git a/tests/test_config.py b/tests/test_config.py index c1310b70..ba8381e1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,6 +1,7 @@ import unittest from scripts.config import Config + class TestConfig(unittest.TestCase): def test_singleton(self): diff --git a/tests/test_json_parser.py b/tests/test_json_parser.py index 0f2c6488..438e047b 100644 --- a/tests/test_json_parser.py +++ b/tests/test_json_parser.py @@ -3,6 +3,7 @@ import tests.context from scripts.json_parser import fix_and_parse_json + class TestParseJson(unittest.TestCase): def test_valid_json(self): # Test that a valid JSON string is parsed correctly diff --git a/tests/unit/json_tests.py b/tests/unit/json_tests.py index 3320ad5e..4f326721 100644 --- a/tests/unit/json_tests.py +++ b/tests/unit/json_tests.py @@ -5,6 +5,7 @@ import sys sys.path.append(os.path.abspath('../scripts')) from json_parser import fix_and_parse_json + class TestParseJson(unittest.TestCase): def test_valid_json(self): # Test that a valid JSON string is parsed correctly From 62edc148a8b43dfe4b30c5ca9de3c462cd366a46 Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Thu, 13 Apr 2023 10:56:02 +0200 Subject: [PATCH 34/55] chore: Remove functions that had been removed on the master branch recently --- scripts/browse.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/scripts/browse.py b/scripts/browse.py index a5b167c9..9e93c55a 100644 --- a/scripts/browse.py +++ b/scripts/browse.py @@ -21,28 +21,12 @@ def sanitize_url(url): return urljoin(url, urlparse(url).path) -# Function to make a request with a specified timeout and handle exceptions -def make_request(url, timeout=10): - try: - response = requests.get(url, headers=cfg.user_agent_header, timeout=timeout) - response.raise_for_status() - return response - except requests.exceptions.RequestException as e: - return "Error: " + str(e) - - # Define and check for local file address prefixes def check_local_file_access(url): local_prefixes = ['file:///', 'file://localhost', 'http://localhost', 'https://localhost'] return any(url.startswith(prefix) for prefix in local_prefixes) -def scrape_text(url): - """Scrape text from a webpage""" - # Basic check if the URL is valid - if not url.startswith('http'): - return "Error: Invalid URL" - def get_response(url, headers=cfg.user_agent_header, timeout=10): try: # Restrict access to local files From abe01ab81e0428b6b9cc1844df8e2130c9ffe3f6 Mon Sep 17 00:00:00 2001 From: Drikus Roor Date: Thu, 13 Apr 2023 11:05:36 +0200 Subject: [PATCH 35/55] fix: Fix flake8 linting errors --- scripts/execute_code.py | 1 + scripts/logger.py | 8 ++++---- scripts/memory/base.py | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/execute_code.py b/scripts/execute_code.py index 2c92903c..dbd62c22 100644 --- a/scripts/execute_code.py +++ b/scripts/execute_code.py @@ -67,6 +67,7 @@ def execute_python_file(file): except Exception as e: return f"Error: {str(e)}" + def execute_shell(command_line): current_dir = os.getcwd() diff --git a/scripts/logger.py b/scripts/logger.py index 42a43878..f5e94687 100644 --- a/scripts/logger.py +++ b/scripts/logger.py @@ -161,11 +161,11 @@ class ConsoleHandler(logging.StreamHandler): self.handleError(record) -''' -Allows to handle custom placeholders 'title_color' and 'message_no_color'. -To use this formatter, make sure to pass 'color', 'title' as log extras. -''' class AutoGptFormatter(logging.Formatter): + """ + Allows to handle custom placeholders 'title_color' and 'message_no_color'. + To use this formatter, make sure to pass 'color', 'title' as log extras. + """ def format(self, record: LogRecord) -> str: if (hasattr(record, 'color')): record.title_color = getattr(record, 'color') + getattr(record, 'title') + " " + Style.RESET_ALL diff --git a/scripts/memory/base.py b/scripts/memory/base.py index 1be7b3dd..96cf3df1 100644 --- a/scripts/memory/base.py +++ b/scripts/memory/base.py @@ -4,7 +4,6 @@ from config import AbstractSingleton, Config import openai cfg = Config() -cfg = Config() def get_ada_embedding(text): text = text.replace("\n", " ") From 0c7b7e5de8f99fb9254d54b327a4cfccb9b3ae57 Mon Sep 17 00:00:00 2001 From: digger-yu Date: Thu, 13 Apr 2023 18:43:32 +0800 Subject: [PATCH 36/55] Update test_json_parser.py Optimize part of the code to maintain uniformity --- tests/test_json_parser.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_json_parser.py b/tests/test_json_parser.py index b8cb2680..352cf3d4 100644 --- a/tests/test_json_parser.py +++ b/tests/test_json_parser.py @@ -13,12 +13,14 @@ class TestParseJson(unittest.TestCase): def test_invalid_json_minor(self): # Test that an invalid JSON string can be fixed with gpt json_str = '{"name": "John", "age": 30, "city": "New York",}' - self.assertRaises(Exception, fix_and_parse_json, json_str, try_to_fix_with_gpt=False) + with self.assertRaises(Exception): + fix_and_parse_json(json_str, try_to_fix_with_gpt=False) def test_invalid_json_major_with_gpt(self): # Test that an invalid JSON string raises an error when try_to_fix_with_gpt is False json_str = 'BEGIN: "name": "John" - "age": 30 - "city": "New York" :END' - self.assertRaises(Exception, fix_and_parse_json, json_str, try_to_fix_with_gpt=False) + with self.assertRaises(Exception): + fix_and_parse_json(json_str, try_to_fix_with_gpt=False) def test_invalid_json_major_without_gpt(self): # Test that a REALLY invalid JSON string raises an error when try_to_fix_with_gpt is False From f3fb8109798c0be88138d0c137212fdd19a33777 Mon Sep 17 00:00:00 2001 From: sagarishere <5121817+sagarishere@users.noreply.github.com> Date: Thu, 13 Apr 2023 14:37:56 +0300 Subject: [PATCH 37/55] Remove deprecated (404) links, and add alt-text to one image: Update README.md 1. Removed the link to Unit-tests as that link is deprecated and on clicking on it, it says, that workflow no longer exists. 2. Added alt text to the Discord link, following the convention from Twitter link alt text --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 87b5d1be..bee4dbc9 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ ![GitHub Repo stars](https://img.shields.io/github/stars/Torantulino/auto-gpt?style=social) ![Twitter Follow](https://img.shields.io/twitter/follow/siggravitas?style=social) -[![](https://dcbadge.vercel.app/api/server/PQ7VX6TY4t?style=flat)](https://discord.gg/PQ7VX6TY4t) -[![Unit Tests](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml) +[![Discord Follow](https://dcbadge.vercel.app/api/server/PQ7VX6TY4t?style=flat)](https://discord.gg/PQ7VX6TY4t) Auto-GPT is an experimental open-source application showcasing the capabilities of the GPT-4 language model. This program, driven by GPT-4, chains together LLM "thoughts", to autonomously achieve whatever goal you set. As one of the first examples of GPT-4 running fully autonomously, Auto-GPT pushes the boundaries of what is possible with AI. From ccfb568694ee6aa2bf2789ea8131a88bdb8ab0c2 Mon Sep 17 00:00:00 2001 From: sagarishere <5121817+sagarishere@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:08:23 +0300 Subject: [PATCH 38/55] Fix twitter link: in README.md Fixed twitter link to go to: https://twitter.com/SigGravitas Previously it was going to the icon image. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43d0ff72..f9e8d63d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Auto-GPT: An Autonomous GPT-4 Experiment ![GitHub Repo stars](https://img.shields.io/github/stars/Torantulino/auto-gpt?style=social) -![Twitter Follow](https://img.shields.io/twitter/follow/siggravitas?style=social) +[![Twitter Follow](https://img.shields.io/twitter/follow/siggravitas?style=social)](https://twitter.com/SigGravitas) [![Discord Follow](https://dcbadge.vercel.app/api/server/PQ7VX6TY4t?style=flat)](https://discord.gg/PQ7VX6TY4t) [![Unit Tests](https://github.com/Torantulino/Auto-GPT/actions/workflows/ci.yml/badge.svg)](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml) From dd15900804ea502fdca76077ea7bc30ebfaaa476 Mon Sep 17 00:00:00 2001 From: Yossi Marouani Date: Thu, 13 Apr 2023 17:19:02 +0300 Subject: [PATCH 39/55] temperature should not be an Int. it can be any value between 0-1 --- scripts/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index ebf1b08b..8cbc67fc 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -44,7 +44,7 @@ class Config(metaclass=Singleton): self.smart_token_limit = int(os.getenv("SMART_TOKEN_LIMIT", 8000)) self.openai_api_key = os.getenv("OPENAI_API_KEY") - self.temperature = int(os.getenv("TEMPERATURE", "1")) + self.temperature = float(os.getenv("TEMPERATURE", "1")) self.use_azure = False self.use_azure = os.getenv("USE_AZURE") == 'True' self.execute_local_commands = os.getenv('EXECUTE_LOCAL_COMMANDS', 'False') == 'True' From f7910e85ce8080602a02886712ebd8da0f1340a5 Mon Sep 17 00:00:00 2001 From: ShifraSec <48570596+MoElaSec@users.noreply.github.com> Date: Thu, 13 Apr 2023 18:33:20 +0400 Subject: [PATCH 40/55] Link to 11Labs website to obtain API_KEY --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43d0ff72..64e29864 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Your support is greatly appreciated Optional: -- ElevenLabs Key (If you want the AI to speak) +- [ElevenLabs Key](https://elevenlabs.io/) (If you want the AI to speak) ## 💾 Installation From 2f7a40204088b5c5c9e9eee5e0e7b4445105c28d Mon Sep 17 00:00:00 2001 From: "Joseph C. Miller, II" Date: Thu, 13 Apr 2023 08:49:22 -0600 Subject: [PATCH 41/55] Use yellow instead of red for termination message --- scripts/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/main.py b/scripts/main.py index e0ddc9fb..3c847eec 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -186,7 +186,7 @@ def construct_prompt(): if config.ai_name: logger.typewriter_log( f"Welcome back! ", - Fore.GREEN, + Fore.YELLOW, f"Would you like me to return to being {config.ai_name}?", speak_text=True) should_continue = utils.clean_input(f"""Continue with the last settings? From 2a623941127c03f900853ff201b75f5e40fc0adb Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Thu, 13 Apr 2023 07:56:56 -0700 Subject: [PATCH 42/55] add: execute shell command to prompt.py --- scripts/prompt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/prompt.py b/scripts/prompt.py index bbdfa5ec..286002ee 100644 --- a/scripts/prompt.py +++ b/scripts/prompt.py @@ -34,6 +34,7 @@ def get_prompt(): ("Get Improved Code", "improve_code", {"suggestions": "", "code": ""}), ("Write Tests", "write_tests", {"code": "", "focus": ""}), ("Execute Python File", "execute_python_file", {"file": ""}), + ("Execute Shell Command, non-interactive commands only", "execute_shell", { "command_line": ""}), ("Task Complete (Shutdown)", "task_complete", {"reason": ""}), ("Generate Image", "generate_image", {"prompt": ""}), ("Do Nothing", "do_nothing", {}), From c5188d561184db27e9ed2f71822d7c04cd9f6917 Mon Sep 17 00:00:00 2001 From: celthi Date: Thu, 13 Apr 2023 23:41:09 +0800 Subject: [PATCH 43/55] skip getting relevant memory if no message history --- scripts/chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/chat.py b/scripts/chat.py index e16cee38..afec2219 100644 --- a/scripts/chat.py +++ b/scripts/chat.py @@ -69,7 +69,7 @@ def chat_with_ai( logger.debug(f"Token limit: {token_limit}") send_token_limit = token_limit - 1000 - relevant_memory = permanent_memory.get_relevant(str(full_message_history[-9:]), 10) + relevant_memory = '' if len(full_message_history) ==0 else permanent_memory.get_relevant(str(full_message_history[-9:]), 10) logger.debug(f'Memory Stats: {permanent_memory.get_stats()}') From b112f5ebfafe2d488e2819dcf02b767e416f3919 Mon Sep 17 00:00:00 2001 From: Merwane Hamadi Date: Thu, 13 Apr 2023 05:57:21 -0700 Subject: [PATCH 44/55] put loop in in if main --- scripts/main.py | 219 +++++++++++++++++++++++++----------------------- 1 file changed, 112 insertions(+), 107 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 81f560b2..4f1b23ea 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -316,118 +316,123 @@ def parse_arguments(): cfg.memory_backend = chosen -# TODO: fill in llm values here -check_openai_api_key() -parse_arguments() -logger.set_level(logging.DEBUG if cfg.debug_mode else logging.INFO) -ai_name = "" -prompt = construct_prompt() -# print(prompt) -# Initialize variables -full_message_history = [] -result = None -next_action_count = 0 -# Make a constant: -user_input = "Determine which next command to use, and respond using the format specified above:" +def main(): + global ai_name, memory + # TODO: fill in llm values here + check_openai_api_key() + parse_arguments() + logger.set_level(logging.DEBUG if cfg.debug_mode else logging.INFO) + ai_name = "" + prompt = construct_prompt() + # print(prompt) + # Initialize variables + full_message_history = [] + result = None + next_action_count = 0 + # Make a constant: + user_input = "Determine which next command to use, and respond using the format specified above:" + # Initialize memory and make sure it is empty. + # this is particularly important for indexing and referencing pinecone memory + memory = get_memory(cfg, init=True) + print('Using memory of type: ' + memory.__class__.__name__) + # Interaction Loop + while True: + # Send message to AI, get response + with Spinner("Thinking... "): + assistant_reply = chat.chat_with_ai( + prompt, + user_input, + full_message_history, + memory, + cfg.fast_token_limit) # TODO: This hardcodes the model to use GPT3.5. Make this an argument -# Initialize memory and make sure it is empty. -# this is particularly important for indexing and referencing pinecone memory -memory = get_memory(cfg, init=True) -print('Using memory of type: ' + memory.__class__.__name__) + # Print Assistant thoughts + print_assistant_thoughts(assistant_reply) -# Interaction Loop -while True: - # Send message to AI, get response - with Spinner("Thinking... "): - assistant_reply = chat.chat_with_ai( - prompt, - user_input, - full_message_history, - memory, - cfg.fast_token_limit) # TODO: This hardcodes the model to use GPT3.5. Make this an argument + # Get command name and arguments + try: + command_name, arguments = cmd.get_command( + attempt_to_fix_json_by_finding_outermost_brackets(assistant_reply)) + if cfg.speak_mode: + speak.say_text(f"I want to execute {command_name}") + except Exception as e: + logger.error("Error: \n", str(e)) - # Print Assistant thoughts - print_assistant_thoughts(assistant_reply) - - # Get command name and arguments - try: - command_name, arguments = cmd.get_command(attempt_to_fix_json_by_finding_outermost_brackets(assistant_reply)) - if cfg.speak_mode: - speak.say_text(f"I want to execute {command_name}") - except Exception as e: - logger.error("Error: \n", str(e)) - - if not cfg.continuous_mode and next_action_count == 0: - ### GET USER AUTHORIZATION TO EXECUTE COMMAND ### - # Get key press: Prompt the user to press enter to continue or escape - # to exit - user_input = "" - logger.typewriter_log( - "NEXT ACTION: ", - Fore.CYAN, - f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}") - print( - f"Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for {ai_name}...", - flush=True) - while True: - console_input = utils.clean_input(Fore.MAGENTA + "Input:" + Style.RESET_ALL) - if console_input.lower().rstrip() == "y": - user_input = "GENERATE NEXT COMMAND JSON" - break - elif console_input.lower().startswith("y -"): - try: - next_action_count = abs(int(console_input.split(" ")[1])) - user_input = "GENERATE NEXT COMMAND JSON" - except ValueError: - print("Invalid input format. Please enter 'y -n' where n is the number of continuous tasks.") - continue - break - elif console_input.lower() == "n": - user_input = "EXIT" - break - else: - user_input = console_input - command_name = "human_feedback" - break - - if user_input == "GENERATE NEXT COMMAND JSON": + if not cfg.continuous_mode and next_action_count == 0: + ### GET USER AUTHORIZATION TO EXECUTE COMMAND ### + # Get key press: Prompt the user to press enter to continue or escape + # to exit + user_input = "" logger.typewriter_log( - "-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=", - Fore.MAGENTA, - "") - elif user_input == "EXIT": - print("Exiting...", flush=True) - break - else: - # Print command - logger.typewriter_log( - "NEXT ACTION: ", - Fore.CYAN, - f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}") + "NEXT ACTION: ", + Fore.CYAN, + f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}") + print( + f"Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for {ai_name}...", + flush=True) + while True: + console_input = utils.clean_input(Fore.MAGENTA + "Input:" + Style.RESET_ALL) + if console_input.lower().rstrip() == "y": + user_input = "GENERATE NEXT COMMAND JSON" + break + elif console_input.lower().startswith("y -"): + try: + next_action_count = abs(int(console_input.split(" ")[1])) + user_input = "GENERATE NEXT COMMAND JSON" + except ValueError: + print("Invalid input format. Please enter 'y -n' where n is the number of continuous tasks.") + continue + break + elif console_input.lower() == "n": + user_input = "EXIT" + break + else: + user_input = console_input + command_name = "human_feedback" + break - # Execute command - if command_name is not None and command_name.lower().startswith( "error" ): - result = f"Command {command_name} threw the following error: " + arguments - elif command_name == "human_feedback": - result = f"Human feedback: {user_input}" - else: - result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}" - if next_action_count > 0: - next_action_count -= 1 + if user_input == "GENERATE NEXT COMMAND JSON": + logger.typewriter_log( + "-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=", + Fore.MAGENTA, + "") + elif user_input == "EXIT": + print("Exiting...", flush=True) + break + else: + # Print command + logger.typewriter_log( + "NEXT ACTION: ", + Fore.CYAN, + f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}") - memory_to_add = f"Assistant Reply: {assistant_reply} " \ - f"\nResult: {result} " \ - f"\nHuman Feedback: {user_input} " + # Execute command + if command_name is not None and command_name.lower().startswith("error"): + result = f"Command {command_name} threw the following error: " + arguments + elif command_name == "human_feedback": + result = f"Human feedback: {user_input}" + else: + result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}" + if next_action_count > 0: + next_action_count -= 1 - memory.add(memory_to_add) + memory_to_add = f"Assistant Reply: {assistant_reply} " \ + f"\nResult: {result} " \ + f"\nHuman Feedback: {user_input} " - # Check if there's a result from the command append it to the message - # history - if result is not None: - full_message_history.append(chat.create_chat_message("system", result)) - logger.typewriter_log("SYSTEM: ", Fore.YELLOW, result) - else: - full_message_history.append( - chat.create_chat_message( - "system", "Unable to execute command")) - logger.typewriter_log("SYSTEM: ", Fore.YELLOW, "Unable to execute command") + memory.add(memory_to_add) + + # Check if there's a result from the command append it to the message + # history + if result is not None: + full_message_history.append(chat.create_chat_message("system", result)) + logger.typewriter_log("SYSTEM: ", Fore.YELLOW, result) + else: + full_message_history.append( + chat.create_chat_message( + "system", "Unable to execute command")) + logger.typewriter_log("SYSTEM: ", Fore.YELLOW, "Unable to execute command") + + +if __name__ == "__main__": + main() From d2f75e8659de28709ddb5839ee485e7918db4059 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 13 Apr 2023 17:23:16 +0100 Subject: [PATCH 45/55] Added simple retry on Open AI chat if a Rate Limit or 502 Bad Gateway error received --- scripts/llm_utils.py | 56 ++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/scripts/llm_utils.py b/scripts/llm_utils.py index 35cc5ce0..731acae2 100644 --- a/scripts/llm_utils.py +++ b/scripts/llm_utils.py @@ -1,26 +1,52 @@ +import time import openai +from colorama import Fore from config import Config + cfg = Config() openai.api_key = cfg.openai_api_key + # Overly simple abstraction until we create something better +# simple retry mechanism when getting a rate error or a bad gateway def create_chat_completion(messages, model=None, temperature=cfg.temperature, max_tokens=None)->str: """Create a chat completion using the OpenAI API""" - if cfg.use_azure: - response = openai.ChatCompletion.create( - deployment_id=cfg.get_azure_deployment_id_for_model(model), - model=model, - messages=messages, - temperature=temperature, - max_tokens=max_tokens - ) - else: - response = openai.ChatCompletion.create( - model=model, - messages=messages, - temperature=temperature, - max_tokens=max_tokens - ) + response = None + num_retries = 5 + for attempt in range(num_retries): + try: + if cfg.use_azure: + response = openai.ChatCompletion.create( + deployment_id=cfg.get_azure_deployment_id_for_model(model), + model=model, + messages=messages, + temperature=temperature, + max_tokens=max_tokens + ) + else: + response = openai.ChatCompletion.create( + model=model, + messages=messages, + temperature=temperature, + max_tokens=max_tokens + ) + break + except openai.error.RateLimitError: + if cfg.debug_mode: + print(Fore.RED + "Error: ", "API Rate Limit Reached. Waiting 20 seconds..." + Fore.RESET) + time.sleep(20) + except openai.error.APIError as e: + if e.http_status == 502: + if cfg.debug_mode: + print(Fore.RED + "Error: ", "API Bad gateway. Waiting 20 seconds..." + Fore.RESET) + time.sleep(20) + else: + raise + if attempt == num_retries - 1: + raise + + if response is None: + raise RuntimeError("Failed to get response after 5 retries") return response.choices[0].message["content"] From f98fba66577b426630faab9cd01cee41e932bb73 Mon Sep 17 00:00:00 2001 From: Richard Beales Date: Thu, 13 Apr 2023 17:33:22 +0100 Subject: [PATCH 46/55] Update README - Discord link and unit test link Use new url for discord, correct link to ci.yaml workflow. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 68acfe75..5e3197d2 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ ![GitHub Repo stars](https://img.shields.io/github/stars/Torantulino/auto-gpt?style=social) ![Twitter Follow](https://img.shields.io/twitter/follow/siggravitas?style=social) -[![Discord Follow](https://dcbadge.vercel.app/api/server/PQ7VX6TY4t?style=flat)](https://discord.gg/PQ7VX6TY4t) -[![Unit Tests](https://github.com/Torantulino/Auto-GPT/actions/workflows/ci.yml/badge.svg)](https://github.com/Torantulino/Auto-GPT/actions/workflows/unit_tests.yml) +[![Discord Follow](https://dcbadge.vercel.app/api/server/autogpt?style=flat)](https://discord.gg/autogpt) +[![Unit Tests](https://github.com/Torantulino/Auto-GPT/actions/workflows/ci.yml/badge.svg)](https://github.com/Torantulino/Auto-GPT/actions/workflows/ci.yml) Auto-GPT is an experimental open-source application showcasing the capabilities of the GPT-4 language model. This program, driven by GPT-4, chains together LLM "thoughts", to autonomously achieve whatever goal you set. As one of the first examples of GPT-4 running fully autonomously, Auto-GPT pushes the boundaries of what is possible with AI. From da247ca600dd0961d2ba8d3ea69819121f589468 Mon Sep 17 00:00:00 2001 From: Kory Becker Date: Thu, 13 Apr 2023 12:47:16 -0400 Subject: [PATCH 47/55] merge fix --- azure.yaml.template | 1 + scripts/config.py | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/azure.yaml.template b/azure.yaml.template index 852645ca..74ca797b 100644 --- a/azure.yaml.template +++ b/azure.yaml.template @@ -1,3 +1,4 @@ +azure_api_type: azure_ad azure_api_base: your-base-url-for-azure azure_api_version: api-version-for-azure azure_model_map: diff --git a/scripts/config.py b/scripts/config.py index 0270dbec..03d48dd4 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -45,18 +45,12 @@ class Config(metaclass=Singleton): self.openai_api_key = os.getenv("OPENAI_API_KEY") self.temperature = int(os.getenv("TEMPERATURE", "1")) - self.use_azure = False self.use_azure = os.getenv("USE_AZURE") == 'True' self.execute_local_commands = os.getenv('EXECUTE_LOCAL_COMMANDS', 'False') == 'True' if self.use_azure: - self.openai_api_base = os.getenv("OPENAI_AZURE_API_BASE") - self.openai_api_version = os.getenv("OPENAI_AZURE_API_VERSION") - self.openai_deployment_id = os.getenv("OPENAI_AZURE_DEPLOYMENT_ID") - self.azure_chat_deployment_id = os.getenv("OPENAI_AZURE_CHAT_DEPLOYMENT_ID") - self.azure_embeddigs_deployment_id = os.getenv("OPENAI_AZURE_EMBEDDINGS_DEPLOYMENT_ID") self.load_azure_config() - openai.api_type = os.getenv("OPENAI_API_TYPE", "azure") + openai.api_type = self.openai_api_type openai.api_base = self.openai_api_base openai.api_version = self.openai_api_version @@ -126,8 +120,9 @@ class Config(metaclass=Singleton): config_params = yaml.load(file, Loader=yaml.FullLoader) except FileNotFoundError: config_params = {} - self.openai_api_base = config_params.get("azure_api_base", "") - self.openai_api_version = config_params.get("azure_api_version", "") + self.openai_api_type = os.getenv("OPENAI_API_TYPE", config_params.get("azure_api_type", "azure")) + self.openai_api_base = os.getenv("OPENAI_AZURE_API_BASE", config_params.get("azure_api_base", "")) + self.openai_api_version = os.getenv("OPENAI_AZURE_API_VERSION", config_params.get("azure_api_version", "")) self.azure_model_to_deployment_id_map = config_params.get("azure_model_map", []) def set_continuous_mode(self, value: bool): From 53c00b4199d047cfcbf44146447c18ed0919795d Mon Sep 17 00:00:00 2001 From: Richard Beales Date: Thu, 13 Apr 2023 18:01:12 +0100 Subject: [PATCH 48/55] Hotfix - re-add missing cfg variable to memory/base --- scripts/memory/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/memory/base.py b/scripts/memory/base.py index 1d908531..1bb4e89f 100644 --- a/scripts/memory/base.py +++ b/scripts/memory/base.py @@ -3,6 +3,7 @@ import abc from config import AbstractSingleton, Config import openai +cfg = Config() def get_ada_embedding(text): text = text.replace("\n", " ") From 1da9dbe671fb6d876b7e8883c5ec06a88225adb5 Mon Sep 17 00:00:00 2001 From: "fabi.s" Date: Thu, 13 Apr 2023 19:05:23 +0200 Subject: [PATCH 49/55] remove output to set OpenAI API key in config.py --- scripts/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/main.py b/scripts/main.py index 68f9d10c..c08ba1b2 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -26,7 +26,7 @@ def check_openai_api_key(): if not cfg.openai_api_key: print( Fore.RED + - "Please set your OpenAI API key in config.py or as an environment variable." + "Please set your OpenAI API key in .env or as an environment variable." ) print("You can get your key from https://beta.openai.com/account/api-keys") exit(1) From 6bb4ca0bff34cfdf22b1e6bdb1b6b08d81c62e73 Mon Sep 17 00:00:00 2001 From: Andy Melnikov Date: Thu, 13 Apr 2023 19:32:35 +0200 Subject: [PATCH 50/55] Fix flake8 E302 --- scripts/memory/no_memory.py | 1 + scripts/memory/pinecone.py | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/memory/no_memory.py b/scripts/memory/no_memory.py index 45dbd734..830982f9 100644 --- a/scripts/memory/no_memory.py +++ b/scripts/memory/no_memory.py @@ -2,6 +2,7 @@ from typing import Optional, List, Any from memory.base import MemoryProviderSingleton + class NoMemory(MemoryProviderSingleton): def __init__(self, cfg): """ diff --git a/scripts/memory/pinecone.py b/scripts/memory/pinecone.py index fa21124b..20a905b3 100644 --- a/scripts/memory/pinecone.py +++ b/scripts/memory/pinecone.py @@ -5,6 +5,7 @@ from memory.base import MemoryProviderSingleton, get_ada_embedding from logger import logger from colorama import Fore, Style + class PineconeMemory(MemoryProviderSingleton): def __init__(self, cfg): pinecone_api_key = cfg.pinecone_api_key From f4ff62f0cb09fd04a1be359800983db7126b5327 Mon Sep 17 00:00:00 2001 From: Richard Beales Date: Thu, 13 Apr 2023 18:57:14 +0100 Subject: [PATCH 51/55] Flake8 linter fix E302 --- scripts/memory/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/memory/base.py b/scripts/memory/base.py index 1bb4e89f..4dbf6791 100644 --- a/scripts/memory/base.py +++ b/scripts/memory/base.py @@ -5,6 +5,7 @@ import openai cfg = Config() + def get_ada_embedding(text): text = text.replace("\n", " ") if cfg.use_azure: From 8186ccb56a52841bc859d1bcafffaba79c27d10a Mon Sep 17 00:00:00 2001 From: Alrik Olson <10505065+AlrikOlson@users.noreply.github.com> Date: Thu, 13 Apr 2023 11:36:48 -0700 Subject: [PATCH 52/55] formatting --- scripts/prompt.py | 5 +++-- tests/promptgenerator_tests.py | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/prompt.py b/scripts/prompt.py index 286002ee..188603a3 100644 --- a/scripts/prompt.py +++ b/scripts/prompt.py @@ -1,9 +1,10 @@ from promptgenerator import PromptGenerator + def get_prompt(): """ This function generates a prompt string that includes various constraints, commands, resources, and performance evaluations. - + Returns: str: The generated prompt string. """ @@ -58,5 +59,5 @@ def get_prompt(): # Generate the prompt string prompt_string = prompt_generator.generate_prompt_string() - + return prompt_string diff --git a/tests/promptgenerator_tests.py b/tests/promptgenerator_tests.py index ac5c3a79..181fdea6 100644 --- a/tests/promptgenerator_tests.py +++ b/tests/promptgenerator_tests.py @@ -7,6 +7,7 @@ import os sys.path.append(os.path.abspath("../scripts")) from promptgenerator import PromptGenerator + # Create a test class for the PromptGenerator, subclassed from unittest.TestCase class promptgenerator_tests(unittest.TestCase): @@ -81,7 +82,7 @@ class promptgenerator_tests(unittest.TestCase): self.assertIn(constraint, prompt_string) for command in commands: self.assertIn(command["name"], prompt_string) - + # Check for each key-value pair in the command args dictionary for key, value in command["args"].items(): self.assertIn(f'"{key}": "{value}"', prompt_string) @@ -94,6 +95,7 @@ class promptgenerator_tests(unittest.TestCase): self.assertIn("resources", prompt_string.lower()) self.assertIn("performance evaluation", prompt_string.lower()) + # Run the tests when this script is executed if __name__ == '__main__': unittest.main() From 95b93045be17bb7205f37bb6fa28ab9d6124093c Mon Sep 17 00:00:00 2001 From: "Joseph C. Miller, II" Date: Thu, 13 Apr 2023 13:16:14 -0600 Subject: [PATCH 53/55] Exit message should be yellow --- scripts/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/main.py b/scripts/main.py index 59719130..0856648e 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -357,7 +357,7 @@ def main(): # Discontinue if continuous limit is reached loop_count += 1 if cfg.continuous_mode and cfg.continuous_limit > 0 and loop_count > cfg.continuous_limit: - logger.typewriter_log("Continuous Limit Reached: ", Fore.RED, f"{cfg.continuous_limit}") + logger.typewriter_log("Continuous Limit Reached: ", Fore.YELLOW, f"{cfg.continuous_limit}") break # Send message to AI, get response From f3e973950128f5a61d23c726b93f6d312a3ab123 Mon Sep 17 00:00:00 2001 From: "Joseph C. Miller, II" Date: Thu, 13 Apr 2023 13:35:46 -0600 Subject: [PATCH 54/55] Revert inadvertent change --- scripts/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/main.py b/scripts/main.py index 0856648e..08b73d64 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -189,7 +189,7 @@ def construct_prompt(): if config.ai_name: logger.typewriter_log( f"Welcome back! ", - Fore.YELLOW, + Fore.GREEN, f"Would you like me to return to being {config.ai_name}?", speak_text=True) should_continue = utils.clean_input(f"""Continue with the last settings? From 439e736b8ba2c8e676b321695b032cac2561b50e Mon Sep 17 00:00:00 2001 From: Sma Das Date: Thu, 13 Apr 2023 17:00:03 -0400 Subject: [PATCH 55/55] Removed unneeded imports --- scripts/ai_functions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/ai_functions.py b/scripts/ai_functions.py index 8c95c0f2..f4ee79cd 100644 --- a/scripts/ai_functions.py +++ b/scripts/ai_functions.py @@ -1,8 +1,7 @@ -from typing import List, Optional +from typing import List import json from config import Config from call_ai_function import call_ai_function -from json_parser import fix_and_parse_json cfg = Config()