generated from cheshire-cat-ai/plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
luca.gobbi
committed
Jun 14, 2024
1 parent
7eb4984
commit 7481f24
Showing
8 changed files
with
206 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,54 @@ | ||
# My plugin | ||
# White Rabbit In Action | ||
|
||
<img src="./assets/white-rabbit-in-action.png" width=400> | ||
|
||
[![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://) | ||
[![awesome plugin](https://custom-icon-badges.demolab.com/static/v1?label=&message=awesome+plugin&color=F4F4F5&style=for-the-badge&logo=cheshire_cat_black)](https://) | ||
|
||
Write here all the useful information about your plugin. | ||
White Rabbit In Action is a Cheshire Cat plugin that seamlessly integrates scheduling capabilities into your plugins and tools without requiring you to write specific scheduling code. | ||
|
||
Let the White Rabbit decide when your tools are executed! | ||
|
||
## Overview | ||
|
||
The White Rabbit In Action introduces a new Python annotation into the framework called `@white_rabbit_tool`, an enhanced version of the standard Cheshire Cat `@tool`. The `@white_rabbit_tool` allows you to bypass writing specific scheduling code by utilizing the White Rabbit component within the Cheshire Cat framework. It wraps your function similarly to the standard `@tool`, but with added capabilities for handling scheduling functions. This means the Agent can determine whether the triggered tool needs immediate execution (as usual) or should be scheduled to run in the future or according to a specified cron expression. | ||
|
||
This repository is the template to automate the release of official Cheshire Cat AI plugins. | ||
## Key Features | ||
|
||
- **Automatic Scheduling**: The White Rabbit component manages the timing of tool execution, freeing you from the complexity of scheduling code. | ||
- **Intelligent Execution**: The Agent understands if a tool needs instant execution or should be scheduled for the future. | ||
- **Flexible Scheduling Options**: Schedule tools to run at specific times or intervals using cron expressions. | ||
|
||
## Usage | ||
|
||
1. Create a new repository clicking on the `Use this template` button. | ||
2. Clone your new repo directly in the Cat's `plugins` folder. | ||
3. Run the `setup.py` script: | ||
```bash | ||
python setup.py | ||
### How to use the annotation | ||
|
||
To enable scheduling capabilities of White Rabbit In Action, apply the `@white_rabbit_tool` annotation to your functions, just like you would normally do with standard Cheshire Cat tools. This allows the Agent to manage their execution schedule. | ||
|
||
```python | ||
|
||
from white_rabbit_in_action import white_rabbit_tool | ||
|
||
@white_rabbit_tool | ||
def turn_on_lights(cat): | ||
""" | ||
Call this tool whenever the user wants to turn on the lights. | ||
""" | ||
|
||
cat.send_ws_message("Turning on the lights", msg_type="chat") | ||
|
||
``` | ||
The script will prompt you to write the name of your plugin and make an initial setup setting the name in the files. | ||
|
||
4. Start developing! | ||
> **Warning ⚠️** | ||
> | ||
> This implementation modifies some mechanisms within the Cheshire Cat framework. As a consequence, certain features, such as `return_direct`, will not work as expected. Please consider this limitation when developing your own plugins. | ||
|
||
### Managing scheduled jobs | ||
|
||
In addition to scheduling, White Rabbit In Action provides basic Cheshire Cat tools to manage scheduled jobs in a conversational manner. These tools include: | ||
|
||
> **Important** | ||
> A new release of your plugin is triggered every time you set a new `version` in the `plugin.json` file. | ||
> Please, remember to set it correctly every time you want to release an update. | ||
- **Retrieve Scheduled Jobs**: View a list of all scheduled jobs. | ||
- **Pause a Scheduled Job**: Temporarily halt a scheduled job without removing it. | ||
- **Resume a Scheduled Job**: Reactivate a paused job. | ||
- **Remove a Scheduled Job**: Delete a scheduled job. | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
{ | ||
"name": "My plugin", | ||
"name": "White Rabbit In Action", | ||
"version": "0.0.1", | ||
"description": "Description of my_plugin.", | ||
"author_name": "Me", | ||
"author_url": "https://mywebsite.me", | ||
"plugin_url": "https://github.com/my_name/my_plugin", | ||
"tags": "cat, template, example", | ||
"thumb": "https://raw.githubusercontent.com/my_repo_path/my_plugin.png" | ||
"description": "White Rabbit In Action is a Cheshire Cat's plugin designed to enhance the capabilities of the White Rabbit scheduler.", | ||
"author_name": "Luca Gobbi", | ||
"author_url": "https://github.com/lucagobbi", | ||
"plugin_url": "https://github.com/lucagobbi/white-rabbit-in-action", | ||
"tags": "cat, white rabbit, scheduler, tools, planner", | ||
"thumb": "https://raw.githubusercontent.com/lucagobbi/white-rabbit-in-action/main/assets/white-rabbit-in-action.png" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import inspect | ||
import re | ||
from typing import Callable | ||
|
||
|
||
def extract_args_as_kwargs(func: Callable, *args, **kwargs) -> dict: | ||
sig = inspect.signature(func) | ||
param_names = list(sig.parameters.keys()) | ||
|
||
for name, arg in zip(param_names, args): | ||
if name not in kwargs: | ||
kwargs[name] = arg | ||
return kwargs | ||
|
||
|
||
def parse_cron_expression(cron_expression: str): | ||
keys = ['minute', 'hour', 'day', 'month', 'day_of_week'] | ||
return dict(zip(keys, cron_expression.split())) | ||
|
||
|
||
def extract_int_from_string(s: str): | ||
match = re.search(r'\d+', s) | ||
if match: | ||
return int(match.group()) | ||
raise ValueError("No integer found in the string.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
from typing import Callable, Union, List | ||
|
||
from cat.plugins.white_rabbit_in_action.utils import extract_int_from_string, parse_cron_expression, \ | ||
extract_args_as_kwargs | ||
from cat.mad_hatter.decorators.tool import CatTool | ||
from cat.mad_hatter.decorators import tool | ||
from cat.log import log | ||
|
||
from cat.looking_glass.stray_cat import StrayCat | ||
|
||
|
||
def classify_schedule(stray_cat: StrayCat) -> str: | ||
user_message = stray_cat.working_memory.user_message_json.text | ||
example_labels = { | ||
"fixed_date": ["Turn on the light in 30 seconds"], | ||
"cron_based": ["Turn on the light every morning at 7am"], | ||
"unscheduled": ["Turn on the light"] | ||
} | ||
schedule_type = stray_cat.classify(f"Extract the exact schedule from the following message: {user_message}", | ||
example_labels) | ||
return schedule_type | ||
|
||
|
||
def schedule_function(type_of_schedule: str, func: Callable[[str], str], *args, **kwargs) -> Callable[[], None]: | ||
stray_cat = kwargs["cat"] | ||
user_message = stray_cat.working_memory.user_message_json.text | ||
|
||
def extract_seconds() -> int: | ||
seconds_expression = stray_cat.llm( | ||
f"Extract the exact number of seconds from the following message: {user_message}") | ||
return extract_int_from_string(seconds_expression) | ||
|
||
if type_of_schedule == "fixed_date": | ||
seconds = extract_seconds() | ||
log.debug(f"WhiteRabbitInAction - Schedule date: {seconds}") | ||
return stray_cat.white_rabbit.schedule_job(func, seconds=seconds, *args, **kwargs) | ||
elif type_of_schedule == "cron_based": | ||
cron_expression = stray_cat.llm(f"Deduce the exact cron expression (e.g. 0 7 * * *) from this message: {user_message}") | ||
log.debug(f"WhiteRabbitInAction - Schedule cron: {cron_expression}") | ||
kwargs = extract_args_as_kwargs(func, *args, **kwargs) | ||
return stray_cat.white_rabbit.schedule_cron_job(func, **parse_cron_expression(cron_expression), **kwargs) | ||
else: | ||
raise ValueError(f"WhiteRabbitInAction - Unknown schedule type: {type_of_schedule}") | ||
|
||
|
||
def white_rabbit_tool(*args: Union[str, Callable], return_direct: bool = False, examples: List[str] = []) -> Callable: | ||
def _make_with_name(tool_name: str) -> Callable: | ||
def _make_tool(func: Callable[[str], str]) -> CatTool: | ||
|
||
def white_rabbit_func(*in_args, **kwargs): | ||
stray_cat = kwargs['cat'] | ||
schedule_type = classify_schedule(stray_cat) | ||
log.debug(f"WhiteRabbitInAction - Classified schedule_type: {schedule_type}") | ||
|
||
if schedule_type == "unscheduled": | ||
log.debug(f"WhiteRabbitInAction - Running function {func.__name__}") | ||
return func(*in_args, **kwargs) | ||
|
||
log.debug(f"WhiteRabbitInAction - Scheduling function {func.__name__}") | ||
schedule_function(schedule_type, func, *in_args, **kwargs) | ||
return "Roger that. I'll run it later." | ||
|
||
assert func.__doc__, "Function must have a docstring" | ||
white_rabbit_func.__doc__ = func.__doc__ | ||
|
||
tool_ = CatTool( | ||
name=tool_name, | ||
func=white_rabbit_func, | ||
return_direct=return_direct, | ||
examples=examples, | ||
) | ||
|
||
return tool_ | ||
|
||
return _make_tool | ||
|
||
if len(args) == 1 and isinstance(args[0], str): | ||
return _make_with_name(args[0]) | ||
elif len(args) == 1 and callable(args[0]): | ||
return _make_with_name(args[0].__name__)(args[0]) | ||
elif len(args) == 0: | ||
def _partial(func: Callable[[str], str]) -> CatTool: | ||
return _make_with_name(func.__name__)(func) | ||
|
||
return _partial | ||
else: | ||
raise ValueError("Too many arguments for tool decorator") | ||
|
||
|
||
@tool | ||
def get_running_jobs(user_input, cat: StrayCat): | ||
""" | ||
Call this tool whenever the user wants to get the running scheduled jobs. | ||
""" | ||
return [{"id": job["id"], "name": job["name"], "next_run": job["next_run"].isoformat() if job["next_run"] else None} | ||
for job in cat.white_rabbit.get_jobs()] | ||
|
||
|
||
@tool(return_direct=True) | ||
def remove_job_by_id(job_id: str, cat: StrayCat): | ||
""" | ||
Call this tool whenever the user wants to remove a scheduled job by id. | ||
""" | ||
return cat.white_rabbit.remove_job(job_id) | ||
|
||
|
||
@tool(return_direct=True) | ||
def pause_job_by_id(job_id: str, cat: StrayCat): | ||
""" | ||
Call this tool whenever the user wants to pause a scheduled job by id. | ||
""" | ||
return cat.white_rabbit.pause_job(job_id) | ||
|
||
|
||
@tool(return_direct=True) | ||
def resume_job_by_id(job_id: str, cat: StrayCat): | ||
""" | ||
Call this tool whenever the user wants to resume a scheduled job by id. | ||
""" | ||
return cat.white_rabbit.resume_job(job_id) | ||
|
||
|
||
# Example usage of the white rabbit tool | ||
# | ||
# @white_rabbit_tool | ||
# def turn_on_lights(cat: StrayCat): | ||
# """ | ||
# Call this tool whenever the user wants to turn on the lights. | ||
# """ | ||
# cat.send_ws_message("Turning on the lights", msg_type="chat") |