cheshire-cat-ai/core

[Feature] WhiteRabbit expansion

Opened this issue · 2 comments

About the path to follow for the WhiteRabbit. During the dev meeting we discussed:

  1. Add the WhiteRabbit inside the StrayCat.
  2. Pass the StrayCat instance to the WhiteRabbit when calling any WhiteRabbit's function.
  3. Additional methods (we should define in particular what to add).

About the first two points I have the following idea:

  • The StrayCat has the WhiteRabbit instance
...
# The Stray cat goes around tools and hook, making troubles
class StrayCat:
    """User/session based object containing working memory and a few utility pointers"""

    def __init__(
            self,
            user_id: str,
            main_loop,
            ws: WebSocket = None,
        ):
        self.__user_id = user_id
        self.working_memory = WorkingMemory()
        self.white_rabbit = WhiteRabbit()
...
  • The WhiteRabbit has all methods with a StrayCat instance parameter (as done in the actual code for schedule_chat_message.
  • The StrayCat "wraps" the WhiteRabbit functions to make the cat instance "invisible" to the plugin dev: (example with schedule_cat_message)
        ...
        # Inside StrayCat

        def schedule_chat_message(self, content: str, days=0, hours=0, minutes=0, seconds=0, milliseconds=0, microseconds=0):
                self.white_rabbit.schedule_chat_message(content=content, cat=self, days=days, hours=hours, minutes=minutes, seconds=seconds, milliseconds=milliseconds, microseconds=microseconds)
         ...

By doing that the plugin developer can schedule a message just like that:

from cat.mad_hatter.decorators import hook

@hook
def before_cat_sends_message(final_output, cat):    
    cat.schedule_chat_message(content="White Rabbit: Oh dear! Oh dear! I shall be too late!", minutes=1)
    return final_output

It's a little bit a continuous communication between the StrayCat and the WhiteRabbit but it should make very easy the integration inside the plugins. @pieroit @lucagobbi what do you think?

Hi Jacopo, thanks for organizing this discussion.

Regarding point 1):

I think we should stick with the current code and make WhiteRabbit a property of StrayCat just like MadHatter, RabbitHole, etc. it makes the code more consistent

...
@property
def white_rabbit(self):
    return CheshireCat().white_rabbit
...

Regarding point 2) and your proposal:

I was wondering: do we really need this for every scheduling function? One could do some work ignoring the session and schedule a system-level job, if you need Stray you can still pass it as argument in the kwargs:

from cat.mad_hatter.decorators import hook
from cat.log import log

def log_greetings(cat):
    llm_response = cat.llm("Hi!")
    log.debug(f"LLM response: {llm_response }")

@hook
def after_cat_bootstrap(cat):
    cat.white_rabbit.schedule_date_task(log_greetings, seconds=10, cat=cat)

I think that WhiteRabbit should be called via Stray as:

cat.white_rabbit.schedule_job(your_function, seconds=10, kwargs_to_your_function)

I think it is better to avoid wrapping WhiteRabbit function in Stray to keep the separation of concerns. Plus, if I want to be consistent to my thesis, in which the session is not always needed in scheduling, the cat instance should not be invisible to developer, but he/she should decide whether to include it or not.

Regarding point 3):

As I suggested in your first PR we should support all the 3 types of scheduling job that are available in APScheduling: date, interval, cron.

  • date: Executes the job once at a specified date and time. Ideal for tasks that need to run only once.
  • interval: Executes the job at regular intervals. Suitable for recurring tasks that need to run at fixed time intervals.
  • cron: Executes the job periodically based on a schedule specified with cron-like expressions. Best for complex schedules, such as running tasks on specific days of the week, month, etc.

Thank you Luca, it's all clear.