# Creating Custom Skills in Pymirokai Pymirokai allows you to create **custom skills** to enhance its capabilities according to your needs. --- ## How to Create a Custom Skill ### 1. Use the `@custom_skill` Decorator The `@custom_skill` decorator is required to register the function as a valid skill. ### 2. Define Access Level Specify who can use the skill with the `access_level` parameter. ### 3. Describe the Skill for Natural Language Interaction To allow natural triggering of the skill, define `verbal_descriptions` with example phrases in multiple languages. Example: ```python verbal_descriptions={ "en": ["find rhymes", "words that rhyme", "rhyme finder"], "fr": ["trouver des rimes", "mots qui riment", "rime"], } ``` ### 4. Define Input Parameters Each parameter must be described so the LLM understands what values to provide. Example: ```python parameters=[ ParameterDescription(name="word", description="The word to find rhymes for."), ParameterDescription(name="max_results", description="Maximum number of rhymes to retrieve."), ] ``` ### 5. Use Proper Function Signatures - Include type annotations for **all** parameters. - If interacting with Pymirokai's built-in functions, add `robot` as a parameter. Correct: ```python async def fetch_rhymes(robot: Robot, word: str, max_results: int = 5, timeout: int = 5) -> dict: ``` Incorrect (missing type annotations): ```python async def fetch_rhymes(word, max_results=5, timeout=5): # Incorrect ``` ### 6. Interacting with the Robot If your skill interacts with **Pymirokai functionalities**, include the `robot` parameter: ```python async def fetch_rhymes(robot: Robot, word: str, max_results: int = 5, timeout: int = 5) -> dict: ``` This allows using **robot actions** such as: ```python await robot.wave().completed() # Make the robot wave await robot.say("Here are some rhymes!") # Make the robot speak ``` ### 7. Returning the Response A skill can return: - Nothing - A **string** - A **list** - A **dictionary** - Or anything else that is JSON-serializable However, if you want the **LLM to reformulate the response**, **you must return a dictionary with the key `"llm_output"`**. ✅ **Correct Example (LLM can process and reformulate):** ```python return {"llm_output": "Words that rhyme with 'fun': sun, run, gun, bun, pun."} ``` ❌ **Incorrect Example for LLM: (LLM won't reformulate)** ```python return "Words that rhyme with 'fun': sun, run, gun, bun, pun." # Just a string ``` --- ## Example: Fetch Rhymes Skill Here is a complete example of a skill that finds **rhyming words** for a given input. ```{mermaid} graph TD; A["User request"] --> B["Skill receives input"]; B --> C["Fetch rhymes from API"]; C -->|"Success"| D["Extract API response"]; C -->|"Failure"| E["Handle error and output"]; D --> F["Format response"]; F --> G["Robot announces rhymes"]; G --> H["Return structured response"]; E --> H; ``` ```python import requests from pymirokai.decorators.skill import custom_skill, ParameterDescription from pymirokai.enums.enums import AccessLevel @custom_skill( access_level=AccessLevel.USER, # Defines access level for the skill verbal_descriptions={ "en": ["find rhymes", "words that rhyme", "rhyme finder"], "fr": ["trouver des rimes", "mots qui riment", "rime"], }, parameters=[ ParameterDescription(name="word", description="The word to find rhymes for."), ParameterDescription(name="max_results", description="Maximum number of rhymes to retrieve."), ], ) async def fetch_rhymes(robot: Robot, word: str, max_results: int = 5, timeout: int = 5) -> dict: """Fetch words that rhyme with the given input word. Args: robot (Robot): The robot instance to interact with. word (str): The word to find rhymes for. max_results (int, optional): The maximum number of rhyming words to retrieve. Defaults to 5. timeout (int, optional): The timeout duration for the API request in seconds. Defaults to 5. Returns: dict: A dictionary containing the response output for the robot to announce. """ try: # Fetch rhymes from the Datamuse API url = f"https://api.datamuse.com/words?rel_rhy={word}&max={max_results}" response = requests.get(url, timeout=timeout) response.raise_for_status() rhyme_data = response.json() if rhyme_data: rhymes = [entry["word"] for entry in rhyme_data] answer = f"Words that rhyme with '{word}': {', '.join(rhymes)}" else: answer = f"No rhymes found for '{word}'." except requests.RequestException: answer = "Couldn't fetch rhymes at this moment." await robot.play_face_reaction("amused").completed() return {"llm_output": answer} # if you want the LLM to reformulate the answer ``` ## Final Notes - Ensure **all arguments have type annotations**. - If using `robot`, it must be included as a parameter. - Properly define **verbal descriptions** and **parameter descriptions** for better integration.