diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 070df794..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 + 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 b8d59b94..b5a36b18 100644 --- a/README.md +++ b/README.md @@ -77,32 +77,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. - If you want to use GPT on an Azure instance, set `USE_AZURE` to `True` and then: @@ -370,11 +370,13 @@ 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,E231,E302`. See the [flake8 rules](https://www.flake8rules.com/) for more information. + +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,E302 +``` \ No newline at end of file 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/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/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/config.py b/scripts/config.py index 516a2bd1..14e094d5 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -45,13 +45,12 @@ class Config(metaclass=Singleton): self.openai_api_key = os.getenv("OPENAI_API_KEY") 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' if self.use_azure: self.load_azure_config() - 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 @@ -83,7 +82,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", "") @@ -131,8 +130,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): 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/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/file_operations.py b/scripts/file_operations.py index d0fa175f..3bbe9da6 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 3d131dd9..91bdb6f6 100644 --- a/scripts/logger.py +++ b/scripts/logger.py @@ -157,6 +157,7 @@ class TypingConsoleHandler(logging.StreamHandler): except Exception: self.handleError(record) + class ConsoleHandler(logging.StreamHandler): def emit(self, record): msg = self.format(record) @@ -166,11 +167,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/main.py b/scripts/main.py index 5b84bd70..c08ba1b2 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -20,16 +20,18 @@ 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: 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) + 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 @@ -316,118 +320,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() diff --git a/scripts/memory/__init__.py b/scripts/memory/__init__.py index 0386f688..7535d091 100644 --- a/scripts/memory/__init__.py +++ b/scripts/memory/__init__.py @@ -57,6 +57,7 @@ def get_memory(cfg, init=False): memory.clear() return memory + def get_supported_memory_backends(): return supported_memory diff --git a/scripts/memory/base.py b/scripts/memory/base.py index 1bb4e89f..1d908531 100644 --- a/scripts/memory/base.py +++ b/scripts/memory/base.py @@ -3,7 +3,6 @@ import abc from config import AbstractSingleton, Config import openai -cfg = Config() def get_ada_embedding(text): text = text.replace("\n", " ") 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 352cf3d4..c403c73d 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 @@ -52,7 +53,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } }, @@ -91,7 +92,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..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 @@ -52,7 +53,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } }, @@ -91,7 +92,7 @@ class TestParseJson(unittest.TestCase): good_obj = { "command": { "name": "browse_website", - "args":{ + "args": { "url": "https://github.com/Torantulino/Auto-GPT" } },