From 4963ed67f110a831bae35c483e3f866de8541862 Mon Sep 17 00:00:00 2001 From: Nicola Date: Fri, 8 Dec 2023 23:48:06 +0100 Subject: [PATCH] started flow --- .github/workflows/main.yml | 18 +----- README.md | 2 +- my_plugin.py | 31 --------- plugin.json | 8 +-- setup.py | 79 ----------------------- tool.py | 51 +++++++++++++++ utils.py | 1 + wizard.py | 125 +++++++++++++++++++++++++++++++++++++ 8 files changed, 183 insertions(+), 132 deletions(-) delete mode 100644 my_plugin.py delete mode 100644 setup.py create mode 100644 tool.py create mode 100644 utils.py create mode 100644 wizard.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 158948b..621ba9b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,26 +18,10 @@ permissions: env: PLUGIN_JSON: "0.0.1" TAG_EXISTS: false - PLUGIN_NAME: "my_plugin" + PLUGIN_NAME: "hello_dear_world" jobs: -# This will be deleted by setup.py - check: - runs-on: ubuntu-latest - outputs: - plugin_name: ${{ steps.init.outputs.plugin_name }} - steps: - - name: Get plugin name - id: init - run: | - echo "plugin_name=${{ env.PLUGIN_NAME }}" >> $GITHUB_OUTPUT - -# This is the end of the removed section release: - # This will be deleted by setup.py - needs: check - if: startsWith(needs.check.outputs.plugin_name, 'MY_PLUGIN') == false - # This is the end of the removed section runs-on: ubuntu-latest steps: - name: Checkout diff --git a/README.md b/README.md index 2ebc3e5..c614761 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# My plugin +# Hello Dear World [![awesome plugin](https://custom-icon-badges.demolab.com/static/v1?label=&message=awesome+plugin&color=383938&style=for-the-badge&logo=cheshire_cat_ai)](https://) [![Awesome plugin](https://custom-icon-badges.demolab.com/static/v1?label=&message=Awesome+plugin&color=000000&style=for-the-badge&logo=cheshire_cat_ai)](https://) diff --git a/my_plugin.py b/my_plugin.py deleted file mode 100644 index 779cb24..0000000 --- a/my_plugin.py +++ /dev/null @@ -1,31 +0,0 @@ -from cat.mad_hatter.decorators import tool, hook, plugin -from pydantic import BaseModel -from datetime import datetime, date - -class MySettings(BaseModel): - required_int: int - optional_int: int = 69 - required_str: str - optional_str: str = "meow" - required_date: date - optional_date: date = 1679616000 - -@plugin -def settings_schema(): - return MySettings.schema() - -@tool -def get_the_day(tool_input, cat): - """Get the day of the week. Input is always None.""" - - dt = datetime.now() - - return dt.strftime('%A') - -@hook -def before_cat_sends_message(message, cat): - - prompt = f'Rephrase the following sentence in a grumpy way: {message["content"]}' - message["content"] = cat.llm(prompt) - - return message diff --git a/plugin.json b/plugin.json index d213dea..d061566 100644 --- a/plugin.json +++ b/plugin.json @@ -1,10 +1,10 @@ { - "name": "My plugin", + "name": "Hello Dear World", "version": "0.0.1", - "description": "Description of my_plugin.", + "description": "Description of hello_dear_world.", "author_name": "Me", "author_url": "https://mywebsite.me", - "plugin_url": "https://github.com/my_name/my_plugin", + "plugin_url": "https://github.com/my_name/hello_dear_world", "tags": "cat, template, example", - "thumb": "https://raw.githubusercontent.com/my_repo_path/my_plugin.png" + "thumb": "https://raw.githubusercontent.com/my_repo_path/hello_dear_world.png" } diff --git a/setup.py b/setup.py deleted file mode 100644 index ee231e1..0000000 --- a/setup.py +++ /dev/null @@ -1,79 +0,0 @@ -import os -import pathlib -import fnmatch -import sys - -""" -Run this script once after first creating the repository from the template. - -This script is interactive and will prompt you for various inputs. -""" - - -def filter_lines(file_path, excluded_ranges): - with open(file_path, 'r') as file: - lines = file.readlines() - - new_lines = [] - current_line = 1 - for line in lines: - exclude = any(start <= current_line <= end for start, end in excluded_ranges) - if not exclude: - new_lines.append(line) - current_line += 1 - - with open(file_path, 'w') as file: - file.writelines(new_lines) - - -if __name__ == "__main__": - - repo_name = input("What is the name of your plugin (full name with spaces)? ") - - snake_name = "_".join(repo_name.lower().split(" ")) - - os.rename("my_plugin.py", f"{snake_name}.py") - - # Pipeline file's line ranges to remove - # This must reflect eventual main.yml changes - excluded_line_ranges = [(24, 35), (37, 40)] - - yaml_file_path = os.path.join(os.path.dirname(__file__), '.github', 'workflows', 'main.yml') - - filter_lines(yaml_file_path, excluded_line_ranges) - - for file in pathlib.Path(".").glob("**/*.*"): - filename = str(file) - - if fnmatch.fnmatch(filename, ".git/*"): # Exclude .git directory - continue - - if fnmatch.fnmatch(filename, "__pycache__/*"): # Exclude __pycache__ directory - continue - - if fnmatch.fnmatch(filename, "venv/*"): # Exclude venv directory - continue - - if fnmatch.fnmatch(filename, ".idea*"): - continue - - if fnmatch.fnmatch(filename, sys.argv[0]): # Exclude the script file itself - continue - - if os.path.basename(file) == "setup.py": - continue - - if file.is_dir(): - continue - else: - print(file) - with open(file, "r", encoding="utf-8", errors="ignore") as f: - content = f.read() - - replaced = content.replace("my_plugin", snake_name).replace("My plugin", repo_name.title()) - - with open(file, "w", encoding="utf-8", errors="ignore") as f: - f.write(replaced) - - print(f"All the occurrences were replaced successfully with `{repo_name}`!") - os.remove(sys.argv[0]) diff --git a/tool.py b/tool.py new file mode 100644 index 0000000..73637e8 --- /dev/null +++ b/tool.py @@ -0,0 +1,51 @@ +import os +import json + +from cat.mad_hatter.decorators import tool +from cat.utils import get_plugins_path + + +@tool +def complete_json(tool_input, cat): + """Useful to put a dictionary-like text inside a JSON file. + Input is a python dictionary.""" + json_file = os.path.join(get_plugins_path(), "start_from_here", "plugin.json") + try: + json_content = eval(tool_input) + except Exception as exc: + return "There might be an error in the dictionary you wrote" + + if "name" not in json_content: + return "uh-oh I think you forgot to tell me the name of your plugin" + + with open(json_file, "w") as file: + json.dump(json_content, file) + + return "This has been magical! Go check the plugin in the `cat/plugins/start_from_here` folder" + + +@tool +def complete_hook(tool_input, cat): + """Useful to complete the .py file to change the Cat's personality. + Input is a string describing how the Cat should behave.""" + plugin_file = os.path.join(get_plugins_path(), "start_from_here", "plugin.py") + hook_start = """from cat.mad_hatter.decorators import hook + + @hook + def agent_prompt_prefix(prefix, cat): + """ + + hook_end = """ + return prefix + """ + + hook = f""" + {hook_start} + prefix="{tool_input}" + {hook_end} + """ + + with open(plugin_file, "w") as file: + file.write(hook) + + return "Go and take a look at how the file is changed!" diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..b2ec333 --- /dev/null +++ b/utils.py @@ -0,0 +1 @@ +def create_file(path): diff --git a/wizard.py b/wizard.py new file mode 100644 index 0000000..617b1ed --- /dev/null +++ b/wizard.py @@ -0,0 +1,125 @@ +import os +import json + +from cat.log import log +from cat.utils import get_static_path, get_plugins_path +from cat.mad_hatter.decorators import plugin, hook +from cat.looking_glass.cheshire_cat import CheshireCat +from cat.looking_glass.prompts import MAIN_PROMPT_PREFIX + + +URLS = [ + "https://cheshire-cat-ai.github.io/docs/technical/plugins/plugins/", + "https://cheshire-cat-ai.github.io/docs/technical/plugins/tools/", + "https://cheshire-cat-ai.github.io/docs/technical/plugins/hooks/", + "https://cheshire-cat-ai.github.io/docs/technical/plugins/settings/", + "https://cheshire-cat-ai.github.io/docs/technical/plugins/dependencies/" +] +TUTORIAL_PATH = os.path.join(get_plugins_path(), "start_from_here") +MAIN_PROMPT_PREFIX = None + + +ccat = CheshireCat() + + +@plugin +def activated(plugin): + declarative_memory = ccat.memory.vectors.declarative + for url in URLS: + metadata = { + "source": url + } + + points = declarative_memory.client.scroll( + collection_name="declarative", + scroll_filter=declarative_memory._qdrant_filter_from_dict(metadata), + ) + log.debug(points) + if len(points[0]) != 0: + continue + log.error(f"Ingesting {url}") + ccat.rabbit_hole.ingest_file(stray=ccat, file=url) + + # clonare template? + + if not os.path.isdir(TUTORIAL_PATH): + os.mkdir(TUTORIAL_PATH) + with open(os.path.join(TUTORIAL_PATH, "plugin.py"), "w"): + pass + # creare json + + +@hook +def agent_prompt_prefix(prefix, cat): + global MAIN_PROMPT_PREFIX + MAIN_PROMPT_PREFIX = prefix + + +@hook +def before_cat_reads_message(message, cat): + if not "hdw" in cat.working_memory and os.path.isdir(TUTORIAL_PATH): + cat.working_memory["hdw"] = True + + +@hook +def before_cat_recalls_procedural_memories(settings, cat): + if "hdw" in cat.working_memory and cat.working_memory["hdw"] is False: + settings["threshold"] = 1.1 + + del cat.working_memory["hdw"] + + return settings + + +@hook +def agent_fast_reply(reply, cat): + + if "hdw" in cat.working_memory and cat.working_memory["hdw"] is True: + cat.working_memory["hdw"] = False + + content = cat.llm(f"{MAIN_PROMPT_PREFIX}. Tell the user that the 'Hello Dear World' experience has begun.") + res = cat({ + "text": "Introduce me about the Cheshire Cat's plugin. Explain the following like I'm five:" + "- Plugin" + "- Hooks" + "- Tools" + }) # funge, cercare risp migliore + + return {"output": f"{content}\n{res['content']}\nAre you ready to begin? Yes/No"} + + # __________________ + + if not "hdw" in cat.working_memory or cat.working_memory["hdw"] is False: + return reply + + if cat.working_memory["plugin_begin"] is None: # TODO: here crasha ricomincia da qua + if "yes" in cat.working_memory["user_json_message"]["text"].lower(): + # Start + + # def agent_prompt_prefix(prefix, cat): + # prefix = dimmi la tua personalità + # return + # + message = """Let's try build a plugin together, this is a plugin that changes my personality. + + @hook + def agent_prompt_prefix(prefix, cat): + prefix = "Choose my personality" + return prefix + + what personality do you want me to have? Write a description + """ + del cat.working_memory["plugin_begin"] + return { + "output": message + } + +# creare forzatamente cartella plugin nuovo? "ti ho creato un plugin, vai a controllare al path...i file servono a..." +# plugin.json con chiavi vuote --> riempibile con tools +# hook esempio con --> completa tu --> il completamento viene scritto dentro al .py +# requirements? + +# info preliminari plugin hook tool (cerca a mano nella memoria e fai un prompt con dentro il contesto pescato?) +# sei pronto per una piccola sfida? si/no +# si -> un piccolo plugin da fare (sfida con few-shots? llm sbizzarrisce) +# no -> vai avanti con altre info preliminari \ No newline at end of file