NestedState

The NestedState group several states together to form a new block. An example of the NestedState (with two layer of nesting) is like:

 

"learning_state": AutomataPage(
    name="learning_state",
    layout=layout2,
    event_listeners={
        'generate_topic_btn.click': {
            'goto': 'generate_topic_state',
            'enable': ['generate_word_btn', 'get_quiz'],
        },
        'generate_word_btn.click': 'generate_word_state',
    },
    inputs=["topic_list", "topic2word", "word2exp", "language"],
    outputs=["topic_list", "topic2word", "word2exp"],
    start_at="empty_state",
    end_at="learn_word_state",
    states={
        "empty_state": TaskState(
            name="empty_state",
        ),
        "generate_topic_state": TaskState(
            name="generate_topic_state",
            module_type='LLMFunctionModule',
            config=dict(
                type='LLMFunctionConfig',
                function_name="set_topic",
                function_description='${f"Propose a topic for studying language {language}, the topic would better contains lots of nouns to learn."}',
                function_parameters=[
                    dict(
                        name="topic",
                        type="str",
                        description="The topic to propose, e.g., greetings, numbers, etc."
                    )
                ],
                system_prompt='${f"You are teaching a {language} class. You want to design the curriculum by different topics, starting with the most basic one and then moving to more advanced ones."}',
                user_prompt='${f"You have chosen the following topics: {topic_list}. Now, you want to propose a different new topic for the next class."}',
            ),
            inputs={
                "generate_topic_btn": Button(
                    value='Click me to generate topic!'
                ),
                "get_quiz": Button(
                    value='Lets get a quiz',
                    interactive=False,
                ),
                
            },
            outputs={
                "topic": Textbox(
                    value="${topic}",
                    
                ),
                "topic_list": ValueType(
                    type="list",
                    value="${topic_list + [topic]}",
                    
                )
            },
            title="Generate Topic",
            next_state="whether_to_continue",
        ),
        "whether_to_continue": ConditionChoiceState(
            name="whether_to_continue",
            choices={
                "true": "generate_word_state",
                "false": "generate_topic_state",
            },
            condition='${topic2word.get(topic) is None or len(topic2word[topic]) < 3}',
            title="Check Idx",
        ),
        "generate_word_state": TaskState(
            name="generate_word_state",
            module_type='LLMFunctionModule',
            config=dict(
                type='LLMFunctionConfig',
                function_name="set_word",
                function_description='${f"Propose a word for studying language {language} and topic {topic}"}',
                function_parameters=[
                    dict(
                        name="word",
                        type="str",
                        description="The word to propose."
                    ),
                    dict(
                        name="explaination",
                        type="str",
                        description="The explaination of the word."
                    ),
                ],
                system_prompt='${f"You are teaching a {language} class. You want to design the curriculum by different topics, starting with the most basic one and then moving to more advanced ones. For each topic, you want to teach the most basic words first."}',
                user_prompt='${f"You have chosen the following topics: {topic}, and now we alreay generate some words {topic2word.get(topic) or []}. Now, you want to propose a new word to learn about {topic}."}',
            ),
            inputs={
                "generate_word_btn": Button(
                    value="Click me to generate word under this topic",
                    interactive=False,
                )
            },
            outputs={
                "word": Textbox(
                    value="${word}",
                    
                ),
                "explaination": Textbox(
                    value="${explaination}",
                    
                ),
                "topic2word": ValueType(
                    type="dict",
                    value="${{**topic2word, topic: (topic2word.get(topic) or []) + [word]}}",
                    
                ),
                "word2exp": ValueType(
                    type="dict",
                    value="${{**word2exp, word: (word2exp.get(word) or []) + [explaination]}}",
                ),
                "learn_text_output": Textbox(
                    value='${f"{word}: {explaination}"}',
                    
                ),
            },
            title="Generate Word",
            next_state="generate_sentence_and_speech",
        ),
        "generate_sentence_and_speech": NestedState(
            name="generate_sentence_and_speech",
            inputs=["language", "topic", "word"],
            outputs=["tts_text_input", "audio_path"],
            start_at="empty_state",
            end_at="text_to_speech",
            next_state="learn_word_state",
            event_listeners={
                'generate_sentence_and_speech_btn.click': 'generate_example_sentence_content',
            },
            states={
                "generate_example_sentence_content": TaskState(
                    name="generate_example_sentence_content",
                    module_type='LLMFunctionModule',
                    config=dict(
                        type='LLMFunctionConfig',
                        function_name="set_topic",
                        function_description='${f"Generate a sentence for speech generation in {language}, containing the given words"}',
                        function_parameters=[
                            dict(
                                name="tts_text_input",
                                type="str",
                                description="The generated text content, e.g., Hello, how do you do. etc."
                            )
                        ],
                        system_prompt='${f"You are instructing a {language} class. Currently, you wish to generate sentences to help students better grasp the language. These sentences may occur in various real-life situations and are in {language}."}',
                        user_prompt='${f"You have chosen the following topics: {topic}. Now, you want to propose a example sentence to learn about {topic}, which containing of {word}."}',
                    ),
                    outputs={
                        "tts_text_input": Textbox(
                            value="${tts_text_input}",
                        ),
                    },
                    title="Generate Sentence",
                    next_state="text_to_speech",
                ),
                "text_to_speech": TaskState(
                    name="text_to_speech",
                    module_type='TTSFunctionModule',
                    config=dict(
                        type='TTSFunctionConfig',
                        input='${f"{tts_text_input}"}',
                        speed=0.8,
                    ), # If the `input` parameter is not provided, the function will fetch the value of `tts_text_input` from the context (cooperating with LLM).
                    outputs={
                        "audio_path": Audio(
                            value="${audio_path}",
                            
                        )
                    },
                    title="text_to_speech",
                ),  
            }
        ),

Note that here generate_sentence_and_speech state wraps two states together, which can generate example sentences and the audio sequentially. The outer AutomataPage is also a type of NestedState that group the states inside a page together. The NestedState needs to specify the inputs and outputs as lists, e.g., the generate_sentence_and_speech state needs to obtain the variables

 inputs=["language", "topic", "word"],

from the parent ctx, and output the variables

outputs=["tts_text_input", "audio_path"],

back to the parent ctx.

Last updated