From 64c7c6a53698e6bbea974c786b54cb980431b002 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 17:00:15 -0700 Subject: [PATCH 01/24] Validates registry name --- examples/commands.ipynb | 127 +++++++++--------- .../jupyter_ai_magics/magics.py | 35 +++++ 2 files changed, 95 insertions(+), 67 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 76634cee8..bc47e54bf 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -181,7 +181,7 @@ ], "text/plain": [ "ai21\n", - "Requires environment variable AI21_API_KEY (set)\n", + "Requires environment variable AI21_API_KEY (not set)\n", "* ai21:j1-large\n", "* ai21:j1-grande\n", "* ai21:j1-jumbo\n", @@ -193,7 +193,7 @@ "* ai21:j2-jumbo-instruct\n", "\n", "anthropic\n", - "Requires environment variable ANTHROPIC_API_KEY (set)\n", + "Requires environment variable ANTHROPIC_API_KEY (not set)\n", "* anthropic:claude-v1\n", "* anthropic:claude-v1.0\n", "* anthropic:claude-v1.2\n", @@ -201,16 +201,16 @@ "* anthropic:claude-instant-v1.0\n", "\n", "cohere\n", - "Requires environment variable COHERE_API_KEY (set)\n", + "Requires environment variable COHERE_API_KEY (not set)\n", "* cohere:medium\n", "* cohere:xlarge\n", "\n", "huggingface_hub\n", - "Requires environment variable HUGGINGFACEHUB_API_TOKEN (set)\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (not set)\n", "* This provider does not define a list of models.\n", "\n", "openai\n", - "Requires environment variable OPENAI_API_KEY (set)\n", + "Requires environment variable OPENAI_API_KEY (not set)\n", "* openai:text-davinci-003\n", "* openai:text-davinci-002\n", "* openai:text-curie-001\n", @@ -222,7 +222,7 @@ "* openai:ada\n", "\n", "openai-chat\n", - "Requires environment variable OPENAI_API_KEY (set)\n", + "Requires environment variable OPENAI_API_KEY (not set)\n", "* openai-chat:gpt-4\n", "* openai-chat:gpt-4-0314\n", "* openai-chat:gpt-4-32k\n", @@ -264,11 +264,11 @@ "text/markdown": [ "| Provider | Environment variable | Set? | Models |\n", "|----------|----------------------|------|--------|\n", - "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n" + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n" ], "text/plain": [ "openai\n", - "Requires environment variable OPENAI_API_KEY (set)\n", + "Requires environment variable OPENAI_API_KEY (not set)\n", "* openai:text-davinci-003\n", "* openai:text-davinci-002\n", "* openai:text-curie-001\n", @@ -292,27 +292,32 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "b56ff0e3-42c2-4927-affd-be6a089dfa43", "metadata": {}, "outputs": [ { - "ename": "SyntaxError", - "evalue": "Missing parentheses in call to 'print'. Did you mean print(...)? (1142230402.py, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m Cell \u001b[0;32mIn[7], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m print 'foo'\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m Missing parentheses in call to 'print'. Did you mean print(...)?\n" - ] + "data": { + "text/markdown": [ + "Usage: `%ai register NAME CHAIN`" + ], + "text/plain": [ + "Usage: %ai register NAME CHAIN\n" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "print 'foo'" + "%ai register foo" ] }, { "cell_type": "code", - "execution_count": 8, - "id": "63581a74-9237-4f11-aff2-48612c97cb27", + "execution_count": 7, + "id": "f1400b59-5783-454a-b8ad-f69b2c7a7178", "metadata": { "tags": [] }, @@ -320,89 +325,77 @@ { "data": { "text/markdown": [ - "The error message \"SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?\", occurs when attempting to use the print function without parentheses in Python 3, which is not syntactically valid. In Python 2, it was possible to use the print statement without parentheses, but in Python 3 it has become a function and its use requires parentheses. The error message suggests that the print statement should be replaced with print() to rectify the error." + "Registry name is valid" ], "text/plain": [ - "" + "Registry name is valid" ] }, - "execution_count": 8, - "metadata": { - "text/markdown": { - "jupyter_ai": { - "model_id": "gpt-3.5-turbo", - "provider_id": "openai-chat" - } - } - }, + "execution_count": 7, + "metadata": {}, "output_type": "execute_result" } ], "source": [ - "%ai error chatgpt" + "%ai register foo bar" ] }, { "cell_type": "code", "execution_count": 9, - "id": "1afe4536-f908-4bd7-aec4-f8d1cc3bf01f", + "id": "c4ff8026-7423-4e40-96bd-cd96ef2b8003", "metadata": { "tags": [] }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/langchain/llms/anthropic.py:134: UserWarning: This Anthropic LLM is deprecated. Please use `from langchain.chat_models import ChatAnthropic` instead\n", - " warnings.warn(\n" - ] - }, { "data": { "text/markdown": [ - "\n", - "The error `Cell In[7], line 1 print 'foo' ^ SyntaxError: Missing parentheses in call to 'print' . Did you mean print(...)?` \n", - "is occurring because in Python 3, the `print` statement has changed. \n", - "\n", - "In Python 2, you could simply do:\n", - "`print 'foo'`\n", - "\n", - "to print the string `foo`. \n", - "\n", - "However, in Python 3, the `print` function requires parentheses:\n", - "`print('foo')`\n", - "\n", - "So the error is telling you that you're trying to use the Python 2 `print` statement in Python 3 code. \n", - "It's suggesting that you likely meant to call the `print()` function instead, with parentheses: \n", - "`print('foo')`.\n", - "\n", - "Adding the parentheses will fix the error." + "Unable to create a new entry with name list: This name is reserved for a command" ], "text/plain": [ - "" + "Unable to create a new entry with name list: This name is reserved for a command" ] }, "execution_count": 9, - "metadata": { - "text/markdown": { - "jupyter_ai": { - "model_id": "claude-v1.2", - "provider_id": "anthropic" - } - } + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai register list bar" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b77706d7-0c3a-409d-b909-d9f58d35ce4e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "Unable to create a new entry with name foo:bar: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" + ], + "text/plain": [ + "Unable to create a new entry with name foo:bar: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" + ] }, + "execution_count": 10, + "metadata": {}, "output_type": "execute_result" } ], "source": [ - "%ai error anthropic:claude-v1.2" + "%ai register foo:bar baz" ] }, { "cell_type": "code", "execution_count": null, - "id": "d47aa5ec-31e0-4670-b1d1-6b4cd7f75832", + "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [], "source": [] @@ -424,7 +417,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.10.11" } }, "nbformat": 4, diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index bc1f9b362..981d17d66 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -119,6 +119,9 @@ def __init__(self, shell): "`from langchain.chat_models import ChatOpenAI`") self.providers = load_providers() + + # initialize a registry of custom model/chain names + self.custom_model_registry = {} def _ai_bulleted_list_models_for_provider(self, provider_id, Provider): @@ -184,7 +187,39 @@ def _ai_env_status_for_provider_text(self, provider_id): output += "(not set)" return output + "\n" + + # Returns any error + def _validate_register_name(self, register_name): + # Existing command names are not allowed + if (register_name in AI_COMMANDS): + return 'This name is reserved for a command' + + # Existing registered names are not allowed + if (register_name in self.custom_model_registry): + # TODO: Recommend 'update' command + return 'This name is already associated with a custom model' + + # A registry name contains ASCII letters, numbers, hyphens, underscores, + # and periods. No other characters, including a colon, are permitted + acceptable_name = re.compile('^[a-zA-Z0-9._-]+$') + if (acceptable_name.match(register_name)): + return None # No error + else: + return ('A registry name may contain ASCII letters, numbers, hyphens, underscores, ' + + 'and periods. No other characters, including a colon, are permitted') + def _ai_register_command_markdown(self, register_name, variable_name): + # TODO: Write this method + return self._ai_register_command_text(register_name, variable_name) + + def _ai_register_command_text(self, register_name, variable_name): + output = 'Registry name is valid' + + register_name_errors = self._validate_register_name(register_name) + if (register_name_errors is not None): + output = f"Unable to create a new entry with name {register_name}: {register_name_errors}" + + return output def _ai_list_command_markdown(self, single_provider=None): output = ("| Provider | Environment variable | Set? | Models |\n" From 877d09aa4f79637dbfed25422108d784c6b31702 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 17:34:51 -0700 Subject: [PATCH 02/24] WIP: Register alias --- examples/commands.ipynb | 209 ++++++++++++------ .../jupyter_ai_magics/magics.py | 36 ++- 2 files changed, 178 insertions(+), 67 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index bc47e54bf..953aa494a 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -43,58 +43,23 @@ }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Usage: %%ai [OPTIONS] MODEL_ID\n", - "\n", - " Invokes a language model identified by MODEL_ID, with the prompt being\n", - " contained in all lines after the first. Both local model IDs and global\n", - " model IDs (with the provider ID explicitly prefixed, followed by a colon)\n", - " are accepted.\n", - "\n", - " To view available language models, please run `%ai list`.\n", - "\n", - "Options:\n", - " -f, --format [code|html|image|json|markdown|math|md|text]\n", - " IPython display to use when rendering\n", - " output. [default=\"markdown\"]\n", - " -r, --reset Clears the conversation transcript used when\n", - " interacting with an OpenAI chat model\n", - " provider. Does nothing with other providers.\n", - " --help Show this message and exit.\n", - "------------------------------------------------------------------------------\n", - "Usage: %%ai [OPTIONS] MODEL_ID\n", - "\n", - " Invokes a language model identified by MODEL_ID, with the prompt being\n", - " contained in all lines after the first. Both local model IDs and global\n", - " model IDs (with the provider ID explicitly prefixed, followed by a colon)\n", - " are accepted.\n", - "\n", - " To view available language models, please run `%ai list`.\n", - "\n", - "Options:\n", - " -f, --format [code|html|image|json|markdown|math|md|text]\n", - " IPython display to use when rendering\n", - " output. [default=\"markdown\"]\n", - " -r, --reset Clears the conversation transcript used when\n", - " interacting with an OpenAI chat model\n", - " provider. Does nothing with other providers.\n", - " --help Show this message and exit.\n", - "------------------------------------------------------------------------------\n", - "Usage: %ai [OPTIONS] COMMAND [ARGS]...\n", - "\n", - " Invokes a subcommand.\n", - "\n", - "Options:\n", - " --help Show this message and exit.\n", - "\n", - "Commands:\n", - " error Explains the most recent error.\n", - " help Show this message and exit.\n", - " list List language models. See `%ai list --help` for options.\n", - "\n" - ] + "data": { + "text/markdown": [ + "| Command | Description |\n", + "| ------- | ----------- |\n", + "| `help` | Display a list of supported commands|\n", + "| `list` | Display a list of models that you can use (optionally, for a single provider)|\n", + "| `register` | Add a custom LangChain chain or alias to a model for use with %ai magic commands.Usage: `%ai register NAME CHAIN_OR_MODEL`|\n" + ], + "text/plain": [ + "help - Display a list of supported commands\n", + "list - Display a list of models that you can use (optionally, for a single provider)\n", + "register - Add a custom LangChain chain or alias to a model for use with %ai magic commands.Usage: `%ai register NAME CHAIN_OR_MODEL`\n" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -292,20 +257,20 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "b56ff0e3-42c2-4927-affd-be6a089dfa43", "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "Usage: `%ai register NAME CHAIN`" + "Usage: `%ai register NAME CHAIN_OR_MODEL`" ], "text/plain": [ - "Usage: %ai register NAME CHAIN\n" + "Usage: %ai register NAME CHAIN_OR_MODEL\n" ] }, - "execution_count": 6, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -316,7 +281,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "id": "f1400b59-5783-454a-b8ad-f69b2c7a7178", "metadata": { "tags": [] @@ -331,7 +296,7 @@ "Registry name is valid" ] }, - "execution_count": 7, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -342,7 +307,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 5, "id": "c4ff8026-7423-4e40-96bd-cd96ef2b8003", "metadata": { "tags": [] @@ -357,7 +322,7 @@ "Unable to create a new entry with name list: This name is reserved for a command" ] }, - "execution_count": 9, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -368,7 +333,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 6, "id": "b77706d7-0c3a-409d-b909-d9f58d35ce4e", "metadata": { "tags": [] @@ -383,7 +348,7 @@ "Unable to create a new entry with name foo:bar: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" ] }, - "execution_count": 10, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -394,9 +359,127 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "Registry name is valid" + ], + "text/plain": [ + "Registry name is valid" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai register mychat openai-chat:gpt-4" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "| Provider | Environment variable | Set? | Models |\n", + "|----------|----------------------|------|--------|\n", + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "\n", + "Aliases:\n", + "\n", + "| Name | Target |\n", + "| `gpt2` | `huggingface_hub:gpt2` |\n", + "| `gpt3` | `openai:text-davinci-003` |\n", + "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", + "| `gpt4` | `openai-chat:gpt-4` |\n" + ], + "text/plain": [ + "ai21\n", + "Requires environment variable AI21_API_KEY (not set)\n", + "* ai21:j1-large\n", + "* ai21:j1-grande\n", + "* ai21:j1-jumbo\n", + "* ai21:j1-grande-instruct\n", + "* ai21:j2-large\n", + "* ai21:j2-grande\n", + "* ai21:j2-jumbo\n", + "* ai21:j2-grande-instruct\n", + "* ai21:j2-jumbo-instruct\n", + "\n", + "anthropic\n", + "Requires environment variable ANTHROPIC_API_KEY (not set)\n", + "* anthropic:claude-v1\n", + "* anthropic:claude-v1.0\n", + "* anthropic:claude-v1.2\n", + "* anthropic:claude-instant-v1\n", + "* anthropic:claude-instant-v1.0\n", + "\n", + "cohere\n", + "Requires environment variable COHERE_API_KEY (not set)\n", + "* cohere:medium\n", + "* cohere:xlarge\n", + "\n", + "huggingface_hub\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (not set)\n", + "* This provider does not define a list of models.\n", + "\n", + "openai\n", + "Requires environment variable OPENAI_API_KEY (not set)\n", + "* openai:text-davinci-003\n", + "* openai:text-davinci-002\n", + "* openai:text-curie-001\n", + "* openai:text-babbage-001\n", + "* openai:text-ada-001\n", + "* openai:davinci\n", + "* openai:curie\n", + "* openai:babbage\n", + "* openai:ada\n", + "\n", + "openai-chat\n", + "Requires environment variable OPENAI_API_KEY (not set)\n", + "* openai-chat:gpt-4\n", + "* openai-chat:gpt-4-0314\n", + "* openai-chat:gpt-4-32k\n", + "* openai-chat:gpt-4-32k-0314\n", + "* openai-chat:gpt-3.5-turbo\n", + "* openai-chat:gpt-3.5-turbo-0301\n", + "\n", + "sagemaker-endpoint\n", + "* This provider does not define a list of models.\n", + "\n" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea75ac14-d83d-45b4-8c1d-40e4fbc1d263", + "metadata": {}, "outputs": [], "source": [] } diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 981d17d66..fbce2fa84 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -121,7 +121,7 @@ def __init__(self, shell): self.providers = load_providers() # initialize a registry of custom model/chain names - self.custom_model_registry = {} + self.custom_model_registry = MODEL_ID_ALIASES def _ai_bulleted_list_models_for_provider(self, provider_id, Provider): @@ -208,15 +208,30 @@ def _validate_register_name(self, register_name): return ('A registry name may contain ASCII letters, numbers, hyphens, underscores, ' + 'and periods. No other characters, including a colon, are permitted') + def _register_name(self, register_name, variable_name): + # This presumes that register_name is unique and valid. + + # If variable_name is a string, treat this as an alias. + if (isinstance(variable_name, str)): + if (':' in variable_name): + # Establish alias + self.custom_model_registry[register_name] = variable_name + return None # No error + else: + return 'To register an alias, use %ai register ALIAS PROVIDER_ID:MODEL_NAME' + + return None + def _ai_register_command_markdown(self, register_name, variable_name): # TODO: Write this method return self._ai_register_command_text(register_name, variable_name) def _ai_register_command_text(self, register_name, variable_name): - output = 'Registry name is valid' - register_name_errors = self._validate_register_name(register_name) - if (register_name_errors is not None): + if (register_name_errors is None): + self._register_name(register_name, variable_name) + output = f"Registered new name {register_name}" + else: output = f"Unable to create a new entry with name {register_name}: {register_name_errors}" return output @@ -236,6 +251,15 @@ def _ai_list_command_markdown(self, single_provider=None): + self._ai_inline_list_models_for_provider(provider_id, Provider) + " |\n") + # Also list aliases. + if (single_provider is None and len(self.custom_model_registry) > 0): + output += ("\nAliases and custom commands:\n\n" + + "| Name | Target |\n" + + "|------|--------|\n") + for key, value in self.custom_model_registry.items(): + # TODO: Handle cases where value is not a string + output += f"| `{key}` | `{value}` |\n" + return output def _ai_list_command_text(self, single_provider=None): @@ -296,6 +320,10 @@ def _append_exchange_openai(self, prompt: str, output: str): }) def _decompose_model_id(self, model_id: str): + """Breaks down a model ID into a two-tuple (provider_id, local_model_id). Returns (None, None) if indeterminate.""" + if model_id in MODEL_ID_ALIASES: + model_id = MODEL_ID_ALIASES[model_id] + return decompose_model_id(model_id, self.providers) def _get_provider(self, provider_id: Optional[str]) -> BaseProvider: From 86bb43f5135493bbf7ac96dd37379ce39ed54d00 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 17:43:56 -0700 Subject: [PATCH 03/24] Raises exceptions --- examples/commands.ipynb | 147 ++++++++++-------- .../jupyter_ai_magics/magics.py | 26 +--- 2 files changed, 93 insertions(+), 80 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 953aa494a..e4ab1091c 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -135,14 +135,22 @@ "text/markdown": [ "| Provider | Environment variable | Set? | Models |\n", "|----------|----------------------|------|--------|\n", - "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", - "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", - "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", - "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", - "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", - "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", - "| `openai-chat-new` | `OPENAI_API_KEY` | | `openai-chat-new:gpt-4`, `openai-chat-new:gpt-4-0314`, `openai-chat-new:gpt-4-32k`, `openai-chat-new:gpt-4-32k-0314`, `openai-chat-new:gpt-3.5-turbo`, `openai-chat-new:gpt-3.5-turbo-0301` |\n", - "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n" + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "\n", + "Aliases and custom commands:\n", + "\n", + "| Name | Target |\n", + "|------|--------|\n", + "| `gpt2` | `huggingface_hub:gpt2` |\n", + "| `gpt3` | `openai:text-davinci-003` |\n", + "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", + "| `gpt4` | `openai-chat:gpt-4` |\n" ], "text/plain": [ "ai21\n", @@ -257,7 +265,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "b56ff0e3-42c2-4927-affd-be6a089dfa43", "metadata": {}, "outputs": [ @@ -270,7 +278,7 @@ "Usage: %ai register NAME CHAIN_OR_MODEL\n" ] }, - "execution_count": 3, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -281,24 +289,27 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "id": "f1400b59-5783-454a-b8ad-f69b2c7a7178", "metadata": { "tags": [] }, "outputs": [ { - "data": { - "text/markdown": [ - "Registry name is valid" - ], - "text/plain": [ - "Registry name is valid" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" + "ename": "ValueError", + "evalue": "Target model was not specified in PROVIDER_ID:MODEL_NAME format", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[7], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:318\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[0;32m--> 318\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_markdown(register_name, variable_name)\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:234\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 232\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;66;03m# No error\u001b[39;00m\n\u001b[1;32m 233\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTarget model was not specified in PROVIDER_ID:MODEL_NAME format\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 236\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[0;31mValueError\u001b[0m: Target model was not specified in PROVIDER_ID:MODEL_NAME format" + ] } ], "source": [ @@ -307,24 +318,27 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "id": "c4ff8026-7423-4e40-96bd-cd96ef2b8003", "metadata": { "tags": [] }, "outputs": [ { - "data": { - "text/markdown": [ - "Unable to create a new entry with name list: This name is reserved for a command" - ], - "text/plain": [ - "Unable to create a new entry with name list: This name is reserved for a command" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" + "ename": "ValueError", + "evalue": "This name is reserved for a command", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister list bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:318\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[0;32m--> 318\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_markdown(register_name, variable_name)\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:213\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 210\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_register_name\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[1;32m 211\u001b[0m \u001b[38;5;66;03m# Existing command names are not allowed\u001b[39;00m\n\u001b[1;32m 212\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[0;32m--> 213\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is reserved for a command\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 215\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 216\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n\u001b[1;32m 217\u001b[0m \u001b[38;5;66;03m# TODO: Recommend 'update' command\u001b[39;00m\n", + "\u001b[0;31mValueError\u001b[0m: This name is reserved for a command" + ] } ], "source": [ @@ -333,24 +347,27 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "id": "b77706d7-0c3a-409d-b909-d9f58d35ce4e", "metadata": { "tags": [] }, "outputs": [ { - "data": { - "text/markdown": [ - "Unable to create a new entry with name foo:bar: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" - ], - "text/plain": [ - "Unable to create a new entry with name foo:bar: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "ename": "ValueError", + "evalue": "A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo:bar baz\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:318\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[0;32m--> 318\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_markdown(register_name, variable_name)\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:224\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 222\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;129;01mnot\u001b[39;00m acceptable_name\u001b[38;5;241m.\u001b[39mmatch(register_name)):\n\u001b[0;32m--> 224\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA registry name may contain ASCII letters, numbers, hyphens, underscores, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 225\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand periods. No other characters, including a colon, are permitted\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 227\u001b[0m \u001b[38;5;66;03m# If variable_name is a string, treat this as an alias.\u001b[39;00m\n\u001b[1;32m 228\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28misinstance\u001b[39m(variable_name, \u001b[38;5;28mstr\u001b[39m)):\n", + "\u001b[0;31mValueError\u001b[0m: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" + ] } ], "source": [ @@ -359,22 +376,26 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [ { - "data": { - "text/markdown": [ - "Registry name is valid" - ], - "text/plain": [ - "Registry name is valid" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" + "ename": "ValueError", + "evalue": "This name is already associated with a custom model", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister mychat openai-chat:gpt-4\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:319\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_text(register_name, variable_name),\n\u001b[0;32m--> 319\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_markdown\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:240\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_markdown\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 238\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_markdown\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[1;32m 239\u001b[0m \u001b[38;5;66;03m# TODO: Write this method\u001b[39;00m\n\u001b[0;32m--> 240\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:218\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 215\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 216\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n\u001b[1;32m 217\u001b[0m \u001b[38;5;66;03m# TODO: Recommend 'update' command\u001b[39;00m\n\u001b[0;32m--> 218\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is already associated with a custom model\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 220\u001b[0m \u001b[38;5;66;03m# A registry name contains ASCII letters, numbers, hyphens, underscores,\u001b[39;00m\n\u001b[1;32m 221\u001b[0m \u001b[38;5;66;03m# and periods. No other characters, including a colon, are permitted\u001b[39;00m\n\u001b[1;32m 222\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[0;31mValueError\u001b[0m: This name is already associated with a custom model" + ] } ], "source": [ @@ -383,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", "metadata": { "tags": [] @@ -402,13 +423,15 @@ "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", - "Aliases:\n", + "Aliases and custom commands:\n", "\n", "| Name | Target |\n", + "|------|--------|\n", "| `gpt2` | `huggingface_hub:gpt2` |\n", "| `gpt3` | `openai:text-davinci-003` |\n", "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", - "| `gpt4` | `openai-chat:gpt-4` |\n" + "| `gpt4` | `openai-chat:gpt-4` |\n", + "| `mychat` | `openai-chat:gpt-4` |\n" ], "text/plain": [ "ai21\n", @@ -466,7 +489,7 @@ "\n" ] }, - "execution_count": 2, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index fbce2fa84..8a5c915ab 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -188,29 +188,23 @@ def _ai_env_status_for_provider_text(self, provider_id): return output + "\n" - # Returns any error - def _validate_register_name(self, register_name): + def _register_name(self, register_name, variable_name): # Existing command names are not allowed if (register_name in AI_COMMANDS): - return 'This name is reserved for a command' + raise ValueError('This name is reserved for a command') # Existing registered names are not allowed if (register_name in self.custom_model_registry): # TODO: Recommend 'update' command - return 'This name is already associated with a custom model' + raise ValueError('This name is already associated with a custom model') # A registry name contains ASCII letters, numbers, hyphens, underscores, # and periods. No other characters, including a colon, are permitted acceptable_name = re.compile('^[a-zA-Z0-9._-]+$') - if (acceptable_name.match(register_name)): - return None # No error - else: - return ('A registry name may contain ASCII letters, numbers, hyphens, underscores, ' + if (not acceptable_name.match(register_name)): + raise ValueError('A registry name may contain ASCII letters, numbers, hyphens, underscores, ' + 'and periods. No other characters, including a colon, are permitted') - def _register_name(self, register_name, variable_name): - # This presumes that register_name is unique and valid. - # If variable_name is a string, treat this as an alias. if (isinstance(variable_name, str)): if (':' in variable_name): @@ -218,7 +212,7 @@ def _register_name(self, register_name, variable_name): self.custom_model_registry[register_name] = variable_name return None # No error else: - return 'To register an alias, use %ai register ALIAS PROVIDER_ID:MODEL_NAME' + raise ValueError('Target model was not specified in PROVIDER_ID:MODEL_NAME format') return None @@ -227,12 +221,8 @@ def _ai_register_command_markdown(self, register_name, variable_name): return self._ai_register_command_text(register_name, variable_name) def _ai_register_command_text(self, register_name, variable_name): - register_name_errors = self._validate_register_name(register_name) - if (register_name_errors is None): - self._register_name(register_name, variable_name) - output = f"Registered new name {register_name}" - else: - output = f"Unable to create a new entry with name {register_name}: {register_name_errors}" + self._register_name(register_name, variable_name) + output = f"Registered new name {register_name}" return output From 7be8f50d1444d6664d6aef73d7ef046ed0f672f0 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 18:35:16 -0700 Subject: [PATCH 04/24] Refactors, adds delete and update commands --- examples/commands.ipynb | 73 ++++++++-------- .../jupyter_ai_magics/magics.py | 87 +++++++++++++------ 2 files changed, 97 insertions(+), 63 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index e4ab1091c..beb5549e8 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -45,16 +45,20 @@ { "data": { "text/markdown": [ - "| Command | Description |\n", - "| ------- | ----------- |\n", - "| `help` | Display a list of supported commands|\n", - "| `list` | Display a list of models that you can use (optionally, for a single provider)|\n", - "| `register` | Add a custom LangChain chain or alias to a model for use with %ai magic commands.Usage: `%ai register NAME CHAIN_OR_MODEL`|\n" + "| Command | Description | Usage |\n", + "| ------- | ----------- | ----- |\n", + "| `help` | Display a list of supported commands | `%ai help` |\n", + "| `list` | Display a list of models that you can use (optionally, for a single provider) | `%ai list [PROVIDER_ID]` |\n", + "| `register` | Add a custom LangChain chain or alias to a model for use with %ai magic commands. | `%ai register NAME TARGET` |\n", + "| `delete` | Delete a previously registered name that points to a chain or model. | `%ai delete NAME` |\n", + "| `update` | Update a previously registered name that points to a chain or model. | `%ai update NAME TARGET` |\n" ], "text/plain": [ "help - Display a list of supported commands\n", "list - Display a list of models that you can use (optionally, for a single provider)\n", - "register - Add a custom LangChain chain or alias to a model for use with %ai magic commands.Usage: `%ai register NAME CHAIN_OR_MODEL`\n" + "register - Add a custom LangChain chain or alias to a model for use with %ai magic commands.\n", + "delete - Delete a previously registered name that points to a chain or model.\n", + "update - Update a previously registered name that points to a chain or model.\n" ] }, "execution_count": 2, @@ -141,7 +145,7 @@ "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", - "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", "\n", @@ -272,10 +276,10 @@ { "data": { "text/markdown": [ - "Usage: `%ai register NAME CHAIN_OR_MODEL`" + "Usage: `%ai register NAME TARGET`" ], "text/plain": [ - "Usage: %ai register NAME CHAIN_OR_MODEL\n" + "Usage: %ai register NAME TARGET\n" ] }, "execution_count": 6, @@ -304,10 +308,11 @@ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[7], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:318\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[0;32m--> 318\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_markdown(register_name, variable_name)\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:234\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 232\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;66;03m# No error\u001b[39;00m\n\u001b[1;32m 233\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTarget model was not specified in PROVIDER_ID:MODEL_NAME format\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 236\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:467\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 470\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:361\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 358\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 359\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 361\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 362\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 364\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:285\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[0;32m--> 285\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:269\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 266\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[1;32m 267\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_validate_name(register_name)\n\u001b[0;32m--> 269\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_safely_set_target\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._safely_set_target\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 240\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28misinstance\u001b[39m(target, \u001b[38;5;28mstr\u001b[39m)):\n\u001b[1;32m 241\u001b[0m \u001b[38;5;66;03m# Ensure that the destination is properly formatted\u001b[39;00m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m:\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m target):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTarget model was not specified in PROVIDER_ID:MODEL_NAME format\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 245\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry[register_name] \u001b[38;5;241m=\u001b[39m target\n", "\u001b[0;31mValueError\u001b[0m: Target model was not specified in PROVIDER_ID:MODEL_NAME format" ] } @@ -333,10 +338,10 @@ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister list bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:318\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[0;32m--> 318\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_markdown(register_name, variable_name)\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:213\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 210\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_register_name\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[1;32m 211\u001b[0m \u001b[38;5;66;03m# Existing command names are not allowed\u001b[39;00m\n\u001b[1;32m 212\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[0;32m--> 213\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is reserved for a command\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 215\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 216\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n\u001b[1;32m 217\u001b[0m \u001b[38;5;66;03m# TODO: Recommend 'update' command\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:467\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 470\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:361\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 358\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 359\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 361\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 362\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 364\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:285\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[0;32m--> 285\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:259\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 256\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_register_name\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[1;32m 257\u001b[0m \u001b[38;5;66;03m# Existing command names are not allowed\u001b[39;00m\n\u001b[1;32m 258\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[0;32m--> 259\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is reserved for a command\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 261\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 262\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n\u001b[1;32m 263\u001b[0m \u001b[38;5;66;03m# TODO: Recommend 'update' command\u001b[39;00m\n", "\u001b[0;31mValueError\u001b[0m: This name is reserved for a command" ] } @@ -376,26 +381,22 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [ { - "ename": "ValueError", - "evalue": "This name is already associated with a custom model", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister mychat openai-chat:gpt-4\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:319\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_text(register_name, variable_name),\n\u001b[0;32m--> 319\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_markdown\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:240\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_markdown\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 238\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_markdown\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[1;32m 239\u001b[0m \u001b[38;5;66;03m# TODO: Write this method\u001b[39;00m\n\u001b[0;32m--> 240\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:218\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 215\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 216\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n\u001b[1;32m 217\u001b[0m \u001b[38;5;66;03m# TODO: Recommend 'update' command\u001b[39;00m\n\u001b[0;32m--> 218\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is already associated with a custom model\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 220\u001b[0m \u001b[38;5;66;03m# A registry name contains ASCII letters, numbers, hyphens, underscores,\u001b[39;00m\n\u001b[1;32m 221\u001b[0m \u001b[38;5;66;03m# and periods. No other characters, including a colon, are permitted\u001b[39;00m\n\u001b[1;32m 222\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "\u001b[0;31mValueError\u001b[0m: This name is already associated with a custom model" - ] + "data": { + "text/markdown": [ + "Registered new name `mychat`" + ], + "text/plain": [ + "Registered new name `mychat`" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -404,7 +405,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", "metadata": { "tags": [] @@ -421,7 +422,7 @@ "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", - "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", "\n", @@ -489,7 +490,7 @@ "\n" ] }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 8a5c915ab..f4ff1d071 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -68,6 +68,14 @@ def _repr_mimebundle_(self, include=None, exclude=None): "text": TextWithMetadata } +NA_MESSAGE = 'N/A' + +REGISTER_COMMAND_USAGE = "%ai register NAME TARGET" + +DELETE_COMMAND_USAGE = "%ai delete NAME" + +UPDATE_COMMAND_USAGE = "%ai update NAME TARGET" + MARKDOWN_PROMPT_TEMPLATE = '{prompt}\n\nProduce output in markdown format only.' PROVIDER_NO_MODELS = 'This provider does not define a list of models.' @@ -92,7 +100,7 @@ def _repr_mimebundle_(self, include=None, exclude=None): "text": '{prompt}' # No customization } -AI_COMMANDS = { "error", "help", "list" } +AI_COMMANDS = { "delete", "error", "help", "list", "register", "update" } class FormatDict(dict): """Subclass of dict to be passed to str#format(). Suppresses KeyError and @@ -123,7 +131,6 @@ def __init__(self, shell): # initialize a registry of custom model/chain names self.custom_model_registry = MODEL_ID_ALIASES - def _ai_bulleted_list_models_for_provider(self, provider_id, Provider): output = "" if (len(Provider.models) == 1 and Provider.models[0] == "*"): @@ -149,7 +156,7 @@ def _ai_inline_list_models_for_provider(self, provider_id, Provider): # Is the required environment variable set? def _ai_env_status_for_provider_markdown(self, provider_id): - na_message = 'Not applicable. | N/A ' + na_message = 'Not applicable. | ' + NA_MESSAGE if (provider_id not in self.providers or self.providers[provider_id].auth_strategy == None): @@ -187,8 +194,36 @@ def _ai_env_status_for_provider_text(self, provider_id): output += "(not set)" return output + "\n" + + # Is this an acceptable name for an alias? + def _validate_name(self, register_name): + # A registry name contains ASCII letters, numbers, hyphens, underscores, + # and periods. No other characters, including a colon, are permitted + acceptable_name = re.compile('^[a-zA-Z0-9._-]+$') + if (not acceptable_name.match(register_name)): + raise ValueError('A registry name may contain ASCII letters, numbers, hyphens, underscores, ' + + 'and periods. No other characters, including a colon, are permitted') + + # Initially set or update an alias to a target + def _safely_set_target(self, register_name, target): + # If target is a string, treat this as an alias. + if (isinstance(target, str)): + # Ensure that the destination is properly formatted + if (':' not in target): + raise ValueError('Target model was not specified in PROVIDER_ID:MODEL_NAME format') + + self.custom_model_registry[register_name] = target + + def _delete_name(self, register_name): + if (register_name in AI_COMMANDS): + raise ValueError('Reserved command names cannot be deleted') + + if (register_name not in self.custom_model_registry): + raise ValueError(f"There is no alias called {register_name}") + + del self.custom_model_registry[register_name] - def _register_name(self, register_name, variable_name): + def _register_name(self, register_name, target): # Existing command names are not allowed if (register_name in AI_COMMANDS): raise ValueError('This name is reserved for a command') @@ -198,33 +233,31 @@ def _register_name(self, register_name, variable_name): # TODO: Recommend 'update' command raise ValueError('This name is already associated with a custom model') - # A registry name contains ASCII letters, numbers, hyphens, underscores, - # and periods. No other characters, including a colon, are permitted - acceptable_name = re.compile('^[a-zA-Z0-9._-]+$') - if (not acceptable_name.match(register_name)): - raise ValueError('A registry name may contain ASCII letters, numbers, hyphens, underscores, ' - + 'and periods. No other characters, including a colon, are permitted') + # Does the new name match expected format? + self._validate_name(register_name) - # If variable_name is a string, treat this as an alias. - if (isinstance(variable_name, str)): - if (':' in variable_name): - # Establish alias - self.custom_model_registry[register_name] = variable_name - return None # No error - else: - raise ValueError('Target model was not specified in PROVIDER_ID:MODEL_NAME format') + self._safely_set_target(register_name, target) + + def _update_name(self, register_name, target): + if (register_name in AI_COMMANDS): + raise ValueError('Reserved command names cannot be updated') - return None + if (register_name not in self.custom_model_registry): + raise ValueError(f"There is no alias called {register_name}") + + self._safely_set_target(register_name, target) - def _ai_register_command_markdown(self, register_name, variable_name): - # TODO: Write this method - return self._ai_register_command_text(register_name, variable_name) + def _ai_delete_command(self, register_name): + self._delete_name(register_name) + return f"Deleted name `{register_name}`" - def _ai_register_command_text(self, register_name, variable_name): - self._register_name(register_name, variable_name) - output = f"Registered new name {register_name}" - - return output + def _ai_register_command(self, register_name, target): + self._register_name(register_name, target) + return f"Registered new name `{register_name}`" + + def _ai_update_command(self, register_name, target): + self._update_name(register_name, target) + return f"Updated target of name `{register_name}`" def _ai_list_command_markdown(self, single_provider=None): output = ("| Provider | Environment variable | Set? | Models |\n" From 5b8528623c69155fdb0164ed680ba35618f2b9ba Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 18:43:06 -0700 Subject: [PATCH 05/24] Additional examples --- examples/commands.ipynb | 384 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 349 insertions(+), 35 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index beb5549e8..8b1814faf 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -139,12 +139,12 @@ "text/markdown": [ "| Provider | Environment variable | Set? | Models |\n", "|----------|----------------------|------|--------|\n", - "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", - "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", - "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", - "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", - "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", - "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", @@ -158,7 +158,7 @@ ], "text/plain": [ "ai21\n", - "Requires environment variable AI21_API_KEY (not set)\n", + "Requires environment variable AI21_API_KEY (set)\n", "* ai21:j1-large\n", "* ai21:j1-grande\n", "* ai21:j1-jumbo\n", @@ -170,7 +170,7 @@ "* ai21:j2-jumbo-instruct\n", "\n", "anthropic\n", - "Requires environment variable ANTHROPIC_API_KEY (not set)\n", + "Requires environment variable ANTHROPIC_API_KEY (set)\n", "* anthropic:claude-v1\n", "* anthropic:claude-v1.0\n", "* anthropic:claude-v1.2\n", @@ -178,16 +178,16 @@ "* anthropic:claude-instant-v1.0\n", "\n", "cohere\n", - "Requires environment variable COHERE_API_KEY (not set)\n", + "Requires environment variable COHERE_API_KEY (set)\n", "* cohere:medium\n", "* cohere:xlarge\n", "\n", "huggingface_hub\n", - "Requires environment variable HUGGINGFACEHUB_API_TOKEN (not set)\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (set)\n", "* This provider does not define a list of models.\n", "\n", "openai\n", - "Requires environment variable OPENAI_API_KEY (not set)\n", + "Requires environment variable OPENAI_API_KEY (set)\n", "* openai:text-davinci-003\n", "* openai:text-davinci-002\n", "* openai:text-curie-001\n", @@ -199,7 +199,7 @@ "* openai:ada\n", "\n", "openai-chat\n", - "Requires environment variable OPENAI_API_KEY (not set)\n", + "Requires environment variable OPENAI_API_KEY (set)\n", "* openai-chat:gpt-4\n", "* openai-chat:gpt-4-0314\n", "* openai-chat:gpt-4-32k\n", @@ -241,11 +241,11 @@ "text/markdown": [ "| Provider | Environment variable | Set? | Models |\n", "|----------|----------------------|------|--------|\n", - "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n" + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n" ], "text/plain": [ "openai\n", - "Requires environment variable OPENAI_API_KEY (not set)\n", + "Requires environment variable OPENAI_API_KEY (set)\n", "* openai:text-davinci-003\n", "* openai:text-davinci-002\n", "* openai:text-curie-001\n", @@ -367,10 +367,11 @@ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[9], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo:bar baz\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:400\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 398\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 399\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:318\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 314\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 315\u001b[0m variable_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[0;32m--> 318\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ai_register_command_markdown(register_name, variable_name)\n\u001b[1;32m 320\u001b[0m )\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 322\u001b[0m \u001b[38;5;66;03m# This should be unreachable, since unhandled commands are treated like model names\u001b[39;00m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(\n\u001b[1;32m 324\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 325\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo handler for command `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 326\u001b[0m )\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command_text\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, variable_name):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 244\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m output\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:224\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, variable_name)\u001b[0m\n\u001b[1;32m 222\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;129;01mnot\u001b[39;00m acceptable_name\u001b[38;5;241m.\u001b[39mmatch(register_name)):\n\u001b[0;32m--> 224\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA registry name may contain ASCII letters, numbers, hyphens, underscores, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 225\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand periods. No other characters, including a colon, are permitted\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 227\u001b[0m \u001b[38;5;66;03m# If variable_name is a string, treat this as an alias.\u001b[39;00m\n\u001b[1;32m 228\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28misinstance\u001b[39m(variable_name, \u001b[38;5;28mstr\u001b[39m)):\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:467\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 470\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:361\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 358\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 359\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 361\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 362\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 364\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:285\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[0;32m--> 285\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:267\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 264\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is already associated with a custom model\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 266\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[0;32m--> 267\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 269\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_safely_set_target(register_name, target)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:234\u001b[0m, in \u001b[0;36mAiMagics._validate_name\u001b[0;34m(self, register_name)\u001b[0m\n\u001b[1;32m 232\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 233\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;129;01mnot\u001b[39;00m acceptable_name\u001b[38;5;241m.\u001b[39mmatch(register_name)):\n\u001b[0;32m--> 234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA registry name may contain ASCII letters, numbers, hyphens, underscores, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 235\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand periods. No other characters, including a colon, are permitted\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" ] } @@ -381,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [ @@ -394,7 +395,7 @@ "Registered new name `mychat`" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -405,7 +406,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", "metadata": { "tags": [] @@ -416,12 +417,12 @@ "text/markdown": [ "| Provider | Environment variable | Set? | Models |\n", "|----------|----------------------|------|--------|\n", - "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", - "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", - "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", - "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", - "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", - "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", @@ -436,7 +437,7 @@ ], "text/plain": [ "ai21\n", - "Requires environment variable AI21_API_KEY (not set)\n", + "Requires environment variable AI21_API_KEY (set)\n", "* ai21:j1-large\n", "* ai21:j1-grande\n", "* ai21:j1-jumbo\n", @@ -448,7 +449,7 @@ "* ai21:j2-jumbo-instruct\n", "\n", "anthropic\n", - "Requires environment variable ANTHROPIC_API_KEY (not set)\n", + "Requires environment variable ANTHROPIC_API_KEY (set)\n", "* anthropic:claude-v1\n", "* anthropic:claude-v1.0\n", "* anthropic:claude-v1.2\n", @@ -456,16 +457,16 @@ "* anthropic:claude-instant-v1.0\n", "\n", "cohere\n", - "Requires environment variable COHERE_API_KEY (not set)\n", + "Requires environment variable COHERE_API_KEY (set)\n", "* cohere:medium\n", "* cohere:xlarge\n", "\n", "huggingface_hub\n", - "Requires environment variable HUGGINGFACEHUB_API_TOKEN (not set)\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (set)\n", "* This provider does not define a list of models.\n", "\n", "openai\n", - "Requires environment variable OPENAI_API_KEY (not set)\n", + "Requires environment variable OPENAI_API_KEY (set)\n", "* openai:text-davinci-003\n", "* openai:text-davinci-002\n", "* openai:text-curie-001\n", @@ -477,7 +478,7 @@ "* openai:ada\n", "\n", "openai-chat\n", - "Requires environment variable OPENAI_API_KEY (not set)\n", + "Requires environment variable OPENAI_API_KEY (set)\n", "* openai-chat:gpt-4\n", "* openai-chat:gpt-4-0314\n", "* openai-chat:gpt-4-32k\n", @@ -490,7 +491,7 @@ "\n" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -501,8 +502,321 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "ea75ac14-d83d-45b4-8c1d-40e4fbc1d263", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + "\n", + "This model is not identified." + ], + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": { + "text/markdown": { + "jupyter_ai": { + "model_id": "text-davinci-003", + "provider_id": "openai" + } + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "%%ai gpt3\n", + "What model is this?" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "3e7fb7fb-d61c-4909-959b-14bc97af409a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "Updated target of name `mychat`" + ], + "text/plain": [ + "Updated target of name `mychat`" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai update mychat openai:text-davinci-003" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "a89a4c2a-b37f-4a3d-86cb-67747113d3d7", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + "\n", + "This model is not specified." + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": { + "text/markdown": { + "jupyter_ai": { + "model_id": "text-davinci-003", + "provider_id": "openai" + } + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "%%ai mychat\n", + "What model is this?" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c7453152-6c70-4f91-bef6-4ae38d700f52", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "| Provider | Environment variable | Set? | Models |\n", + "|----------|----------------------|------|--------|\n", + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "\n", + "Aliases and custom commands:\n", + "\n", + "| Name | Target |\n", + "|------|--------|\n", + "| `gpt2` | `huggingface_hub:gpt2` |\n", + "| `gpt3` | `openai:text-davinci-003` |\n", + "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", + "| `gpt4` | `openai-chat:gpt-4` |\n", + "| `mychat` | `openai:text-davinci-003` |\n" + ], + "text/plain": [ + "ai21\n", + "Requires environment variable AI21_API_KEY (set)\n", + "* ai21:j1-large\n", + "* ai21:j1-grande\n", + "* ai21:j1-jumbo\n", + "* ai21:j1-grande-instruct\n", + "* ai21:j2-large\n", + "* ai21:j2-grande\n", + "* ai21:j2-jumbo\n", + "* ai21:j2-grande-instruct\n", + "* ai21:j2-jumbo-instruct\n", + "\n", + "anthropic\n", + "Requires environment variable ANTHROPIC_API_KEY (set)\n", + "* anthropic:claude-v1\n", + "* anthropic:claude-v1.0\n", + "* anthropic:claude-v1.2\n", + "* anthropic:claude-instant-v1\n", + "* anthropic:claude-instant-v1.0\n", + "\n", + "cohere\n", + "Requires environment variable COHERE_API_KEY (set)\n", + "* cohere:medium\n", + "* cohere:xlarge\n", + "\n", + "huggingface_hub\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (set)\n", + "* This provider does not define a list of models.\n", + "\n", + "openai\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai:text-davinci-003\n", + "* openai:text-davinci-002\n", + "* openai:text-curie-001\n", + "* openai:text-babbage-001\n", + "* openai:text-ada-001\n", + "* openai:davinci\n", + "* openai:curie\n", + "* openai:babbage\n", + "* openai:ada\n", + "\n", + "openai-chat\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat:gpt-4\n", + "* openai-chat:gpt-4-0314\n", + "* openai-chat:gpt-4-32k\n", + "* openai-chat:gpt-4-32k-0314\n", + "* openai-chat:gpt-3.5-turbo\n", + "* openai-chat:gpt-3.5-turbo-0301\n", + "\n", + "sagemaker-endpoint\n", + "* This provider does not define a list of models.\n", + "\n" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai list" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "971f823d-8f35-4201-a6cb-12a21a87628a", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "Deleted name `mychat`" + ], + "text/plain": [ + "Deleted name `mychat`" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai delete mychat" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "6fb1b54a-ee4f-41c0-b666-ea9e0a1279ee", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "| Provider | Environment variable | Set? | Models |\n", + "|----------|----------------------|------|--------|\n", + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "\n", + "Aliases and custom commands:\n", + "\n", + "| Name | Target |\n", + "|------|--------|\n", + "| `gpt2` | `huggingface_hub:gpt2` |\n", + "| `gpt3` | `openai:text-davinci-003` |\n", + "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", + "| `gpt4` | `openai-chat:gpt-4` |\n" + ], + "text/plain": [ + "ai21\n", + "Requires environment variable AI21_API_KEY (set)\n", + "* ai21:j1-large\n", + "* ai21:j1-grande\n", + "* ai21:j1-jumbo\n", + "* ai21:j1-grande-instruct\n", + "* ai21:j2-large\n", + "* ai21:j2-grande\n", + "* ai21:j2-jumbo\n", + "* ai21:j2-grande-instruct\n", + "* ai21:j2-jumbo-instruct\n", + "\n", + "anthropic\n", + "Requires environment variable ANTHROPIC_API_KEY (set)\n", + "* anthropic:claude-v1\n", + "* anthropic:claude-v1.0\n", + "* anthropic:claude-v1.2\n", + "* anthropic:claude-instant-v1\n", + "* anthropic:claude-instant-v1.0\n", + "\n", + "cohere\n", + "Requires environment variable COHERE_API_KEY (set)\n", + "* cohere:medium\n", + "* cohere:xlarge\n", + "\n", + "huggingface_hub\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (set)\n", + "* This provider does not define a list of models.\n", + "\n", + "openai\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai:text-davinci-003\n", + "* openai:text-davinci-002\n", + "* openai:text-curie-001\n", + "* openai:text-babbage-001\n", + "* openai:text-ada-001\n", + "* openai:davinci\n", + "* openai:curie\n", + "* openai:babbage\n", + "* openai:ada\n", + "\n", + "openai-chat\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat:gpt-4\n", + "* openai-chat:gpt-4-0314\n", + "* openai-chat:gpt-4-32k\n", + "* openai-chat:gpt-4-32k-0314\n", + "* openai-chat:gpt-3.5-turbo\n", + "* openai-chat:gpt-3.5-turbo-0301\n", + "\n", + "sagemaker-endpoint\n", + "* This provider does not define a list of models.\n", + "\n" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7088a6ed-3a56-4249-a7e8-f8d05c287df8", "metadata": {}, "outputs": [], "source": [] From 5dcf09df933bd3a64355b95afd8c02e113def9f6 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 20:15:38 -0700 Subject: [PATCH 06/24] Update sample notebook --- examples/commands.ipynb | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 8b1814faf..0f9ecc9b2 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -49,16 +49,16 @@ "| ------- | ----------- | ----- |\n", "| `help` | Display a list of supported commands | `%ai help` |\n", "| `list` | Display a list of models that you can use (optionally, for a single provider) | `%ai list [PROVIDER_ID]` |\n", - "| `register` | Add a custom LangChain chain or alias to a model for use with %ai magic commands. | `%ai register NAME TARGET` |\n", - "| `delete` | Delete a previously registered name that points to a chain or model. | `%ai delete NAME` |\n", - "| `update` | Update a previously registered name that points to a chain or model. | `%ai update NAME TARGET` |\n" + "| `register` | Add an alias to a model for use with %ai magic commands | `%ai register NAME TARGET` |\n", + "| `delete` | Delete a previously registered alias | `%ai delete NAME` |\n", + "| `update` | Update a previously registered alias | `%ai update NAME TARGET` |\n" ], "text/plain": [ "help - Display a list of supported commands\n", "list - Display a list of models that you can use (optionally, for a single provider)\n", - "register - Add a custom LangChain chain or alias to a model for use with %ai magic commands.\n", - "delete - Delete a previously registered name that points to a chain or model.\n", - "update - Update a previously registered name that points to a chain or model.\n" + "register - Add an alias to a model for use with %ai magic commands\n", + "delete - Delete a previously registered alias\n", + "update - Update a previously registered alias\n" ] }, "execution_count": 2, @@ -502,7 +502,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 12, "id": "ea75ac14-d83d-45b4-8c1d-40e4fbc1d263", "metadata": { "tags": [] @@ -513,13 +513,13 @@ "text/markdown": [ "\n", "\n", - "This model is not identified." + "This question cannot be answered without more information." ], "text/plain": [ "" ] }, - "execution_count": 15, + "execution_count": 12, "metadata": { "text/markdown": { "jupyter_ai": { @@ -538,7 +538,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 13, "id": "3e7fb7fb-d61c-4909-959b-14bc97af409a", "metadata": {}, "outputs": [ @@ -551,7 +551,7 @@ "Updated target of name `mychat`" ] }, - "execution_count": 16, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -562,7 +562,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 14, "id": "a89a4c2a-b37f-4a3d-86cb-67747113d3d7", "metadata": { "tags": [] @@ -579,7 +579,7 @@ "" ] }, - "execution_count": 17, + "execution_count": 14, "metadata": { "text/markdown": { "jupyter_ai": { @@ -598,7 +598,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 15, "id": "c7453152-6c70-4f91-bef6-4ae38d700f52", "metadata": { "tags": [] @@ -683,7 +683,7 @@ "\n" ] }, - "execution_count": 18, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -694,7 +694,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 16, "id": "971f823d-8f35-4201-a6cb-12a21a87628a", "metadata": { "tags": [] @@ -709,7 +709,7 @@ "Deleted name `mychat`" ] }, - "execution_count": 19, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -720,7 +720,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 17, "id": "6fb1b54a-ee4f-41c0-b666-ea9e0a1279ee", "metadata": { "tags": [] @@ -804,7 +804,7 @@ "\n" ] }, - "execution_count": 20, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } From 737e2565b38891f10f6a1a9fc2366462fab68ea3 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 20:21:04 -0700 Subject: [PATCH 07/24] Update docs --- docs/source/users/index.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/source/users/index.md b/docs/source/users/index.md index 52c758c15..1b1079561 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -548,3 +548,33 @@ As a shortcut for explaining errors, you can use the `%ai error` command, which %ai error anthropic:claude-v1.2 ``` +### Creating and managing aliases for models + +You can create an alias for a model using the `%ai register` command. For example, the command: + +``` +%ai register claude anthropic:claude-v1.2 +``` + +will register the alias `claude` as pointing to the `anthropic` provider's `claude-v1.2` model. You can then use this alias as you would use any other model name: + +``` +%%ai claude +Write a poem about C++. +``` + +You can change this alias's target model using the `%ai update` command: + +``` +%ai update claude anthropic:claude-instant-v1.0 +``` + +You can delete this alias using the `%ai delete` command: + +``` +%ai delete claude +``` + +Aliases' names can contain ASCII letters (uppercase and lowercase), numbers, hyphens, underscores, and periods. They may not contain colons. They may also not override built-in commands — run `%ai help` for a list of these commands. + +Aliases must refer to models; they cannot refer to other aliases. From a97a9dbea9974cfd0550de6344e1534a7b9a1367 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 1 May 2023 20:22:08 -0700 Subject: [PATCH 08/24] List aliases --- docs/source/users/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/users/index.md b/docs/source/users/index.md index 1b1079561..30b1ddfc6 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -575,6 +575,8 @@ You can delete this alias using the `%ai delete` command: %ai delete claude ``` +You can see a list of all aliases by running the `%ai list` command. + Aliases' names can contain ASCII letters (uppercase and lowercase), numbers, hyphens, underscores, and periods. They may not contain colons. They may also not override built-in commands — run `%ai help` for a list of these commands. Aliases must refer to models; they cannot refer to other aliases. From 15471d605b9d4d85ea7deec2e5794095d7bf5aa9 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 8 May 2023 16:02:41 -0700 Subject: [PATCH 09/24] Refactoring --- .../jupyter_ai_magics/magics.py | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index f4ff1d071..f1e75831b 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -214,7 +214,7 @@ def _safely_set_target(self, register_name, target): self.custom_model_registry[register_name] = target - def _delete_name(self, register_name): + def _ai_delete_command(self, register_name): if (register_name in AI_COMMANDS): raise ValueError('Reserved command names cannot be deleted') @@ -222,8 +222,9 @@ def _delete_name(self, register_name): raise ValueError(f"There is no alias called {register_name}") del self.custom_model_registry[register_name] - - def _register_name(self, register_name, target): + return f"Deleted name `{register_name}`" + + def _ai_register_command(self, register_name, target): # Existing command names are not allowed if (register_name in AI_COMMANDS): raise ValueError('This name is reserved for a command') @@ -237,8 +238,9 @@ def _register_name(self, register_name, target): self._validate_name(register_name) self._safely_set_target(register_name, target) + return f"Registered new name `{register_name}`" - def _update_name(self, register_name, target): + def _ai_update_command(self, register_name, target): if (register_name in AI_COMMANDS): raise ValueError('Reserved command names cannot be updated') @@ -246,17 +248,6 @@ def _update_name(self, register_name, target): raise ValueError(f"There is no alias called {register_name}") self._safely_set_target(register_name, target) - - def _ai_delete_command(self, register_name): - self._delete_name(register_name) - return f"Deleted name `{register_name}`" - - def _ai_register_command(self, register_name, target): - self._register_name(register_name, target) - return f"Registered new name `{register_name}`" - - def _ai_update_command(self, register_name, target): - self._update_name(register_name, target) return f"Updated target of name `{register_name}`" def _ai_list_command_markdown(self, single_provider=None): From 1206bab497cfd891324bf593e4f70291c6c5f1e0 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 8 May 2023 16:27:29 -0700 Subject: [PATCH 10/24] Recommends using 'update' command --- packages/jupyter-ai-magics/jupyter_ai_magics/magics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index f1e75831b..0c6952de7 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -231,8 +231,8 @@ def _ai_register_command(self, register_name, target): # Existing registered names are not allowed if (register_name in self.custom_model_registry): - # TODO: Recommend 'update' command - raise ValueError('This name is already associated with a custom model') + raise ValueError('This name is already associated with a custom model; ' + + 'use %ai update to change its target') # Does the new name match expected format? self._validate_name(register_name) From 89b2d03fb7a61151d01dbf579d834988e241fe4a Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 9 May 2023 12:25:57 -0700 Subject: [PATCH 11/24] WIP: Gets variable from user namespace, tests whether it's a chain --- .../jupyter_ai_magics/magics.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 0c6952de7..7441ee701 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -1,5 +1,6 @@ import base64 import json +import keyword import os import re import warnings @@ -14,6 +15,7 @@ from .providers import BaseProvider from .parsers import cell_magic_parser, line_magic_parser, CellArgs, ErrorArgs, HelpArgs, ListArgs +from langchain.chains import LLMChain MODEL_ID_ALIASES = { "gpt2": "huggingface_hub:gpt2", @@ -195,6 +197,19 @@ def _ai_env_status_for_provider_text(self, provider_id): return output + "\n" + # Is this a name of a Python variable that can be called as a LangChain chain? + def _is_langchain_chain(self, name): + # Reserved word in Python? + if (keyword.iskeyword(name)): + return False; + + acceptable_name = re.compile('^[a-zA-Z0-9_]+$') + if (not acceptable_name.match(name)): + return False; + + ipython = get_ipython() + return(name in ipython.user_ns and isinstance(ipython.user_ns[name], LLMChain)) + # Is this an acceptable name for an alias? def _validate_name(self, register_name): # A registry name contains ASCII letters, numbers, hyphens, underscores, @@ -234,6 +249,10 @@ def _ai_register_command(self, register_name, target): raise ValueError('This name is already associated with a custom model; ' + 'use %ai update to change its target') + # Is this the name of a variable? + if self._is_langchain_chain(target): + return f"`{target}` is a LangChain chain" + # Does the new name match expected format? self._validate_name(register_name) From 80f40f09e88739b13c92bff67c69a3a2d9f7d44b Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 9 May 2023 15:26:41 -0700 Subject: [PATCH 12/24] Updates sample workbook, calls custom chain --- examples/commands.ipynb | 332 +++++++++++++++++- .../jupyter_ai_magics/magics.py | 76 +++- 2 files changed, 374 insertions(+), 34 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 0f9ecc9b2..f090af834 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -49,14 +49,14 @@ "| ------- | ----------- | ----- |\n", "| `help` | Display a list of supported commands | `%ai help` |\n", "| `list` | Display a list of models that you can use (optionally, for a single provider) | `%ai list [PROVIDER_ID]` |\n", - "| `register` | Add an alias to a model for use with %ai magic commands | `%ai register NAME TARGET` |\n", + "| `register` | Add an alias to a model or a LangChain chain for use with %ai magic commands | `%ai register NAME TARGET` |\n", "| `delete` | Delete a previously registered alias | `%ai delete NAME` |\n", "| `update` | Update a previously registered alias | `%ai update NAME TARGET` |\n" ], "text/plain": [ "help - Display a list of supported commands\n", "list - Display a list of models that you can use (optionally, for a single provider)\n", - "register - Add an alias to a model for use with %ai magic commands\n", + "register - Add an alias to a model or a LangChain chain for use with %ai magic commands\n", "delete - Delete a previously registered alias\n", "update - Update a previously registered alias\n" ] @@ -145,6 +145,7 @@ "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `openai-chat-new` | `OPENAI_API_KEY` | | `openai-chat-new:gpt-4`, `openai-chat-new:gpt-4-0314`, `openai-chat-new:gpt-4-32k`, `openai-chat-new:gpt-4-32k-0314`, `openai-chat-new:gpt-3.5-turbo`, `openai-chat-new:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", @@ -267,6 +268,16 @@ "%ai list openai" ] }, + { + "cell_type": "markdown", + "id": "a7b640f4-c8ba-4c4e-ba91-7bb14758064c", + "metadata": {}, + "source": [ + "## Model aliases\n", + "\n", + "Using the syntax `%ai register NAME TARGET`, you can create a new alias to an existing alias's target. The target must be specified using the full `provider:model` syntax. You cannot create an alias to another alias." + ] + }, { "cell_type": "code", "execution_count": 6, @@ -308,11 +319,10 @@ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[7], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:467\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 470\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:361\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 358\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 359\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 361\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 362\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 364\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:285\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[0;32m--> 285\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:269\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 266\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[1;32m 267\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_validate_name(register_name)\n\u001b[0;32m--> 269\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_safely_set_target\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:243\u001b[0m, in \u001b[0;36mAiMagics._safely_set_target\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 240\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28misinstance\u001b[39m(target, \u001b[38;5;28mstr\u001b[39m)):\n\u001b[1;32m 241\u001b[0m \u001b[38;5;66;03m# Ensure that the destination is properly formatted\u001b[39;00m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m:\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m target):\n\u001b[0;32m--> 243\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTarget model was not specified in PROVIDER_ID:MODEL_NAME format\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 245\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry[register_name] \u001b[38;5;241m=\u001b[39m target\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:482\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 479\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 481\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 482\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 485\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:362\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 359\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 360\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 362\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 364\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 365\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:275\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 272\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[1;32m 273\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_validate_name(register_name)\n\u001b[0;32m--> 275\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_safely_set_target\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 276\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:248\u001b[0m, in \u001b[0;36mAiMagics._safely_set_target\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 245\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 246\u001b[0m \u001b[38;5;66;03m# Ensure that the destination is properly formatted\u001b[39;00m\n\u001b[1;32m 247\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m:\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m target):\n\u001b[0;32m--> 248\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTarget model was not specified in PROVIDER_ID:MODEL_NAME format\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 250\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry[register_name] \u001b[38;5;241m=\u001b[39m target\n", "\u001b[0;31mValueError\u001b[0m: Target model was not specified in PROVIDER_ID:MODEL_NAME format" ] } @@ -338,10 +348,9 @@ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister list bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:467\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 470\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:361\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 358\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 359\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 361\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 362\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 364\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:285\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[0;32m--> 285\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:259\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 256\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_register_name\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[1;32m 257\u001b[0m \u001b[38;5;66;03m# Existing command names are not allowed\u001b[39;00m\n\u001b[1;32m 258\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[0;32m--> 259\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is reserved for a command\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 261\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 262\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n\u001b[1;32m 263\u001b[0m \u001b[38;5;66;03m# TODO: Recommend 'update' command\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:482\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 479\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 481\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 482\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 485\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:362\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 359\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 360\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 362\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 364\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 365\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:265\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 262\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[1;32m 263\u001b[0m \u001b[38;5;66;03m# Existing command names are not allowed\u001b[39;00m\n\u001b[1;32m 264\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[0;32m--> 265\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is reserved for a command\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 267\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 268\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n", "\u001b[0;31mValueError\u001b[0m: This name is reserved for a command" ] } @@ -367,11 +376,10 @@ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[9], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo:bar baz\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:467\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 470\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:361\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 358\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 359\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 361\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 362\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 364\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:285\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[0;32m--> 285\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_register_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:267\u001b[0m, in \u001b[0;36mAiMagics._register_name\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 264\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is already associated with a custom model\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 266\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[0;32m--> 267\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 269\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_safely_set_target(register_name, target)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:234\u001b[0m, in \u001b[0;36mAiMagics._validate_name\u001b[0;34m(self, register_name)\u001b[0m\n\u001b[1;32m 232\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 233\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;129;01mnot\u001b[39;00m acceptable_name\u001b[38;5;241m.\u001b[39mmatch(register_name)):\n\u001b[0;32m--> 234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA registry name may contain ASCII letters, numbers, hyphens, underscores, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 235\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand periods. No other characters, including a colon, are permitted\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:482\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 479\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 481\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 482\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 485\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:362\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 359\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 360\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 362\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 364\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 365\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:273\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 269\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is already associated with a custom model; \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 270\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124muse \u001b[39m\u001b[38;5;132;01m%a\u001b[39;00m\u001b[38;5;124mi update to change its target\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 272\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[0;32m--> 273\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 275\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_safely_set_target(register_name, target)\n\u001b[1;32m 276\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:236\u001b[0m, in \u001b[0;36mAiMagics._validate_name\u001b[0;34m(self, register_name)\u001b[0m\n\u001b[1;32m 234\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 235\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;129;01mnot\u001b[39;00m acceptable_name\u001b[38;5;241m.\u001b[39mmatch(register_name)):\n\u001b[0;32m--> 236\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA registry name may contain ASCII letters, numbers, hyphens, underscores, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 237\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand periods. No other characters, including a colon, are permitted\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" ] } @@ -423,6 +431,7 @@ "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `openai-chat-new` | `OPENAI_API_KEY` | | `openai-chat-new:gpt-4`, `openai-chat-new:gpt-4-0314`, `openai-chat-new:gpt-4-32k`, `openai-chat-new:gpt-4-32k-0314`, `openai-chat-new:gpt-3.5-turbo`, `openai-chat-new:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", @@ -486,6 +495,15 @@ "* openai-chat:gpt-3.5-turbo\n", "* openai-chat:gpt-3.5-turbo-0301\n", "\n", + "openai-chat-new\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat-new:gpt-4\n", + "* openai-chat-new:gpt-4-0314\n", + "* openai-chat-new:gpt-4-32k\n", + "* openai-chat-new:gpt-4-32k-0314\n", + "* openai-chat-new:gpt-3.5-turbo\n", + "* openai-chat-new:gpt-3.5-turbo-0301\n", + "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", "\n" @@ -513,7 +531,7 @@ "text/markdown": [ "\n", "\n", - "This question cannot be answered without more information." + "It is not possible to answer this question without additional information." ], "text/plain": [ "" @@ -615,6 +633,7 @@ "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `openai-chat-new` | `OPENAI_API_KEY` | | `openai-chat-new:gpt-4`, `openai-chat-new:gpt-4-0314`, `openai-chat-new:gpt-4-32k`, `openai-chat-new:gpt-4-32k-0314`, `openai-chat-new:gpt-3.5-turbo`, `openai-chat-new:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", @@ -678,6 +697,15 @@ "* openai-chat:gpt-3.5-turbo\n", "* openai-chat:gpt-3.5-turbo-0301\n", "\n", + "openai-chat-new\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat-new:gpt-4\n", + "* openai-chat-new:gpt-4-0314\n", + "* openai-chat-new:gpt-4-32k\n", + "* openai-chat-new:gpt-4-32k-0314\n", + "* openai-chat-new:gpt-3.5-turbo\n", + "* openai-chat-new:gpt-3.5-turbo-0301\n", + "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", "\n" @@ -737,6 +765,7 @@ "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `openai-chat-new` | `OPENAI_API_KEY` | | `openai-chat-new:gpt-4`, `openai-chat-new:gpt-4-0314`, `openai-chat-new:gpt-4-32k`, `openai-chat-new:gpt-4-32k-0314`, `openai-chat-new:gpt-3.5-turbo`, `openai-chat-new:gpt-3.5-turbo-0301` |\n", "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", "\n", "Aliases and custom commands:\n", @@ -799,6 +828,15 @@ "* openai-chat:gpt-3.5-turbo\n", "* openai-chat:gpt-3.5-turbo-0301\n", "\n", + "openai-chat-new\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat-new:gpt-4\n", + "* openai-chat-new:gpt-4-0314\n", + "* openai-chat-new:gpt-4-32k\n", + "* openai-chat-new:gpt-4-32k-0314\n", + "* openai-chat-new:gpt-3.5-turbo\n", + "* openai-chat-new:gpt-3.5-turbo-0301\n", + "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", "\n" @@ -813,10 +851,266 @@ "%ai list" ] }, + { + "cell_type": "markdown", + "id": "178e9916-5bd8-40bf-a273-ea03553663b4", + "metadata": {}, + "source": [ + "## Custom chains\n", + "\n", + "You can define a LangChain chain in a local variable and use that as the target in a magic `%ai register` command." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "9ef639c7-1ca8-48af-b5e5-f76cfa5779f3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from langchain.prompts import PromptTemplate\n", + "from langchain.llms import OpenAI\n", + "\n", + "llm = OpenAI(temperature=0.9)\n", + "prompt = PromptTemplate(\n", + " input_variables=[\"product\"],\n", + " template=\"What is a good name for a company that makes {product}?\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "29d5239f-7601-405e-b059-4e881ebf7ab1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from langchain.chains import LLMChain\n", + "chain = LLMChain(llm=llm, prompt=prompt)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "43e7a77c-93af-4ef7-a104-f932c9f54183", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Rainbow Toes Sock Co.\n" + ] + } + ], + "source": [ + "# Run the chain only specifying the input variable.\n", + "print(chain.run(\"colorful socks\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "9badc567-9720-4e33-ab4a-54fda5129f36", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "Registered new name `company`" + ], + "text/plain": [ + "Registered new name `company`" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai register company chain" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "92b75d71-8844-4872-b424-b0023706abb1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "| Provider | Environment variable | Set? | Models |\n", + "|----------|----------------------|------|--------|\n", + "| `ai21` | `AI21_API_KEY` | | `ai21:j1-large`, `ai21:j1-grande`, `ai21:j1-jumbo`, `ai21:j1-grande-instruct`, `ai21:j2-large`, `ai21:j2-grande`, `ai21:j2-jumbo`, `ai21:j2-grande-instruct`, `ai21:j2-jumbo-instruct` |\n", + "| `anthropic` | `ANTHROPIC_API_KEY` | | `anthropic:claude-v1`, `anthropic:claude-v1.0`, `anthropic:claude-v1.2`, `anthropic:claude-instant-v1`, `anthropic:claude-instant-v1.0` |\n", + "| `cohere` | `COHERE_API_KEY` | | `cohere:medium`, `cohere:xlarge` |\n", + "| `huggingface_hub` | `HUGGINGFACEHUB_API_TOKEN` | | This provider does not define a list of models. |\n", + "| `openai` | `OPENAI_API_KEY` | | `openai:text-davinci-003`, `openai:text-davinci-002`, `openai:text-curie-001`, `openai:text-babbage-001`, `openai:text-ada-001`, `openai:davinci`, `openai:curie`, `openai:babbage`, `openai:ada` |\n", + "| `openai-chat` | `OPENAI_API_KEY` | | `openai-chat:gpt-4`, `openai-chat:gpt-4-0314`, `openai-chat:gpt-4-32k`, `openai-chat:gpt-4-32k-0314`, `openai-chat:gpt-3.5-turbo`, `openai-chat:gpt-3.5-turbo-0301` |\n", + "| `openai-chat-new` | `OPENAI_API_KEY` | | `openai-chat-new:gpt-4`, `openai-chat-new:gpt-4-0314`, `openai-chat-new:gpt-4-32k`, `openai-chat-new:gpt-4-32k-0314`, `openai-chat-new:gpt-3.5-turbo`, `openai-chat-new:gpt-3.5-turbo-0301` |\n", + "| `sagemaker-endpoint` | Not applicable. | N/A | This provider does not define a list of models. |\n", + "\n", + "Aliases and custom commands:\n", + "\n", + "| Name | Target |\n", + "|------|--------|\n", + "| `gpt2` | `huggingface_hub:gpt2` |\n", + "| `gpt3` | `openai:text-davinci-003` |\n", + "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", + "| `gpt4` | `openai-chat:gpt-4` |\n", + "| `company` | *(custom chain)* |\n" + ], + "text/plain": [ + "ai21\n", + "Requires environment variable AI21_API_KEY (set)\n", + "* ai21:j1-large\n", + "* ai21:j1-grande\n", + "* ai21:j1-jumbo\n", + "* ai21:j1-grande-instruct\n", + "* ai21:j2-large\n", + "* ai21:j2-grande\n", + "* ai21:j2-jumbo\n", + "* ai21:j2-grande-instruct\n", + "* ai21:j2-jumbo-instruct\n", + "\n", + "anthropic\n", + "Requires environment variable ANTHROPIC_API_KEY (set)\n", + "* anthropic:claude-v1\n", + "* anthropic:claude-v1.0\n", + "* anthropic:claude-v1.2\n", + "* anthropic:claude-instant-v1\n", + "* anthropic:claude-instant-v1.0\n", + "\n", + "cohere\n", + "Requires environment variable COHERE_API_KEY (set)\n", + "* cohere:medium\n", + "* cohere:xlarge\n", + "\n", + "huggingface_hub\n", + "Requires environment variable HUGGINGFACEHUB_API_TOKEN (set)\n", + "* This provider does not define a list of models.\n", + "\n", + "openai\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai:text-davinci-003\n", + "* openai:text-davinci-002\n", + "* openai:text-curie-001\n", + "* openai:text-babbage-001\n", + "* openai:text-ada-001\n", + "* openai:davinci\n", + "* openai:curie\n", + "* openai:babbage\n", + "* openai:ada\n", + "\n", + "openai-chat\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat:gpt-4\n", + "* openai-chat:gpt-4-0314\n", + "* openai-chat:gpt-4-32k\n", + "* openai-chat:gpt-4-32k-0314\n", + "* openai-chat:gpt-3.5-turbo\n", + "* openai-chat:gpt-3.5-turbo-0301\n", + "\n", + "openai-chat-new\n", + "Requires environment variable OPENAI_API_KEY (set)\n", + "* openai-chat-new:gpt-4\n", + "* openai-chat-new:gpt-4-0314\n", + "* openai-chat-new:gpt-4-32k\n", + "* openai-chat-new:gpt-4-32k-0314\n", + "* openai-chat-new:gpt-3.5-turbo\n", + "* openai-chat-new:gpt-3.5-turbo-0301\n", + "\n", + "sagemaker-endpoint\n", + "* This provider does not define a list of models.\n", + "\n" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%ai list" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "cfef0fee-a7c6-49e4-8d90-9aa12f7b91d1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + "\n", + "Socktastic!" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 23, + "metadata": { + "text/markdown": { + "jupyter_ai": { + "custom_chain_id": "company" + } + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "%%ai company\n", + "colorful socks" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "06c698e7-e2cf-41b5-88de-2be4d3b60eba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\n", + "\n", + "Brightly Socks." + ] + }, + "execution_count": 24, + "metadata": { + "jupyter_ai": { + "custom_chain_id": "company" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "%%ai company --format text\n", + "colorful socks" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "7088a6ed-3a56-4249-a7e8-f8d05c287df8", + "id": "849f48a3-9477-4a12-afa6-fd2e79c0764f", "metadata": {}, "outputs": [], "source": [] @@ -838,7 +1132,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.10.8" } }, "nbformat": 4, diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 7441ee701..389632c6d 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -221,13 +221,16 @@ def _validate_name(self, register_name): # Initially set or update an alias to a target def _safely_set_target(self, register_name, target): - # If target is a string, treat this as an alias. - if (isinstance(target, str)): + # If target is a string, treat this as an alias to another model. + if self._is_langchain_chain(target): + ip = get_ipython() + self.custom_model_registry[register_name] = ip.user_ns[target] + else: # Ensure that the destination is properly formatted if (':' not in target): raise ValueError('Target model was not specified in PROVIDER_ID:MODEL_NAME format') - self.custom_model_registry[register_name] = target + self.custom_model_registry[register_name] = target def _ai_delete_command(self, register_name): if (register_name in AI_COMMANDS): @@ -249,10 +252,6 @@ def _ai_register_command(self, register_name, target): raise ValueError('This name is already associated with a custom model; ' + 'use %ai update to change its target') - # Is this the name of a variable? - if self._is_langchain_chain(target): - return f"`{target}` is a LangChain chain" - # Does the new name match expected format? self._validate_name(register_name) @@ -290,8 +289,13 @@ def _ai_list_command_markdown(self, single_provider=None): + "| Name | Target |\n" + "|------|--------|\n") for key, value in self.custom_model_registry.items(): - # TODO: Handle cases where value is not a string - output += f"| `{key}` | `{value}` |\n" + output += f"| `{key}` | " + if isinstance(value, str): + output += f"`{value}`" + else: + output += "*(custom chain)*" + + output += " |\n" return output @@ -354,8 +358,8 @@ def _append_exchange_openai(self, prompt: str, output: str): def _decompose_model_id(self, model_id: str): """Breaks down a model ID into a two-tuple (provider_id, local_model_id). Returns (None, None) if indeterminate.""" - if model_id in MODEL_ID_ALIASES: - model_id = MODEL_ID_ALIASES[model_id] + if model_id in self.custom_model_registry: + model_id = self.custom_model_registry[model_id] return decompose_model_id(model_id, self.providers) @@ -365,6 +369,34 @@ def _get_provider(self, provider_id: Optional[str]) -> BaseProvider: return None return self.providers[provider_id] + + def display_output(self, output, display_format, md): + # build output display + DisplayClass = DISPLAYS_BY_FORMAT[display_format] + + # if the user wants code, add another cell with the output. + if display_format == 'code': + # Strip a leading language indicator and trailing triple-backticks + lang_indicator = r'^```[a-zA-Z0-9]*\n' + output = re.sub(lang_indicator, '', output) + output = re.sub(r'\n```$', '', output) + new_cell_payload = dict( + source='set_next_input', + text=output, + replace=False, + ) + ip.payload_manager.write_payload(new_cell_payload) + return HTML('AI generated code inserted below ⬇️', metadata=md); + + if DisplayClass is None: + return output + if display_format == 'json': + # JSON display expects a dict, not a JSON string + output = json.loads(output) + output_display = DisplayClass(output, metadata=md) + + # finally, display output display + return output_display def handle_help(self, _: HelpArgs): with click.Context(cell_magic_parser, info_name="%%ai") as ctx: @@ -383,7 +415,24 @@ def run_ai_cell(self, args: CellArgs, prompt: str): # Apply a prompt template. prompt = PROMPT_TEMPLATES_BY_FORMAT[args.format].format(prompt = prompt) - # determine provider and local model IDs + # interpolate user namespace into prompt + ip = get_ipython() + prompt = prompt.format_map(FormatDict(ip.user_ns)) + + # Determine provider and local model IDs + # If this is a custom chain, send the message to the custom chain. + if (args.model_id in self.custom_model_registry and + isinstance(self.custom_model_registry[args.model_id], LLMChain)): + + return self.display_output( + self.custom_model_registry[args.model_id].run(prompt), + args.format, + { + "jupyter_ai": { + "custom_chain_id": args.model_id + } + }) + provider_id, local_model_id = self._decompose_model_id(args.model_id) Provider = self._get_provider(provider_id) if Provider is None: @@ -424,9 +473,6 @@ def run_ai_cell(self, args: CellArgs, prompt: str): if provider_id == "openai-chat": self._append_exchange_openai(prompt, output) - # build output display - DisplayClass = DISPLAYS_BY_FORMAT[args.format] - md = { "jupyter_ai": { "provider_id": provider_id, From 3384e3b3f97fe7ed55ac01355267ea486d51000c Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 9 May 2023 15:35:36 -0700 Subject: [PATCH 13/24] Updates user docs for aliases --- docs/source/users/index.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/source/users/index.md b/docs/source/users/index.md index 30b1ddfc6..deeabbe79 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -548,7 +548,7 @@ As a shortcut for explaining errors, you can use the `%ai error` command, which %ai error anthropic:claude-v1.2 ``` -### Creating and managing aliases for models +### Creating and managing aliases You can create an alias for a model using the `%ai register` command. For example, the command: @@ -563,7 +563,28 @@ will register the alias `claude` as pointing to the `anthropic` provider's `clau Write a poem about C++. ``` -You can change this alias's target model using the `%ai update` command: +You can also define a custom LangChain chain: + +``` +from langchain.chains import LLMChain +from langchain.prompts import PromptTemplate +from langchain.llms import OpenAI + +llm = OpenAI(temperature=0.9) +prompt = PromptTemplate( + input_variables=["product"], + template="What is a good name for a company that makes {product}?", +) +chain = LLMChain(llm=llm, prompt=prompt) +``` + +… and then use `%ai register` to give it a name: + +``` +%ai register companyname chain +``` + +You can change this alias's target using the `%ai update` command: ``` %ai update claude anthropic:claude-instant-v1.0 @@ -579,4 +600,4 @@ You can see a list of all aliases by running the `%ai list` command. Aliases' names can contain ASCII letters (uppercase and lowercase), numbers, hyphens, underscores, and periods. They may not contain colons. They may also not override built-in commands — run `%ai help` for a list of these commands. -Aliases must refer to models; they cannot refer to other aliases. +Aliases must refer to models or `LLMChain` objects; they cannot refer to other aliases. From fff7af6cb6dd67983c135415d67b23ced29bd0b6 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 9 May 2023 15:37:29 -0700 Subject: [PATCH 14/24] Edits sample notebook --- examples/commands.ipynb | 172 ++++++++-------------------------------- 1 file changed, 32 insertions(+), 140 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index f090af834..550761316 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -281,116 +281,6 @@ { "cell_type": "code", "execution_count": 6, - "id": "b56ff0e3-42c2-4927-affd-be6a089dfa43", - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "Usage: `%ai register NAME TARGET`" - ], - "text/plain": [ - "Usage: %ai register NAME TARGET\n" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%ai register foo" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "f1400b59-5783-454a-b8ad-f69b2c7a7178", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "ename": "ValueError", - "evalue": "Target model was not specified in PROVIDER_ID:MODEL_NAME format", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:482\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 479\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 481\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 482\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 485\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:362\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 359\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 360\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 362\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 364\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 365\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:275\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 272\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[1;32m 273\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_validate_name(register_name)\n\u001b[0;32m--> 275\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_safely_set_target\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 276\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:248\u001b[0m, in \u001b[0;36mAiMagics._safely_set_target\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 245\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 246\u001b[0m \u001b[38;5;66;03m# Ensure that the destination is properly formatted\u001b[39;00m\n\u001b[1;32m 247\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m:\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m target):\n\u001b[0;32m--> 248\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTarget model was not specified in PROVIDER_ID:MODEL_NAME format\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 250\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry[register_name] \u001b[38;5;241m=\u001b[39m target\n", - "\u001b[0;31mValueError\u001b[0m: Target model was not specified in PROVIDER_ID:MODEL_NAME format" - ] - } - ], - "source": [ - "%ai register foo bar" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "c4ff8026-7423-4e40-96bd-cd96ef2b8003", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "ename": "ValueError", - "evalue": "This name is reserved for a command", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister list bar\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:482\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 479\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 481\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 482\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 485\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:362\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 359\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 360\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 362\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 364\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 365\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:265\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 262\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ai_register_command\u001b[39m(\u001b[38;5;28mself\u001b[39m, register_name, target):\n\u001b[1;32m 263\u001b[0m \u001b[38;5;66;03m# Existing command names are not allowed\u001b[39;00m\n\u001b[1;32m 264\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[0;32m--> 265\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is reserved for a command\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 267\u001b[0m \u001b[38;5;66;03m# Existing registered names are not allowed\u001b[39;00m\n\u001b[1;32m 268\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (register_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcustom_model_registry):\n", - "\u001b[0;31mValueError\u001b[0m: This name is reserved for a command" - ] - } - ], - "source": [ - "%ai register list bar" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "b77706d7-0c3a-409d-b909-d9f58d35ce4e", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "ename": "ValueError", - "evalue": "A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[9], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mregister foo:bar baz\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:482\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 479\u001b[0m \u001b[38;5;66;03m# If the user is attempting to run a command, run the command separately.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (args\u001b[38;5;241m.\u001b[39mmodel_id \u001b[38;5;129;01min\u001b[39;00m AI_COMMANDS):\n\u001b[1;32m 481\u001b[0m \u001b[38;5;66;03m# The \"prompt\" is a list of arguments to the command, whitespace-delimited\u001b[39;00m\n\u001b[0;32m--> 482\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[38;5;66;03m# Apply a prompt template.\u001b[39;00m\n\u001b[1;32m 485\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PROMPT_TEMPLATES_BY_FORMAT[args\u001b[38;5;241m.\u001b[39mformat]\u001b[38;5;241m.\u001b[39mformat(prompt \u001b[38;5;241m=\u001b[39m prompt)\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:362\u001b[0m, in \u001b[0;36mAiMagics._ai_command\u001b[0;34m(self, command, args_string)\u001b[0m\n\u001b[1;32m 359\u001b[0m register_name \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 360\u001b[0m target \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m--> 362\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_ai_register_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m TextOrMarkdown(output, output)\n\u001b[1;32m 364\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m (command \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdelete\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[1;32m 365\u001b[0m \u001b[38;5;66;03m# Parameters: name\u001b[39;00m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:273\u001b[0m, in \u001b[0;36mAiMagics._ai_register_command\u001b[0;34m(self, register_name, target)\u001b[0m\n\u001b[1;32m 269\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis name is already associated with a custom model; \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 270\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124muse \u001b[39m\u001b[38;5;132;01m%a\u001b[39;00m\u001b[38;5;124mi update to change its target\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 272\u001b[0m \u001b[38;5;66;03m# Does the new name match expected format?\u001b[39;00m\n\u001b[0;32m--> 273\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_name\u001b[49m\u001b[43m(\u001b[49m\u001b[43mregister_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 275\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_safely_set_target(register_name, target)\n\u001b[1;32m 276\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRegistered new name `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mregister_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:236\u001b[0m, in \u001b[0;36mAiMagics._validate_name\u001b[0;34m(self, register_name)\u001b[0m\n\u001b[1;32m 234\u001b[0m acceptable_name \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39mcompile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m^[a-zA-Z0-9._-]+$\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 235\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;129;01mnot\u001b[39;00m acceptable_name\u001b[38;5;241m.\u001b[39mmatch(register_name)):\n\u001b[0;32m--> 236\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA registry name may contain ASCII letters, numbers, hyphens, underscores, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 237\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand periods. No other characters, including a colon, are permitted\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "\u001b[0;31mValueError\u001b[0m: A registry name may contain ASCII letters, numbers, hyphens, underscores, and periods. No other characters, including a colon, are permitted" - ] - } - ], - "source": [ - "%ai register foo:bar baz" - ] - }, - { - "cell_type": "code", - "execution_count": 10, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [ @@ -403,7 +293,7 @@ "Registered new name `mychat`" ] }, - "execution_count": 10, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -414,7 +304,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 7, "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", "metadata": { "tags": [] @@ -509,7 +399,7 @@ "\n" ] }, - "execution_count": 11, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -520,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 8, "id": "ea75ac14-d83d-45b4-8c1d-40e4fbc1d263", "metadata": { "tags": [] @@ -537,7 +427,7 @@ "" ] }, - "execution_count": 12, + "execution_count": 8, "metadata": { "text/markdown": { "jupyter_ai": { @@ -556,7 +446,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 9, "id": "3e7fb7fb-d61c-4909-959b-14bc97af409a", "metadata": {}, "outputs": [ @@ -569,7 +459,7 @@ "Updated target of name `mychat`" ] }, - "execution_count": 13, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -580,7 +470,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 10, "id": "a89a4c2a-b37f-4a3d-86cb-67747113d3d7", "metadata": { "tags": [] @@ -597,7 +487,7 @@ "" ] }, - "execution_count": 14, + "execution_count": 10, "metadata": { "text/markdown": { "jupyter_ai": { @@ -616,7 +506,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 11, "id": "c7453152-6c70-4f91-bef6-4ae38d700f52", "metadata": { "tags": [] @@ -711,7 +601,7 @@ "\n" ] }, - "execution_count": 15, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -722,7 +612,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 12, "id": "971f823d-8f35-4201-a6cb-12a21a87628a", "metadata": { "tags": [] @@ -737,7 +627,7 @@ "Deleted name `mychat`" ] }, - "execution_count": 16, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -748,7 +638,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 13, "id": "6fb1b54a-ee4f-41c0-b666-ea9e0a1279ee", "metadata": { "tags": [] @@ -842,7 +732,7 @@ "\n" ] }, - "execution_count": 17, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -863,13 +753,14 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 14, "id": "9ef639c7-1ca8-48af-b5e5-f76cfa5779f3", "metadata": { "tags": [] }, "outputs": [], "source": [ + "from langchain.chains import LLMChain\n", "from langchain.prompts import PromptTemplate\n", "from langchain.llms import OpenAI\n", "\n", @@ -877,12 +768,13 @@ "prompt = PromptTemplate(\n", " input_variables=[\"product\"],\n", " template=\"What is a good name for a company that makes {product}?\",\n", - ")" + ")\n", + "chain = LLMChain(llm=llm, prompt=prompt)" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 15, "id": "29d5239f-7601-405e-b059-4e881ebf7ab1", "metadata": { "tags": [] @@ -895,7 +787,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 16, "id": "43e7a77c-93af-4ef7-a104-f932c9f54183", "metadata": { "tags": [] @@ -907,7 +799,7 @@ "text": [ "\n", "\n", - "Rainbow Toes Sock Co.\n" + "Rainbow Socks Co.\n" ] } ], @@ -918,7 +810,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 17, "id": "9badc567-9720-4e33-ab4a-54fda5129f36", "metadata": { "tags": [] @@ -933,7 +825,7 @@ "Registered new name `company`" ] }, - "execution_count": 21, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -944,7 +836,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 18, "id": "92b75d71-8844-4872-b424-b0023706abb1", "metadata": {}, "outputs": [ @@ -1037,7 +929,7 @@ "\n" ] }, - "execution_count": 22, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -1048,7 +940,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 19, "id": "cfef0fee-a7c6-49e4-8d90-9aa12f7b91d1", "metadata": {}, "outputs": [ @@ -1057,13 +949,13 @@ "text/markdown": [ "\n", "\n", - "Socktastic!" + "# Colorful Socks Co." ], "text/plain": [ "" ] }, - "execution_count": 23, + "execution_count": 19, "metadata": { "text/markdown": { "jupyter_ai": { @@ -1081,7 +973,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 20, "id": "06c698e7-e2cf-41b5-88de-2be4d3b60eba", "metadata": {}, "outputs": [ @@ -1090,10 +982,10 @@ "text/plain": [ "\n", "\n", - "Brightly Socks." + "Vibrant Socks Co." ] }, - "execution_count": 24, + "execution_count": 20, "metadata": { "jupyter_ai": { "custom_chain_id": "company" From ce2e72656ba97022d3d25eb41205c23fa8fce33c Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 9 May 2023 16:18:03 -0700 Subject: [PATCH 15/24] Alias list in text display, updates messaging --- .../jupyter_ai_magics/magics.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 389632c6d..82146dd2e 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -228,7 +228,8 @@ def _safely_set_target(self, register_name, target): else: # Ensure that the destination is properly formatted if (':' not in target): - raise ValueError('Target model was not specified in PROVIDER_ID:MODEL_NAME format') + raise ValueError( + 'Target model must be an LLMChain object or a model name in PROVIDER_ID:MODEL_NAME format') self.custom_model_registry[register_name] = target @@ -293,7 +294,7 @@ def _ai_list_command_markdown(self, single_provider=None): if isinstance(value, str): output += f"`{value}`" else: - output += "*(custom chain)*" + output += "*custom chain*" output += " |\n" @@ -312,6 +313,18 @@ def _ai_list_command_text(self, single_provider=None): + self._ai_env_status_for_provider_text(provider_id) # includes \n if nonblank + self._ai_bulleted_list_models_for_provider(provider_id, Provider)) + # Also list aliases. + if (single_provider is None and len(self.custom_model_registry) > 0): + output += "\nAliases and custom commands:\n" + for key, value in self.custom_model_registry.items(): + output += f"{key} - " + if isinstance(value, str): + output += value + else: + output += "custom chain" + + output += "\n" + return output def handle_error(self, args: ErrorArgs): From 0bfbe84a3009eba3d207aa61e3b0d41ac8edb5e7 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 9 May 2023 16:39:10 -0700 Subject: [PATCH 16/24] Updates sample workbook --- examples/commands.ipynb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 550761316..53409fad3 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -838,7 +838,14 @@ "cell_type": "code", "execution_count": 18, "id": "92b75d71-8844-4872-b424-b0023706abb1", - "metadata": {}, + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true, + "source_hidden": true + }, + "tags": [] + }, "outputs": [ { "data": { From 9e7a4554ae7b2b3be12eece500e7291583645503 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Wed, 31 May 2023 15:05:28 -0700 Subject: [PATCH 17/24] Updates sample notebook, parsers to use click --- examples/commands.ipynb | 185 ++++++++++++------ .../jupyter_ai_magics/magics.py | 65 +++--- .../jupyter_ai_magics/parsers.py | 40 ++++ 3 files changed, 203 insertions(+), 87 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 53409fad3..9ba58c77f 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -43,27 +43,61 @@ }, "outputs": [ { - "data": { - "text/markdown": [ - "| Command | Description | Usage |\n", - "| ------- | ----------- | ----- |\n", - "| `help` | Display a list of supported commands | `%ai help` |\n", - "| `list` | Display a list of models that you can use (optionally, for a single provider) | `%ai list [PROVIDER_ID]` |\n", - "| `register` | Add an alias to a model or a LangChain chain for use with %ai magic commands | `%ai register NAME TARGET` |\n", - "| `delete` | Delete a previously registered alias | `%ai delete NAME` |\n", - "| `update` | Update a previously registered alias | `%ai update NAME TARGET` |\n" - ], - "text/plain": [ - "help - Display a list of supported commands\n", - "list - Display a list of models that you can use (optionally, for a single provider)\n", - "register - Add an alias to a model or a LangChain chain for use with %ai magic commands\n", - "delete - Delete a previously registered alias\n", - "update - Update a previously registered alias\n" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Usage: %%ai [OPTIONS] MODEL_ID\n", + "\n", + " Invokes a language model identified by MODEL_ID, with the prompt being\n", + " contained in all lines after the first. Both local model IDs and global\n", + " model IDs (with the provider ID explicitly prefixed, followed by a colon)\n", + " are accepted.\n", + "\n", + " To view available language models, please run `%ai list`.\n", + "\n", + "Options:\n", + " -f, --format [code|html|image|json|markdown|math|md|text]\n", + " IPython display to use when rendering\n", + " output. [default=\"markdown\"]\n", + " -r, --reset Clears the conversation transcript used when\n", + " interacting with an OpenAI chat model\n", + " provider. Does nothing with other providers.\n", + " --help Show this message and exit.\n", + "------------------------------------------------------------------------------\n", + "Usage: %%ai [OPTIONS] MODEL_ID\n", + "\n", + " Invokes a language model identified by MODEL_ID, with the prompt being\n", + " contained in all lines after the first. Both local model IDs and global\n", + " model IDs (with the provider ID explicitly prefixed, followed by a colon)\n", + " are accepted.\n", + "\n", + " To view available language models, please run `%ai list`.\n", + "\n", + "Options:\n", + " -f, --format [code|html|image|json|markdown|math|md|text]\n", + " IPython display to use when rendering\n", + " output. [default=\"markdown\"]\n", + " -r, --reset Clears the conversation transcript used when\n", + " interacting with an OpenAI chat model\n", + " provider. Does nothing with other providers.\n", + " --help Show this message and exit.\n", + "------------------------------------------------------------------------------\n", + "Usage: %ai [OPTIONS] COMMAND [ARGS]...\n", + "\n", + " Invokes a subcommand.\n", + "\n", + "Options:\n", + " --help Show this message and exit.\n", + "\n", + "Commands:\n", + " delete Delete an alias. See `%ai delete --help` for options.\n", + " help Show this message and exit.\n", + " list List language models. See `%ai list --help` for options.\n", + " register Register a new alias. See `%ai register --help` for options.\n", + " update Update the target of an alias. See `%ai update --help` for\n", + " options.\n", + "\n" + ] } ], "source": [ @@ -103,25 +137,22 @@ "metadata": {}, "outputs": [ { - "data": { - "text/markdown": [ - "Cannot determine model provider from model ID `foo`.\n", - "\n", - "To see a list of models you can use, run `%ai list`\n", - "\n", - "If you were trying to run a command, run `%ai help` to see a list of commands." - ], - "text/plain": [ - "Cannot determine model provider from model ID 'foo'.\n", - "\n", - "To see a list of models you can use, run '%ai list'\n", - "\n", - "If you were trying to run a command, run '%ai help' to see a list of commands." - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" + "ename": "UsageError", + "evalue": "No such command 'foo'.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mUsageError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mfoo\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:415\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 413\u001b[0m args \u001b[38;5;241m=\u001b[39m cell_magic_parser(raw_args, prog_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m%%\u001b[39;00m\u001b[38;5;124mai\u001b[39m\u001b[38;5;124m\"\u001b[39m, standalone_mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[1;32m 414\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 415\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[43mline_magic_parser\u001b[49m\u001b[43m(\u001b[49m\u001b[43mraw_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprog_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;132;43;01m%a\u001b[39;49;00m\u001b[38;5;124;43mi\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstandalone_mode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 417\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 418\u001b[0m \u001b[38;5;66;03m# this happens when `--help` is called on the root command, in which\u001b[39;00m\n\u001b[1;32m 419\u001b[0m \u001b[38;5;66;03m# case we want to exit early.\u001b[39;00m\n\u001b[1;32m 420\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1130\u001b[0m, in \u001b[0;36mBaseCommand.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1128\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs: t\u001b[38;5;241m.\u001b[39mAny, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: t\u001b[38;5;241m.\u001b[39mAny) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m t\u001b[38;5;241m.\u001b[39mAny:\n\u001b[1;32m 1129\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Alias for :meth:`main`.\"\"\"\u001b[39;00m\n\u001b[0;32m-> 1130\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1055\u001b[0m, in \u001b[0;36mBaseCommand.main\u001b[0;34m(self, args, prog_name, complete_var, standalone_mode, windows_expand_args, **extra)\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1054\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmake_context(prog_name, args, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mextra) \u001b[38;5;28;01mas\u001b[39;00m ctx:\n\u001b[0;32m-> 1055\u001b[0m rv \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43mctx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1056\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m standalone_mode:\n\u001b[1;32m 1057\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m rv\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1651\u001b[0m, in \u001b[0;36mMultiCommand.invoke\u001b[0;34m(self, ctx)\u001b[0m\n\u001b[1;32m 1647\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mchain:\n\u001b[1;32m 1648\u001b[0m \u001b[38;5;66;03m# Make sure the context is entered so we do not clean up\u001b[39;00m\n\u001b[1;32m 1649\u001b[0m \u001b[38;5;66;03m# resources until the result processor has worked.\u001b[39;00m\n\u001b[1;32m 1650\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m ctx:\n\u001b[0;32m-> 1651\u001b[0m cmd_name, cmd, args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresolve_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mctx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1652\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m cmd \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1653\u001b[0m ctx\u001b[38;5;241m.\u001b[39minvoked_subcommand \u001b[38;5;241m=\u001b[39m cmd_name\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1715\u001b[0m, in \u001b[0;36mMultiCommand.resolve_command\u001b[0;34m(self, ctx, args)\u001b[0m\n\u001b[1;32m 1713\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m split_opt(cmd_name)[\u001b[38;5;241m0\u001b[39m]:\n\u001b[1;32m 1714\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_args(ctx, ctx\u001b[38;5;241m.\u001b[39margs)\n\u001b[0;32m-> 1715\u001b[0m \u001b[43mctx\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfail\u001b[49m\u001b[43m(\u001b[49m\u001b[43m_\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mNo such command \u001b[39;49m\u001b[38;5;132;43;01m{name!r}\u001b[39;49;00m\u001b[38;5;124;43m.\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mformat\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moriginal_cmd_name\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1716\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m cmd_name \u001b[38;5;28;01mif\u001b[39;00m cmd \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, cmd, args[\u001b[38;5;241m1\u001b[39m:]\n", + "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:679\u001b[0m, in \u001b[0;36mContext.fail\u001b[0;34m(self, message)\u001b[0m\n\u001b[1;32m 673\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfail\u001b[39m(\u001b[38;5;28mself\u001b[39m, message: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mte.NoReturn\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 674\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Aborts the execution of the program with a specific error\u001b[39;00m\n\u001b[1;32m 675\u001b[0m \u001b[38;5;124;03m message.\u001b[39;00m\n\u001b[1;32m 676\u001b[0m \n\u001b[1;32m 677\u001b[0m \u001b[38;5;124;03m :param message: the error message to fail with.\u001b[39;00m\n\u001b[1;32m 678\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 679\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m UsageError(message, \u001b[38;5;28mself\u001b[39m)\n", + "\u001b[0;31mUsageError\u001b[0m: No such command 'foo'." + ] } ], "source": [ @@ -219,7 +250,13 @@ "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", - "\n" + "\n", + "\n", + "Aliases and custom commands:\n", + "gpt2 - huggingface_hub:gpt2\n", + "gpt3 - openai:text-davinci-003\n", + "chatgpt - openai-chat:gpt-3.5-turbo\n", + "gpt4 - openai-chat:gpt-4\n" ] }, "execution_count": 5, @@ -287,10 +324,10 @@ { "data": { "text/markdown": [ - "Registered new name `mychat`" + "Registered new alias `mychat`" ], "text/plain": [ - "Registered new name `mychat`" + "Registered new alias `mychat`" ] }, "execution_count": 6, @@ -396,7 +433,14 @@ "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", - "\n" + "\n", + "\n", + "Aliases and custom commands:\n", + "gpt2 - huggingface_hub:gpt2\n", + "gpt3 - openai:text-davinci-003\n", + "chatgpt - openai-chat:gpt-3.5-turbo\n", + "gpt4 - openai-chat:gpt-4\n", + "mychat - openai-chat:gpt-4\n" ] }, "execution_count": 7, @@ -421,7 +465,7 @@ "text/markdown": [ "\n", "\n", - "It is not possible to answer this question without additional information." + "This is not a specific model." ], "text/plain": [ "" @@ -453,10 +497,10 @@ { "data": { "text/markdown": [ - "Updated target of name `mychat`" + "Updated target of alias `mychat`" ], "text/plain": [ - "Updated target of name `mychat`" + "Updated target of alias `mychat`" ] }, "execution_count": 9, @@ -598,7 +642,14 @@ "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", - "\n" + "\n", + "\n", + "Aliases and custom commands:\n", + "gpt2 - huggingface_hub:gpt2\n", + "gpt3 - openai:text-davinci-003\n", + "chatgpt - openai-chat:gpt-3.5-turbo\n", + "gpt4 - openai-chat:gpt-4\n", + "mychat - openai:text-davinci-003\n" ] }, "execution_count": 11, @@ -621,10 +672,10 @@ { "data": { "text/markdown": [ - "Deleted name `mychat`" + "Deleted alias `mychat`" ], "text/plain": [ - "Deleted name `mychat`" + "Deleted alias `mychat`" ] }, "execution_count": 12, @@ -729,7 +780,13 @@ "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", - "\n" + "\n", + "\n", + "Aliases and custom commands:\n", + "gpt2 - huggingface_hub:gpt2\n", + "gpt3 - openai:text-davinci-003\n", + "chatgpt - openai-chat:gpt-3.5-turbo\n", + "gpt4 - openai-chat:gpt-4\n" ] }, "execution_count": 13, @@ -799,7 +856,7 @@ "text": [ "\n", "\n", - "Rainbow Socks Co.\n" + "Rainbow Footwear.\n" ] } ], @@ -819,10 +876,10 @@ { "data": { "text/markdown": [ - "Registered new name `company`" + "Registered new alias `company`" ], "text/plain": [ - "Registered new name `company`" + "Registered new alias `company`" ] }, "execution_count": 17, @@ -839,11 +896,6 @@ "execution_count": 18, "id": "92b75d71-8844-4872-b424-b0023706abb1", "metadata": { - "collapsed": true, - "jupyter": { - "outputs_hidden": true, - "source_hidden": true - }, "tags": [] }, "outputs": [ @@ -869,7 +921,7 @@ "| `gpt3` | `openai:text-davinci-003` |\n", "| `chatgpt` | `openai-chat:gpt-3.5-turbo` |\n", "| `gpt4` | `openai-chat:gpt-4` |\n", - "| `company` | *(custom chain)* |\n" + "| `company` | *custom chain* |\n" ], "text/plain": [ "ai21\n", @@ -933,7 +985,14 @@ "\n", "sagemaker-endpoint\n", "* This provider does not define a list of models.\n", - "\n" + "\n", + "\n", + "Aliases and custom commands:\n", + "gpt2 - huggingface_hub:gpt2\n", + "gpt3 - openai:text-davinci-003\n", + "chatgpt - openai-chat:gpt-3.5-turbo\n", + "gpt4 - openai-chat:gpt-4\n", + "company - custom chain\n" ] }, "execution_count": 18, @@ -956,7 +1015,7 @@ "text/markdown": [ "\n", "\n", - "# Colorful Socks Co." + "**Kaleidosocks**" ], "text/plain": [ "" @@ -989,7 +1048,7 @@ "text/plain": [ "\n", "\n", - "Vibrant Socks Co." + "Fancy Footwear Socks." ] }, "execution_count": 20, diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 82146dd2e..2a403263e 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -13,7 +13,15 @@ from jupyter_ai_magics.utils import decompose_model_id, load_providers from .providers import BaseProvider -from .parsers import cell_magic_parser, line_magic_parser, CellArgs, ErrorArgs, HelpArgs, ListArgs +from .parsers import (cell_magic_parser, + line_magic_parser, + CellArgs, + DeleteArgs, + ErrorArgs, + HelpArgs, + ListArgs, + RegisterArgs, + UpdateArgs) from langchain.chains import LLMChain @@ -233,41 +241,44 @@ def _safely_set_target(self, register_name, target): self.custom_model_registry[register_name] = target - def _ai_delete_command(self, register_name): - if (register_name in AI_COMMANDS): - raise ValueError('Reserved command names cannot be deleted') + def handle_delete(self, args: DeleteArgs): + if (args.name in AI_COMMANDS): + raise ValueError(f"Reserved command names, including {args.name}, cannot be deleted") - if (register_name not in self.custom_model_registry): - raise ValueError(f"There is no alias called {register_name}") + if (args.name not in self.custom_model_registry): + raise ValueError(f"There is no alias called {args.name}") - del self.custom_model_registry[register_name] - return f"Deleted name `{register_name}`" + del self.custom_model_registry[args.name] + output = f"Deleted alias `{args.name}`" + return TextOrMarkdown(output, output) - def _ai_register_command(self, register_name, target): + def handle_register(self, args: RegisterArgs): # Existing command names are not allowed - if (register_name in AI_COMMANDS): - raise ValueError('This name is reserved for a command') + if (args.name in AI_COMMANDS): + raise ValueError(f"The name {args.name} is reserved for a command") # Existing registered names are not allowed - if (register_name in self.custom_model_registry): - raise ValueError('This name is already associated with a custom model; ' + if (args.name in self.custom_model_registry): + raise ValueError(f"The name {args.name} is already associated with a custom model; " + 'use %ai update to change its target') # Does the new name match expected format? - self._validate_name(register_name) + self._validate_name(args.name) - self._safely_set_target(register_name, target) - return f"Registered new name `{register_name}`" + self._safely_set_target(args.name, args.target) + output = f"Registered new alias `{args.name}`" + return TextOrMarkdown(output, output) - def _ai_update_command(self, register_name, target): - if (register_name in AI_COMMANDS): - raise ValueError('Reserved command names cannot be updated') + def handle_update(self, args: UpdateArgs): + if (args.name in AI_COMMANDS): + raise ValueError(f"Reserved command names, including {args.name}, cannot be updated") - if (register_name not in self.custom_model_registry): - raise ValueError(f"There is no alias called {register_name}") + if (args.name not in self.custom_model_registry): + raise ValueError(f"There is no alias called {args.name}") - self._safely_set_target(register_name, target) - return f"Updated target of name `{register_name}`" + self._safely_set_target(args.name, args.target) + output = f"Updated target of alias `{args.name}`" + return TextOrMarkdown(output, output) def _ai_list_command_markdown(self, single_provider=None): output = ("| Provider | Environment variable | Set? | Models |\n" @@ -537,7 +548,13 @@ def ai(self, line, cell=None): return self.handle_help(args) if args.type == "list": return self.handle_list(args) - + if args.type == "register": + return self.handle_register(args) + if args.type == "delete": + return self.handle_delete(args) + if args.type == "update": + return self.handle_update(args) + # hint to the IDE that this object must be of type `RootArgs` args: CellArgs = args diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py b/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py index c4820f5f4..db63cd4da 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py @@ -25,6 +25,20 @@ class ListArgs(BaseModel): type: Literal["list"] = "list" provider_id: Optional[str] +class RegisterArgs(BaseModel): + type: Literal["register"] = "register" + name: str + target: str + +class DeleteArgs(BaseModel): + type: Literal["delete"] = "delete" + name: str + +class UpdateArgs(BaseModel): + type: Literal["update"] = "update" + name: str + target: str + class LineMagicGroup(click.Group): """Helper class to print the help string for cell magics as well when `%ai --help` is called.""" @@ -89,3 +103,29 @@ def help_subparser(): def list_subparser(**kwargs): """List language models, optionally scoped to PROVIDER_ID.""" return ListArgs(**kwargs) + +@line_magic_parser.command(name='register', + short_help="Register a new alias. See `%ai register --help` for options." +) +@click.argument('name') +@click.argument('target') +def register_subparser(**kwargs): + """Register a new alias called NAME for the model or chain named TARGET.""" + return RegisterArgs(**kwargs) + +@line_magic_parser.command(name='delete', + short_help="Delete an alias. See `%ai delete --help` for options." +) +@click.argument('name') +def register_subparser(**kwargs): + """Delete an alias called NAME.""" + return DeleteArgs(**kwargs) + +@line_magic_parser.command(name='update', + short_help="Update the target of an alias. See `%ai update --help` for options." +) +@click.argument('name') +@click.argument('target') +def register_subparser(**kwargs): + """Update an alias called NAME to refer to the model or chain named TARGET.""" + return UpdateArgs(**kwargs) From 4726d17fda0b7f8c1f4f93524bdb3a2c12fadad1 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Wed, 31 May 2023 15:10:26 -0700 Subject: [PATCH 18/24] Additional cleanup --- examples/commands.ipynb | 91 +++++++++---------- .../jupyter_ai_magics/magics.py | 6 -- 2 files changed, 45 insertions(+), 52 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index 9ba58c77f..b72e0444c 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -107,27 +107,26 @@ { "cell_type": "code", "execution_count": 3, - "id": "e1f2b767-0834-4b21-b132-093730efaffb", + "id": "1f249bdc-410b-42f4-b21b-b7bde9e06387", "metadata": { "tags": [] }, "outputs": [ { - "data": { - "text/markdown": [ - "There have been no errors since the kernel started." - ], - "text/plain": [ - "There have been no errors since the kernel started." - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Usage: %ai register [OPTIONS] NAME TARGET\n", + "\n", + " Register a new alias called NAME for the model or chain named TARGET.\n", + "\n", + "Options:\n", + " --help Show this message and exit.\n" + ] } ], "source": [ - "%ai error chatgpt" + "%ai register --help" ] }, { @@ -143,9 +142,9 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mUsageError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mfoo\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mfoo\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:415\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 413\u001b[0m args \u001b[38;5;241m=\u001b[39m cell_magic_parser(raw_args, prog_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m%%\u001b[39;00m\u001b[38;5;124mai\u001b[39m\u001b[38;5;124m\"\u001b[39m, standalone_mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[1;32m 414\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 415\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[43mline_magic_parser\u001b[49m\u001b[43m(\u001b[49m\u001b[43mraw_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprog_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;132;43;01m%a\u001b[39;49;00m\u001b[38;5;124;43mi\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstandalone_mode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 417\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 418\u001b[0m \u001b[38;5;66;03m# this happens when `--help` is called on the root command, in which\u001b[39;00m\n\u001b[1;32m 419\u001b[0m \u001b[38;5;66;03m# case we want to exit early.\u001b[39;00m\n\u001b[1;32m 420\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n", + "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:398\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 396\u001b[0m args \u001b[38;5;241m=\u001b[39m cell_magic_parser(raw_args, prog_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m%%\u001b[39;00m\u001b[38;5;124mai\u001b[39m\u001b[38;5;124m\"\u001b[39m, standalone_mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[1;32m 397\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 398\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[43mline_magic_parser\u001b[49m\u001b[43m(\u001b[49m\u001b[43mraw_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprog_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;132;43;01m%a\u001b[39;49;00m\u001b[38;5;124;43mi\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstandalone_mode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 400\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 401\u001b[0m \u001b[38;5;66;03m# this happens when `--help` is called on the root command, in which\u001b[39;00m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# case we want to exit early.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1130\u001b[0m, in \u001b[0;36mBaseCommand.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1128\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs: t\u001b[38;5;241m.\u001b[39mAny, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: t\u001b[38;5;241m.\u001b[39mAny) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m t\u001b[38;5;241m.\u001b[39mAny:\n\u001b[1;32m 1129\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Alias for :meth:`main`.\"\"\"\u001b[39;00m\n\u001b[0;32m-> 1130\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1055\u001b[0m, in \u001b[0;36mBaseCommand.main\u001b[0;34m(self, args, prog_name, complete_var, standalone_mode, windows_expand_args, **extra)\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1054\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmake_context(prog_name, args, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mextra) \u001b[38;5;28;01mas\u001b[39;00m ctx:\n\u001b[0;32m-> 1055\u001b[0m rv \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43mctx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1056\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m standalone_mode:\n\u001b[1;32m 1057\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m rv\n", "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1651\u001b[0m, in \u001b[0;36mMultiCommand.invoke\u001b[0;34m(self, ctx)\u001b[0m\n\u001b[1;32m 1647\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mchain:\n\u001b[1;32m 1648\u001b[0m \u001b[38;5;66;03m# Make sure the context is entered so we do not clean up\u001b[39;00m\n\u001b[1;32m 1649\u001b[0m \u001b[38;5;66;03m# resources until the result processor has worked.\u001b[39;00m\n\u001b[1;32m 1650\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m ctx:\n\u001b[0;32m-> 1651\u001b[0m cmd_name, cmd, args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresolve_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mctx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1652\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m cmd \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1653\u001b[0m ctx\u001b[38;5;241m.\u001b[39minvoked_subcommand \u001b[38;5;241m=\u001b[39m cmd_name\n", @@ -317,7 +316,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [ @@ -330,7 +329,7 @@ "Registered new alias `mychat`" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -341,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", "metadata": { "tags": [] @@ -443,7 +442,7 @@ "mychat - openai-chat:gpt-4\n" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -454,7 +453,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "ea75ac14-d83d-45b4-8c1d-40e4fbc1d263", "metadata": { "tags": [] @@ -465,13 +464,13 @@ "text/markdown": [ "\n", "\n", - "This is not a specific model." + "This model is **unspecified**." ], "text/plain": [ "" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": { "text/markdown": { "jupyter_ai": { @@ -490,7 +489,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "3e7fb7fb-d61c-4909-959b-14bc97af409a", "metadata": {}, "outputs": [ @@ -503,7 +502,7 @@ "Updated target of alias `mychat`" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -514,7 +513,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "a89a4c2a-b37f-4a3d-86cb-67747113d3d7", "metadata": { "tags": [] @@ -531,7 +530,7 @@ "" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": { "text/markdown": { "jupyter_ai": { @@ -550,7 +549,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "c7453152-6c70-4f91-bef6-4ae38d700f52", "metadata": { "tags": [] @@ -652,7 +651,7 @@ "mychat - openai:text-davinci-003\n" ] }, - "execution_count": 11, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -663,7 +662,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "971f823d-8f35-4201-a6cb-12a21a87628a", "metadata": { "tags": [] @@ -678,7 +677,7 @@ "Deleted alias `mychat`" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -689,7 +688,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "6fb1b54a-ee4f-41c0-b666-ea9e0a1279ee", "metadata": { "tags": [] @@ -789,7 +788,7 @@ "gpt4 - openai-chat:gpt-4\n" ] }, - "execution_count": 13, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -810,7 +809,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "9ef639c7-1ca8-48af-b5e5-f76cfa5779f3", "metadata": { "tags": [] @@ -831,7 +830,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "id": "29d5239f-7601-405e-b059-4e881ebf7ab1", "metadata": { "tags": [] @@ -844,7 +843,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "id": "43e7a77c-93af-4ef7-a104-f932c9f54183", "metadata": { "tags": [] @@ -856,7 +855,7 @@ "text": [ "\n", "\n", - "Rainbow Footwear.\n" + "Brightly Socks\n" ] } ], @@ -867,7 +866,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "id": "9badc567-9720-4e33-ab4a-54fda5129f36", "metadata": { "tags": [] @@ -882,7 +881,7 @@ "Registered new alias `company`" ] }, - "execution_count": 17, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -893,7 +892,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "id": "92b75d71-8844-4872-b424-b0023706abb1", "metadata": { "tags": [] @@ -995,7 +994,7 @@ "company - custom chain\n" ] }, - "execution_count": 18, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -1006,7 +1005,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "id": "cfef0fee-a7c6-49e4-8d90-9aa12f7b91d1", "metadata": {}, "outputs": [ @@ -1015,13 +1014,13 @@ "text/markdown": [ "\n", "\n", - "**Kaleidosocks**" + "BrightSox Co." ], "text/plain": [ "" ] }, - "execution_count": 19, + "execution_count": 20, "metadata": { "text/markdown": { "jupyter_ai": { @@ -1039,7 +1038,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "id": "06c698e7-e2cf-41b5-88de-2be4d3b60eba", "metadata": {}, "outputs": [ @@ -1048,10 +1047,10 @@ "text/plain": [ "\n", "\n", - "Fancy Footwear Socks." + "Bright Socks Co." ] }, - "execution_count": 20, + "execution_count": 21, "metadata": { "jupyter_ai": { "custom_chain_id": "company" diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 2a403263e..b86e1a38e 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -80,12 +80,6 @@ def _repr_mimebundle_(self, include=None, exclude=None): NA_MESSAGE = 'N/A' -REGISTER_COMMAND_USAGE = "%ai register NAME TARGET" - -DELETE_COMMAND_USAGE = "%ai delete NAME" - -UPDATE_COMMAND_USAGE = "%ai update NAME TARGET" - MARKDOWN_PROMPT_TEMPLATE = '{prompt}\n\nProduce output in markdown format only.' PROVIDER_NO_MODELS = 'This provider does not define a list of models.' From 09331268e92c3a3681a5c23b4e7269daf8d4059c Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 5 Jun 2023 16:45:27 -0700 Subject: [PATCH 19/24] Updates sample notebook, removes unahppy case --- examples/commands.ipynb | 97 +++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 63 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index b72e0444c..fe223720a 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -132,35 +132,6 @@ { "cell_type": "code", "execution_count": 4, - "id": "0f073caa-265d-40d6-b537-d025b8df9f41", - "metadata": {}, - "outputs": [ - { - "ename": "UsageError", - "evalue": "No such command 'foo'.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mUsageError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_ipython\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_line_magic\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mfoo\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/IPython/core/interactiveshell.py:2417\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m 2415\u001b[0m kwargs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlocal_ns\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m 2416\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2417\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2419\u001b[0m \u001b[38;5;66;03m# The code below prevents the output from being displayed\u001b[39;00m\n\u001b[1;32m 2420\u001b[0m \u001b[38;5;66;03m# when using magics with decodator @output_can_be_silenced\u001b[39;00m\n\u001b[1;32m 2421\u001b[0m \u001b[38;5;66;03m# when the last Python token in the expression is a ';'.\u001b[39;00m\n\u001b[1;32m 2422\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(fn, magic\u001b[38;5;241m.\u001b[39mMAGIC_OUTPUT_CAN_BE_SILENCED, \u001b[38;5;28;01mFalse\u001b[39;00m):\n", - "File \u001b[0;32m~/git/jupyter-ai/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py:398\u001b[0m, in \u001b[0;36mAiMagics.ai\u001b[0;34m(self, line, cell)\u001b[0m\n\u001b[1;32m 396\u001b[0m args \u001b[38;5;241m=\u001b[39m cell_magic_parser(raw_args, prog_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m%%\u001b[39;00m\u001b[38;5;124mai\u001b[39m\u001b[38;5;124m\"\u001b[39m, standalone_mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[1;32m 397\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 398\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[43mline_magic_parser\u001b[49m\u001b[43m(\u001b[49m\u001b[43mraw_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprog_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;132;43;01m%a\u001b[39;49;00m\u001b[38;5;124;43mi\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstandalone_mode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 400\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 401\u001b[0m \u001b[38;5;66;03m# this happens when `--help` is called on the root command, in which\u001b[39;00m\n\u001b[1;32m 402\u001b[0m \u001b[38;5;66;03m# case we want to exit early.\u001b[39;00m\n\u001b[1;32m 403\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1130\u001b[0m, in \u001b[0;36mBaseCommand.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1128\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs: t\u001b[38;5;241m.\u001b[39mAny, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: t\u001b[38;5;241m.\u001b[39mAny) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m t\u001b[38;5;241m.\u001b[39mAny:\n\u001b[1;32m 1129\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Alias for :meth:`main`.\"\"\"\u001b[39;00m\n\u001b[0;32m-> 1130\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1055\u001b[0m, in \u001b[0;36mBaseCommand.main\u001b[0;34m(self, args, prog_name, complete_var, standalone_mode, windows_expand_args, **extra)\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1054\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmake_context(prog_name, args, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mextra) \u001b[38;5;28;01mas\u001b[39;00m ctx:\n\u001b[0;32m-> 1055\u001b[0m rv \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43mctx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1056\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m standalone_mode:\n\u001b[1;32m 1057\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m rv\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1651\u001b[0m, in \u001b[0;36mMultiCommand.invoke\u001b[0;34m(self, ctx)\u001b[0m\n\u001b[1;32m 1647\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mchain:\n\u001b[1;32m 1648\u001b[0m \u001b[38;5;66;03m# Make sure the context is entered so we do not clean up\u001b[39;00m\n\u001b[1;32m 1649\u001b[0m \u001b[38;5;66;03m# resources until the result processor has worked.\u001b[39;00m\n\u001b[1;32m 1650\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m ctx:\n\u001b[0;32m-> 1651\u001b[0m cmd_name, cmd, args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresolve_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43mctx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1652\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m cmd \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1653\u001b[0m ctx\u001b[38;5;241m.\u001b[39minvoked_subcommand \u001b[38;5;241m=\u001b[39m cmd_name\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:1715\u001b[0m, in \u001b[0;36mMultiCommand.resolve_command\u001b[0;34m(self, ctx, args)\u001b[0m\n\u001b[1;32m 1713\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m split_opt(cmd_name)[\u001b[38;5;241m0\u001b[39m]:\n\u001b[1;32m 1714\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_args(ctx, ctx\u001b[38;5;241m.\u001b[39margs)\n\u001b[0;32m-> 1715\u001b[0m \u001b[43mctx\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfail\u001b[49m\u001b[43m(\u001b[49m\u001b[43m_\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mNo such command \u001b[39;49m\u001b[38;5;132;43;01m{name!r}\u001b[39;49;00m\u001b[38;5;124;43m.\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mformat\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moriginal_cmd_name\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1716\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m cmd_name \u001b[38;5;28;01mif\u001b[39;00m cmd \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, cmd, args[\u001b[38;5;241m1\u001b[39m:]\n", - "File \u001b[0;32m/opt/miniconda3/envs/jupyter-ai/lib/python3.10/site-packages/click/core.py:679\u001b[0m, in \u001b[0;36mContext.fail\u001b[0;34m(self, message)\u001b[0m\n\u001b[1;32m 673\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfail\u001b[39m(\u001b[38;5;28mself\u001b[39m, message: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mte.NoReturn\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 674\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Aborts the execution of the program with a specific error\u001b[39;00m\n\u001b[1;32m 675\u001b[0m \u001b[38;5;124;03m message.\u001b[39;00m\n\u001b[1;32m 676\u001b[0m \n\u001b[1;32m 677\u001b[0m \u001b[38;5;124;03m :param message: the error message to fail with.\u001b[39;00m\n\u001b[1;32m 678\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 679\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m UsageError(message, \u001b[38;5;28mself\u001b[39m)\n", - "\u001b[0;31mUsageError\u001b[0m: No such command 'foo'." - ] - } - ], - "source": [ - "%ai foo" - ] - }, - { - "cell_type": "code", - "execution_count": 5, "id": "bad2d8a8-6141-4247-9af7-7583426c59a6", "metadata": {}, "outputs": [ @@ -258,7 +229,7 @@ "gpt4 - openai-chat:gpt-4\n" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -269,7 +240,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "4d84fcac-7348-4c02-9ec3-34b300ec8459", "metadata": {}, "outputs": [ @@ -295,7 +266,7 @@ "\n" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -316,7 +287,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "539263a2-1c30-4338-9622-bdc500c17830", "metadata": {}, "outputs": [ @@ -329,7 +300,7 @@ "Registered new alias `mychat`" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -340,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "4a453ca5-9f33-4393-a936-d7bc6c4c8f63", "metadata": { "tags": [] @@ -442,7 +413,7 @@ "mychat - openai-chat:gpt-4\n" ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -453,7 +424,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "id": "ea75ac14-d83d-45b4-8c1d-40e4fbc1d263", "metadata": { "tags": [] @@ -464,13 +435,13 @@ "text/markdown": [ "\n", "\n", - "This model is **unspecified**." + "This is model **XYZ123**." ], "text/plain": [ "" ] }, - "execution_count": 9, + "execution_count": 8, "metadata": { "text/markdown": { "jupyter_ai": { @@ -489,7 +460,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "id": "3e7fb7fb-d61c-4909-959b-14bc97af409a", "metadata": {}, "outputs": [ @@ -502,7 +473,7 @@ "Updated target of alias `mychat`" ] }, - "execution_count": 10, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -513,7 +484,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "id": "a89a4c2a-b37f-4a3d-86cb-67747113d3d7", "metadata": { "tags": [] @@ -530,7 +501,7 @@ "" ] }, - "execution_count": 11, + "execution_count": 10, "metadata": { "text/markdown": { "jupyter_ai": { @@ -549,7 +520,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "id": "c7453152-6c70-4f91-bef6-4ae38d700f52", "metadata": { "tags": [] @@ -651,7 +622,7 @@ "mychat - openai:text-davinci-003\n" ] }, - "execution_count": 12, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -662,7 +633,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "id": "971f823d-8f35-4201-a6cb-12a21a87628a", "metadata": { "tags": [] @@ -677,7 +648,7 @@ "Deleted alias `mychat`" ] }, - "execution_count": 13, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -688,7 +659,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "id": "6fb1b54a-ee4f-41c0-b666-ea9e0a1279ee", "metadata": { "tags": [] @@ -788,7 +759,7 @@ "gpt4 - openai-chat:gpt-4\n" ] }, - "execution_count": 14, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -809,7 +780,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "id": "9ef639c7-1ca8-48af-b5e5-f76cfa5779f3", "metadata": { "tags": [] @@ -830,7 +801,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "id": "29d5239f-7601-405e-b059-4e881ebf7ab1", "metadata": { "tags": [] @@ -843,7 +814,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "id": "43e7a77c-93af-4ef7-a104-f932c9f54183", "metadata": { "tags": [] @@ -855,7 +826,7 @@ "text": [ "\n", "\n", - "Brightly Socks\n" + "BrightSox\n" ] } ], @@ -866,7 +837,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "id": "9badc567-9720-4e33-ab4a-54fda5129f36", "metadata": { "tags": [] @@ -881,7 +852,7 @@ "Registered new alias `company`" ] }, - "execution_count": 18, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -892,7 +863,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "id": "92b75d71-8844-4872-b424-b0023706abb1", "metadata": { "tags": [] @@ -994,7 +965,7 @@ "company - custom chain\n" ] }, - "execution_count": 19, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -1005,7 +976,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "id": "cfef0fee-a7c6-49e4-8d90-9aa12f7b91d1", "metadata": {}, "outputs": [ @@ -1014,13 +985,13 @@ "text/markdown": [ "\n", "\n", - "BrightSox Co." + "**Colorful Toes**" ], "text/plain": [ "" ] }, - "execution_count": 20, + "execution_count": 19, "metadata": { "text/markdown": { "jupyter_ai": { @@ -1038,7 +1009,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "id": "06c698e7-e2cf-41b5-88de-2be4d3b60eba", "metadata": {}, "outputs": [ @@ -1047,10 +1018,10 @@ "text/plain": [ "\n", "\n", - "Bright Socks Co." + "Bright Sox Co." ] }, - "execution_count": 21, + "execution_count": 20, "metadata": { "jupyter_ai": { "custom_chain_id": "company" From 306955b29cc37c01bd86de723366c452942f17f3 Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Mon, 5 Jun 2023 17:12:49 -0700 Subject: [PATCH 20/24] Fix error from rebase, updates sample notebook --- examples/commands.ipynb | 9 ++++--- .../jupyter_ai_magics/magics.py | 25 +------------------ 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/examples/commands.ipynb b/examples/commands.ipynb index fe223720a..e87e90205 100644 --- a/examples/commands.ipynb +++ b/examples/commands.ipynb @@ -91,6 +91,7 @@ "\n", "Commands:\n", " delete Delete an alias. See `%ai delete --help` for options.\n", + " error Explains the most recent error.\n", " help Show this message and exit.\n", " list List language models. See `%ai list --help` for options.\n", " register Register a new alias. See `%ai register --help` for options.\n", @@ -435,7 +436,7 @@ "text/markdown": [ "\n", "\n", - "This is model **XYZ123**." + "This is an example of a **Model X**." ], "text/plain": [ "" @@ -826,7 +827,7 @@ "text": [ "\n", "\n", - "BrightSox\n" + "Bright Feet Socks\n" ] } ], @@ -985,7 +986,7 @@ "text/markdown": [ "\n", "\n", - "**Colorful Toes**" + "**Funky Toes**" ], "text/plain": [ "" @@ -1018,7 +1019,7 @@ "text/plain": [ "\n", "\n", - "Bright Sox Co." + "Rainbow Toe Socks." ] }, "execution_count": 20, diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index b86e1a38e..7eaf7952b 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -498,30 +498,7 @@ def run_ai_cell(self, args: CellArgs, prompt: str): } } - # if the user wants code, add another cell with the output. - if args.format == 'code': - # Strip a leading language indicator and trailing triple-backticks - lang_indicator = r'^```[a-zA-Z0-9]*\n' - output = re.sub(lang_indicator, '', output) - output = re.sub(r'\n```$', '', output) - new_cell_payload = dict( - source='set_next_input', - text=output, - replace=False, - ) - ip = get_ipython() - ip.payload_manager.write_payload(new_cell_payload) - return HTML('AI generated code inserted below ⬇️', metadata=md); - - if DisplayClass is None: - return output - if args.format == 'json': - # JSON display expects a dict, not a JSON string - output = json.loads(output) - output_display = DisplayClass(output, metadata=md) - - # finally, display output display - return output_display + return self.display_output(output, args.format, md) @line_cell_magic def ai(self, line, cell=None): From 9f746cd595ee627170eab49d9b68eca8419cd60b Mon Sep 17 00:00:00 2001 From: Piyush Jain Date: Tue, 6 Jun 2023 14:35:00 -0700 Subject: [PATCH 21/24] Fixed error when --format is used --- packages/jupyter-ai-magics/jupyter_ai_magics/magics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 7eaf7952b..2d9864e7b 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -403,6 +403,7 @@ def display_output(self, output, display_format, md): text=output, replace=False, ) + ip = get_ipython() ip.payload_manager.write_payload(new_cell_payload) return HTML('AI generated code inserted below ⬇️', metadata=md); From 59f5b8473d02b64ba6304736e145522f47ef1834 Mon Sep 17 00:00:00 2001 From: Jason Weill <93281816+JasonWeill@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:08:48 -0700 Subject: [PATCH 22/24] Update docs/source/users/index.md Co-authored-by: Piyush Jain --- docs/source/users/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/users/index.md b/docs/source/users/index.md index deeabbe79..d71403648 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -584,7 +584,7 @@ chain = LLMChain(llm=llm, prompt=prompt) %ai register companyname chain ``` -You can change this alias's target using the `%ai update` command: +You can change an alias's target using the `%ai update` command: ``` %ai update claude anthropic:claude-instant-v1.0 From 350ce125576320581a2132f66ecb3bfccba54324 Mon Sep 17 00:00:00 2001 From: Jason Weill <93281816+JasonWeill@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:08:57 -0700 Subject: [PATCH 23/24] Update docs/source/users/index.md Co-authored-by: Piyush Jain --- docs/source/users/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/users/index.md b/docs/source/users/index.md index d71403648..1de889461 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -590,7 +590,7 @@ You can change an alias's target using the `%ai update` command: %ai update claude anthropic:claude-instant-v1.0 ``` -You can delete this alias using the `%ai delete` command: +You can delete an alias using the `%ai delete` command: ``` %ai delete claude From b5a74f48bbf09e2f3d4aae2c87520e087041986c Mon Sep 17 00:00:00 2001 From: Jason Weill Date: Tue, 6 Jun 2023 15:50:51 -0700 Subject: [PATCH 24/24] Wraps ValueError exceptions to not print stack trace --- .../jupyter_ai_magics/magics.py | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py index 2d9864e7b..70a16a07a 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/magics.py @@ -3,6 +3,7 @@ import keyword import os import re +import sys import warnings from typing import Optional @@ -514,18 +515,23 @@ def ai(self, line, cell=None): # case we want to exit early. return - if args.type == "error": - return self.handle_error(args) - if args.type == "help": - return self.handle_help(args) - if args.type == "list": - return self.handle_list(args) - if args.type == "register": - return self.handle_register(args) - if args.type == "delete": - return self.handle_delete(args) - if args.type == "update": - return self.handle_update(args) + # If a value error occurs, don't print the full stacktrace + try: + if args.type == "error": + return self.handle_error(args) + if args.type == "help": + return self.handle_help(args) + if args.type == "list": + return self.handle_list(args) + if args.type == "register": + return self.handle_register(args) + if args.type == "delete": + return self.handle_delete(args) + if args.type == "update": + return self.handle_update(args) + except ValueError as e: + print(e, file=sys.stderr) + return # hint to the IDE that this object must be of type `RootArgs` args: CellArgs = args