#SuperCatForm

1 messages Β· Page 1 of 1 (latest)

silent wasp
#

SuperCatForm is an opinionated extension of the traditional CatForm that allows devs to create more powerful and engaging agents.

The plugin comes with a new decorator for conversational forms @super_cat_form.
Currently I've added just one superpower: the abality to execute tools during form execution: as you can see the Cat now is not only a simple data collector but a more human-like agent.

Here's an example:

from pydantic import BaseModel
from datetime import datetime

from cat.plugins.super_cat_form.super_cat_form import SuperCatForm, form_tool, super_cat_form


class PizzaOrder(BaseModel):
    pizza_type: str
    address: str


@super_cat_form
class PizzaForm(SuperCatForm):
    description = "Pizza Order"
    model_class = PizzaOrder
    start_examples = [
        "order a pizza!",
        "I want pizza"
    ]
    stop_examples = [
        "stop pizza order",
        "not hungry anymore",
    ]
    ask_confirm = False

    @form_tool(return_direct=True)
    def get_menu(self):
        """Useful to get the menu. User may ask: what is the menu? Input is always None."""
        return ["Margherita", "Pepperoni", "Hawaiian"]

    @form_tool(return_direct=True)
    def ask_for_daily_promotions(self):
        """Useful to get any daily promotions. User may ask: what are the daily promotions? Input is always None."""
        if datetime.now().weekday() == 0:
            return "Free delivery"
        elif datetime.now().weekday() == 4:
            return "Free Pepperoni"

    def submit(self, form_data):
        return {
            "output": f"Form submitted: {form_data}"
        }


Here are some screenshots of the enhanced PizzaForm in action.

The goal of this plugin is to push the conversational forms API even further - a feature with enormous potential. Next steps include support for JSON schema, nested fields, and more! Stay tuned!

https://github.com/lucagobbi/super-cat-form

GitHub

Super Cat Form is an extension of Cheshire Cat conversational forms - lucagobbi/super-cat-form

silent wasp
#

Hi!! I've just released version 0.1.0 of the SuperCatForm which brings:

  • Full Pydantic support: both in extraction and in validation (the standard CatForm is leveraging Pydantic only in the validation phase, while missing key schema descriptors in the extraction prompt)
  • Nested fields support: the SuperCatForm overrides the default extract method to use LangChain JsonOutputParser based on the provided Pydantic object to support nested fields as well.

Here's an example of that:

from typing import Literal, List

from pydantic import BaseModel, Field
from cat.experimental.form import form
from cat.plugins.super_cat_form.super_cat_form import SuperCatForm
from datetime import datetime


class Address(BaseModel):
    street: str
    city: str


class Pizza(BaseModel):
    pizza_type: str = Field(description="Type of pizza")
    size: Literal["standard", "large"] = Field(default="standard")
    extra_toppings: List[str] = Field(default_factory=list)


class PizzaOrder(BaseModel):
    pizzas: List[Pizza]
    address: Address
    due_date: datetime = Field(description=f"Datetime when the pizza should be delivered - format YYYY-MM-DD HH:MM - Today is: {datetime.now().strftime('%Y-%m-%d %H:%M')}" )


@form
class PizzaForm(SuperCatForm):
    description = "Pizza Order"
    model_class = PizzaOrder
    start_examples = [
        "order a pizza!",
        "I want pizza"
    ]
    stop_examples = [
        "stop pizza order",
        "not hungry anymore",
    ]
    ask_confirm = True

    def submit(self, form_data):

        form_result = self.form_data_validated

        if form_result is None:
            return {
                "output": "Invalid form data"
            }

        return {
            "output": f"Ok! {form_result.pizzas} will be delivered to {form_result.address} on {form_result.due_date.strftime('%A, %B %d, %Y at %H:%M')}"
        }

Here's attached the result in action:

silent wasp
#

@lusty moth Ive just tried the example in the README with a new installation (Cat 1.7.1., SuperCatForm 0.1.0) and it works, can you share your code?

lusty moth
silent wasp
#

It shoudlnt be an llm matter, I think Ive found the issue

lusty moth
#

Ah ok let me know in case

silent wasp
#

Ok I see, I was working with the latest version of the Cat on develop branch, the conversational form was refactored recently (by me btw eheh, genius). I'll patch the plugin to work with both versions. New plugin version coming soon. Many thanks @lusty moth for the report πŸ™

silent wasp
#

Hola everyone!

