From 7d3e5b24f05297d2ed4497851ec98798ff575345 Mon Sep 17 00:00:00 2001 From: Charles Packer Date: Fri, 22 Dec 2023 01:21:25 -0800 Subject: [PATCH] feat: further simplify setup flow (#673) * made quickstart to openai or memgpt the default option when the user doesn't have a config set * modified formatting + message styles * revised quickstart guides in docs to talk about quickstart command * make message consistent --------- Co-authored-by: Sarah Wooders --- docs/quickstart.md | 34 ++++++++++------- memgpt/cli/cli.py | 95 +++++++++++++++++++++++++++++++++------------- 2 files changed, 90 insertions(+), 39 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index 4f02323c7a..dad5bde808 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -7,36 +7,44 @@ category: 6580d34ee5e4d00068bf2a1d ### Installation To install MemGPT, make sure you have Python installed on your computer, then run: - ```sh pip install pymemgpt ``` If you already have MemGPT installed, you can update to the latest version with: - ```sh pip install pymemgpt -U ``` -### Running MemGPT using the OpenAI API - -Add your OpenAI API key to your environment: +### Running MemGPT +Now, you can run MemGPT and start chatting with a MemGPT agent with: ```sh -export OPENAI_API_KEY=YOUR_API_KEY # on Linux/Mac -set OPENAI_API_KEY=YOUR_API_KEY # on Windows -$Env:OPENAI_API_KEY = "YOUR_API_KEY" # on Windows (PowerShell) +memgpt run ``` -Configure default settings for MemGPT by running: + +If you're running MemGPT for the first time, you'll see two quickstart options: + +1. **OpenAI**: select this if you'd like to run MemGPT with OpenAI models like GPT-4 (requires an OpenAI API key) +2. **MemGPT Free Endpoint**: select this if you'd like to try MemGPT on a top open LLM for free (currently variants of Mixtral 8x7b!) + +Neither of these options require you to have an LLM running on your own machine. If you'd like to run MemGPT with your custom LLM setup (or on OpenAI Azure), select **Other** to proceed to the advanced setup. + +### Quickstart + +If you'd ever like to quickly switch back to the default **OpenAI** or **MemGPT Free Endpoint** options, you can use the `quickstart` command: ```sh -memgpt configure +# this will set you up on the MemGPT Free Endpoint +memgpt quickstart ``` -Now, you can run MemGPT with: ```sh -memgpt run +# this will set you up on the default OpenAI settings +memgpt quickstart --backend openai ``` -In this example we use the OpenAI API, but you can run MemGPT with other backends! See: +### Advanced setup + +MemGPT supports a large number of LLM backends! See: * [Running MemGPT on OpenAI Azure and custom OpenAI endpoints](endpoints) * [Running MemGPT with your own LLMs (Llama 2, Mistral 7B, etc.)](local_llm) diff --git a/memgpt/cli/cli.py b/memgpt/cli/cli.py index 3638efbc39..a8262f42d1 100644 --- a/memgpt/cli/cli.py +++ b/memgpt/cli/cli.py @@ -32,7 +32,7 @@ class QuickstartChoice(Enum): memgpt_hosted = "memgpt" -def set_config_with_dict(new_config: dict): +def set_config_with_dict(new_config: dict) -> bool: """Set the base config using a dict""" from memgpt.utils import printd @@ -51,25 +51,30 @@ def set_config_with_dict(new_config: dict): if modified: printd(f"Saving new config file.") old_config.save() - typer.secho(f"\nMemGPT configuration file updated!", fg=typer.colors.GREEN) - typer.secho('Run "memgpt run" to create an agent with the new config.', fg=typer.colors.YELLOW) + typer.secho(f"šŸ“– MemGPT configuration file updated!", fg=typer.colors.GREEN) + typer.secho(f"šŸ§  model\t-> {old_config.model}\nšŸ–„ļø endpoint\t-> {old_config.model_endpoint}", fg=typer.colors.GREEN) + return True else: - typer.secho(f"\nMemGPT configuration file unchanged.", fg=typer.colors.GREEN) - typer.secho('Run "memgpt run" to create an agent.', fg=typer.colors.YELLOW) + typer.secho(f"šŸ“– MemGPT configuration file unchanged.", fg=typer.colors.WHITE) + typer.secho(f"šŸ§  model\t-> {old_config.model}\nšŸ–„ļø endpoint\t-> {old_config.model_endpoint}", fg=typer.colors.WHITE) + return False def quickstart( backend: QuickstartChoice = typer.Option("memgpt", help="Quickstart setup backend"), latest: bool = typer.Option(False, "--latest", help="Use --latest to pull the latest config from online"), debug: bool = typer.Option(False, "--debug", help="Use --debug to enable debugging output"), + terminal: bool = True, ): """Set the base config file with a single command""" + # setup logger utils.DEBUG = debug logging.getLogger().setLevel(logging.CRITICAL) if debug: logging.getLogger().setLevel(logging.DEBUG) + config_was_modified = False if backend == QuickstartChoice.memgpt_hosted: # if latest, try to pull the config from the repo # fallback to using local @@ -83,10 +88,10 @@ def quickstart( # Parse the response content as JSON config = response.json() # Output a success message and the first few items in the dictionary as a sample - print("JSON config file downloaded successfully.") - set_config_with_dict(config) + printd("JSON config file downloaded successfully.") + config_was_modified = set_config_with_dict(config) else: - print(f"Failed to download config from {url}. Status code:", response.status_code) + typer.secho(f"Failed to download config from {url}. Status code: {response.status_code}", fg=typer.colors.RED) # Load the file from the relative path script_dir = os.path.dirname(__file__) # Get the directory where the script is located @@ -94,10 +99,11 @@ def quickstart( try: with open(backup_config_path, "r") as file: backup_config = json.load(file) - print("Loaded backup config file successfully.") - set_config_with_dict(backup_config) + printd("Loaded backup config file successfully.") + config_was_modified = set_config_with_dict(backup_config) except FileNotFoundError: - print(f"Backup config file not found at {backup_config_path}") + typer.secho(f"Backup config file not found at {backup_config_path}", fg=typer.colors.RED) + return else: # Load the file from the relative path script_dir = os.path.dirname(__file__) # Get the directory where the script is located @@ -105,10 +111,11 @@ def quickstart( try: with open(backup_config_path, "r") as file: backup_config = json.load(file) - print("Loaded config file successfully.") - set_config_with_dict(backup_config) + printd("Loaded config file successfully.") + config_was_modified = set_config_with_dict(backup_config) except FileNotFoundError: - print(f"Config file not found at {backup_config_path}") + typer.secho(f"Config file not found at {backup_config_path}", fg=typer.colors.RED) + return elif backend == QuickstartChoice.openai: # Make sure we have an API key @@ -131,9 +138,9 @@ def quickstart( print("JSON config file downloaded successfully.") # Add the API key config["openai_key"] = api_key - set_config_with_dict(config) + config_was_modified = set_config_with_dict(config) else: - print(f"Failed to download config from {url}. Status code:", response.status_code) + typer.secho(f"Failed to download config from {url}. Status code: {response.status_code}", fg=typer.colors.RED) # Load the file from the relative path script_dir = os.path.dirname(__file__) # Get the directory where the script is located @@ -142,10 +149,11 @@ def quickstart( with open(backup_config_path, "r") as file: backup_config = json.load(file) backup_config["openai_key"] = api_key - print("Loaded backup config file successfully.") - set_config_with_dict(backup_config) + printd("Loaded backup config file successfully.") + config_was_modified = set_config_with_dict(backup_config) except FileNotFoundError: - print(f"Backup config file not found at {backup_config_path}") + typer.secho(f"Backup config file not found at {backup_config_path}", fg=typer.colors.RED) + return else: # Load the file from the relative path script_dir = os.path.dirname(__file__) # Get the directory where the script is located @@ -154,14 +162,22 @@ def quickstart( with open(backup_config_path, "r") as file: backup_config = json.load(file) backup_config["openai_key"] = api_key - print("Loaded config file successfully.") - set_config_with_dict(backup_config) + printd("Loaded config file successfully.") + config_was_modified = set_config_with_dict(backup_config) except FileNotFoundError: - print(f"Config file not found at {backup_config_path}") + typer.secho(f"Config file not found at {backup_config_path}", fg=typer.colors.RED) + return else: raise NotImplementedError(backend) + # 'terminal' = quickstart was run alone, in which case we should guide the user on the next command + if terminal: + if config_was_modified: + typer.secho('āš” Run "memgpt run" to create an agent with the new config.', fg=typer.colors.YELLOW) + else: + typer.secho('āš” Run "memgpt run" to create an agent.', fg=typer.colors.YELLOW) + def open_folder(): """Open a folder viewer of the MemGPT home directory""" @@ -281,14 +297,41 @@ def run( if debug: logging.getLogger().setLevel(logging.DEBUG) - if not MemGPTConfig.exists(): # if no config, run configure + if not MemGPTConfig.exists(): + # if no config, ask about quickstart + # do you want to do: + # - openai (run quickstart) + # - memgpt hosted (run quickstart) + # - other (run configure) if yes: - # use defaults + # if user is passing '-y' to bypass all inputs, use memgpt hosted + # since it can't fail out if you don't have an API key + quickstart(backend=QuickstartChoice.memgpt_hosted) config = MemGPTConfig() + else: - # use input - configure() + config_choices = { + "memgpt": "Use the free MemGPT endpoints", + "openai": "Use OpenAI (requires an OpenAI API key)", + "other": "Other (OpenAI Azure, custom LLM endpoint, etc)", + } + config_selection = questionary.select( + "How would you like to set up MemGPT?", + choices=list(config_choices.values()), + default=config_choices["memgpt"], + ).ask() + + if config_selection == config_choices["memgpt"]: + quickstart(backend=QuickstartChoice.memgpt_hosted, debug=debug, terminal=False) + elif config_selection == config_choices["openai"]: + quickstart(backend=QuickstartChoice.openai, debug=debug, terminal=False) + elif config_selection == config_choices["other"]: + configure() + else: + raise ValueError(config_selection) + config = MemGPTConfig.load() + else: # load config config = MemGPTConfig.load()