Im releasing version 0.2.0 of the SuperCatForm plugin. This version includes several things:

  • backward compatibility for Cat versions pre 1.8.0: this was achieved through some hacky methods but should now work for every Cat version that implements Conversational Forms i.e. >=1.5.1

  • improved tool selection prompt: i noticed that, especially with smaller models, the tool selection was quite weak and sometimes it was triggering tools just for similiraty of context even if the user was answering to a form question

  • form events: this is a new feature for the SuperCatForm and will be probably overkill for most of you. Still, I think that providing an hook mechanism (similar to the Cat one, but simpler) without needing to override SuperCatForm or CatForm methods is a nice addon. With this feature, you can hook into several phase during the lifecycle of a form. Let me suggest some use cases: freezing the booking of an order while the user is filling out the form (hotels, flights, cinema, etc), check real-time delivery availability during a pizza order and more... Here attached a screenshot of the form events in action (more info on the plugin's readme)

Hope you like this! Peace

shell scroll
silent wasp
shell scroll
#

closed source ?

silent wasp
# shell scroll closed source ?

No way! If you want to check it out you need to switch on develop branch on core repo. Latest updates are always there, but be aware that it could be unstable

shell scroll
#

hoooooooo... okay. Sorry... sorry... 😁

#

still learning a lot, hope I can help some day πŸ˜…

#

Explained few people about the cat... my phone rang all week πŸ˜‚

languid wind
lusty moth
#

i'm playing with supercatform, is super !

lusty moth
#

Hello, still playing with supercatform, i have one doubt. I have this class: class Boat(BaseModel):
date_from: datetime = Field(description="Datetime of search start date - format YYYY-MM-DD HH:MM")
date_to: datetime = Field(description="Datetime of search end date - format YYYY-MM-DD HH:MM")
product_type: Literal["bareboat", "crewed", "cabin", "flotilla", "power", "berth", "regatta"] = Field(description="Type of product searched") #default="cabin",
price: Optional[int] = Field(description="Eventually price to filter the results") . The "Optional" on the last field It should make the field optional, but during the conversation the agent still asks me to fill it in. Am I missing something?

silent wasp
#

Hi everyone! Version 0.2.1 just released!

Changelog:

  • Fix support for optional values (thanks again @lusty moth )
lusty moth
#

ei there, one question for you: all that is support on "classic" form, like validators and model_getter (for 1.8.0) is supported using SuperCatForm?

silent wasp
#

sure the SuperCatForm is inheriting from CatForm, plus model getters are already available in the SuperCatForm providing back/forward compatibility

lusty moth
#

good morning, I wanted to report a behavior that I encounter using the form tools. In my example, I have in my pydantic class the field boat_type (is a literal with 6 six values). I have a tool for the form that help the user to know which boat is available: when I "invoke" the tool, the agent show me the type of boat, I respond with one of the suggested types (which coincides with the one in the literal) but the agent always responds to me by invoking the tool, this is repeated for 3-4 turns. Has this behavior happened to anyone?

silent wasp
silent wasp
lusty moth
#

With gpt-4o 🀣🀣

silent wasp
#

holy crap

lusty moth
#

Tomorrow I will try with the mini ahah

#

I use also cat advanced tool as plug-in

#

Can be a problem ?

silent wasp
#

it shouldnt since the cat form has its own prompts

#

i'll make some tests with gpt-4o as well, let's see if it is dumber than its little brother

#

ok sometimes i get the same reiteration of form_tool.. I guess it struggles with those short responses. Maybe you should tweak a little the main prompts of the SuperCatForm. Think I'll release a new version in which you can easily override them from plugin settings.

@lusty moth even if you're not actively developin this plugin, you're makin me think about a lot of adjustments and additions, thankss!!!

lusty moth
#

Yes the behaviour is more with short responses. The main prompt of super cat form is the description correct ? Thanks for your work not to me ahahha

lusty moth
#

@silent wasp rewriting the description the agent doesnt fall in the same loop πŸ™‚ thanks you very much

silent wasp
lusty moth
#

yes the tool docstring

#

rewriting it i dont have more the problem

silent wasp
#

Hola people! Just released version 0.3.0 of the SuperCatForm:

Changelog:

  • New form events that allows you to hook in before, after and on failure of tool execution
  • Form tools now support examples as an argument of the @form_tool decorator
  • Main prompts for entity extraction and tool selection are easily overrideable from your SuperCatForm class
  • Better documentation

Hope somebody will find this useful! Γ  la prochaine

silent wasp
#

Hi! Given that many people are reporting bugs with ollama, gemini and anthropic models I've decided to release 0.3.1 version of the SuperCatForm which basically monkey patch the standard cat.llm() method to support the latest changes from those providers, granting full compatibility with those models. I seize the opportunity to enhance a little the api of that method allowing developers to be more flexible passing both strings and ChatPromptTemplate objects with the related prompts params. You can either call super_llm or use the standard cat.llm that will invoke the above.
Cheerz!

lusty moth
#

Hi, I'm noticing with the new version (I don't know if it's related) that at the start of the form (I have 4 fields to fill in) I fill in the fields one turn at a time (so I tell them first the dates, product type and finally the country) and in the last turn he basically loses his previous slots

silent wasp
lusty moth
lusty moth
#

hello @silent wasp "Dynamic Models with Model Getter" it's supported by super cat form? if i will use i will define the form with the annotation @super_cat_form?

silent wasp
silent wasp
#

Hi guys! Huge updates for the SuperCatForm plugin! Version 0.4.0 has been just released.

  • SuperCatForm now supports creating multi-step workflows through nested forms. (Thanks to the great work of @severe ice)
  • fresh_start attribute was added to allow a clean form startup from previous conversation turns (thanks @shell scroll for the suggestion)

How to use sub forms

First, code up your sub-form like any other SuperCatForm.

tip: ditch the @super_cat_form decorator on sub-forms if you don't want them triggering randomly in the wild. Keep them leashed to their parent.

Then create a parent form with a tool method that fires up your sub-form. That's it! When the sub-form wraps up, it hands control back to the parent automatically.

#

Sub Form Example


# ============= ADDRESS SUB-FORM =============

class AddressModel(BaseModel):
    street: str = Field(description="Street address")
    city: str = Field(description="City name")

class AddressForm(SuperCatForm):
    description = "Collect address information"
    model_class = AddressModel
    start_examples = [
        "I want to enter an address",
    ]
    stop_examples = [
        "cancel address entry",
    ]

    def submit(self, form_data):
        # Stuff the address data into the parent form
        self.parent_form.form_data['address'] = form_data
        return {
            "output": f"Got it! Address saved: {form_data['street']}, {form_data['city']}, {form_data['zip_code']}"
        }

# ============= MAIN ORDER FORM =============

class OrderModel(BaseModel):
    customer_name: str = Field(description="Customer's full name")
    items: List[str] = Field(description="Items to order")
    address: dict = Field(description="Customer's address")

@super_cat_form
class OrderForm(SuperCatForm):
    name = "OrderForm"
    description = "Process customer orders"
    model_class = OrderModel
    start_examples = [
        "I want to place an order",
    ]
    stop_examples = [
        "cancel my order",
    ]

    @form_tool(return_direct=True, examples=["I need to add my address", "Enter my address"])
    def collect_address(self):
        """Collects the customer's address."""
        # Launch the address form and let it do its thing
        return self.start_sub_form(AddressForm)

    def submit(self, form_data):
        items_summary = ", ".join(form_data['items'])
        address = form_data.get('address', {})
        address_str = f"{address.get('street', '')}, {address.get('city', '')},"

        return {
            "output": f"Order placed for {form_data['customer_name']}. Items: {items_summary}. Shipping to: {address_str}"
        }
lusty moth
#

Great release! I found very interesting the sub form feature because I’m imaging an agent that use an endpoint to retrive real time data: the main form can be the mandatory field for the api that retrieves to you some data and then chatting user can refine the research (behinds the scene will complete sub form that have the other parameters). Cool !

lusty moth
silent wasp
lusty moth
#

no then I can successfully call the parent form, the child form and then also return to the parent form perhaps modifying one of its fields, returning to the parent form I still have my dict with the fields of the subform: in the submit() of the parent should I handle the case where I also have the fields of the child form? Another thing: is there a way to avoid that the cat when it calls message_incomplete avoids listing the "optional" fields?

silent wasp
lusty moth
#

No easy to explain 🀣 I mean: chatting with the cat I start the father form, then I enter in the sub form and during the chat I able to re enter in the father form ( no fresh start). Returning on the father form, as filled field I found the files that come from the child( and this is good) but actually on the submit of the father If I need I have to manage there the fields that come from child form ?

silent wasp
lusty moth
#

yes it's ok this! Another doubt it's in the submit() of the child form: i try to access from there to the field that are only of the father (like the customer_name in your example on github). Access with self.parent_form.form_data.get('customer_name') i have always None

lusty moth
#

To satisfied my flow with the super cat form entering in the sub form in the submit i trigger the submit of the parent with all the fields that i need to do an API call