# An Advanced Example

In this chapter, we will implement a more advanced app. This app will start by testing the user's understanding of Pro Config, and then redirect to different pages based on the user's score. If the user's score is low, they will be redirected to a Pro Config tutorial chatbot. This advanced example includes concepts of Pro Config we have learned in previous chapters and serves as a great starting point for developers who would prefer building an app with more complicated logic. \
\
Here is the config:

{% code lineNumbers="true" %}

```json
{
    "type": "automata",
    "id": "advanced_example_demo",
    "initial": "home_page_state",
    "inputs": {},
    "outputs": {},
    "context": {
      "questions_string": "[{\"question\": \"Which of the following statements is not correct? \\n A. The execution of an Automata starts from the `initial` state. \\n B. An Automata can contain multiple AtomicStates. \\n C. Each AtomicState must define both inputs and outputs. \\n D. We can define transitions in either Automata or AtomicState.\", \"answer\": \"C\", \"explanation\": \"Both inputs and outputs in an AtomicState are optional.\"}, {\"question\": \"You are building an AutomicState, please choose the correct order of execution: \\n A. inputs -> tasks -> outputs -> render \\n B. render -> inputs -> tasks -> outputs. \\n C. tasks -> inputs -> outputs -> render.  \\n D. render -> tasks -> inputs -> outputs\", \"answer\": \"A\", \"explanation\": \"The correct order is `inputs -> tasks -> outputs -> render`. Please refer to `Expressions and Variables`\"}, {\"question\": \"Which of the following expressions is not correct (assume all the variables exist)? \\n A. context.variable \\n B. variable \\n C. variable1 + variable2 \\n D. np.array(variable)\", \"answer\": \"D\", \"explanation\": \"Our expression supports JavaScript grammar.\"}]",
      "questions": "",
      "question_idx": "",
      "chosen_answer": "",
      "correct_answer": "",
      "correct_count": "",
      "memory": "{{[]}}",
      "is_correct": "{{false}}",
      "intro_message": "",
      "tts_widget_id": ""
    },
    "transitions": {
      "go_home": "home_page_state",
      "get_quiz": "quiz_page_state",
      "continue": "continue_state"
    },
    "states": {
      "home_page_state": {
        "inputs": {
          "intro_message": {
            "type": "text",
            "user_input": true,
            "default_value": "Hi, this is your Pro Config Tutorial Bot, how can I assist you today"
          },
          "tts_widget_id": {
            "type": "text",
            "user_input": true,
            "default_value": "1743159010695057408"
          }
        },
        "outputs": {
          "context.intro_message": "{{intro_message}}",
          "context.tts_widget_id": "{{tts_widget_id}}",
          "context.questions": "{{JSON.parse(context.questions_string)}}",
          "context.question_idx": "{{0}}",
          "context.correct_count": "{{0}}"
        },
        "render": {
          "text": "Welcome to this Pro Config tutorial bot. Let's start a quiz!",
          "buttons": [
            {
              "content": "Quiz",
              "description": "get_quiz",
              "on_click": "get_quiz"
            }
          ]
        }
      },
      "quiz_page_state": {
        "outputs": {
          "context.correct_answer": "{{context.questions[context.question_idx]['answer']}}"
        },
        "render": {
          "text": "{{context.question_idx + 1}}. {{context.questions[context.question_idx]['question']}}",
          "buttons": [
            {
              "content": "A.",
              "description": "Choose A.",
              "on_click": {
                "event": "check_answer",
                "payload": {
                  "chosen_answer": "A"
                }
              }
            },
            {
              "content": "B.",
              "description": "Choose B.",
              "on_click": {
                "event": "check_answer",
                "payload": {
                  "chosen_answer": "B"
                }
              }
            },
            {
              "content": "C.",
              "description": "Choose C.",
              "on_click": {
                "event": "check_answer",
                "payload": {
                  "chosen_answer": "C"
                }
              }
            },
            {
              "content": "D.",
              "description": "Choose D.",
              "on_click": {
                "event": "check_answer",
                "payload": {
                  "chosen_answer": "D"
                }
              }
            }
          ]
        },
        "transitions": {
          "check_answer": {
            "target": "analyze_answer_state",
            "target_inputs": {
              "chosen_answer": "{{payload.chosen_answer}}"
            }
          }
        }
      },
      "analyze_answer_state": {
        "inputs": {
          "chosen_answer": {
            "type": "text",
            "user_input": false
          }
        },
        "outputs": {
          "context.chosen_answer": "{{chosen_answer}}",
          "context.is_correct": "{{chosen_answer == context.correct_answer}}"
        },
        "render": {
          "text": "Check answer state."
        },
        "transitions": {
          "ALWAYS": [
            {
              "target": "correct_answer_state",
              "condition": "{{context.is_correct}}"
            },
            {
              "target": "wrong_answer_state",
              "condition": "{{true}}"
            }
          ]
        }
      },
      "correct_answer_state": {
        "outputs": {
          "context.question_idx": "{{(context.question_idx + 1) % context.questions.length}}",
          "context.correct_count": "{{context.correct_count + 1}}"
        },
        "render": {
          "text": "Congratulations! You have chosen the correct answer {{context.correct_answer}}",
          "buttons": [
            {
              "content": "Continue",
              "description": "continue",
              "on_click": "continue"
            }
          ]
        }
      },
      "wrong_answer_state": {
        "outputs": {
          "context.question_idx": "{{(context.question_idx + 1) % context.questions.length}}"
        },
        "render": {
          "text": "Oh No! The chosen answer is {{context.chosen_answer}}, while the correct one is {{context.correct_answer}}.",
          "buttons": [
            {
              "content": "Continue",
              "description": "continue",
              "on_click": "continue"
            }
          ]
        }
      },
      "continue_state": {
        "render": {
          "text": "Click to Next Question"
        },
        "transitions": {
          "ALWAYS": [
            {
              "target": "quiz_page_state",
              "condition": "{{context.question_idx > 0}}"
            },
            {
              "target": "finish_state",
              "condition": "{{context.correct_count == context.questions.length}}"
            },
            {
              "target": "review_state",
              "condition": "{{true}}"
            }
          ]
        }
      },
      "finish_state": {
        "render": {
          "text": "Congratulations! You are now a master of Pro Config!",
          "buttons": [
            {
              "content": "Home",
              "description": "Back to Home",
              "on_click": "go_home"
            }
          ]
        }
      },
      "review_state": {
        "outputs": {
          "context.memory": "{{[]}}"
        },
        "render": {
          "text": "{{context.intro_message}}"
        },
        "transitions": {
          "CHAT": "chat_page_state"
        }
      },
      "chat_page_state": {
        "inputs": {
          "user_message": {
            "type": "IM",
            "user_input": true
          }
        },
        "tasks": [
          {
            "name": "generate_reply",
            "module_type": "AnyWidgetModule",
            "module_config": {
              "widget_id": "1744214024104448000", // GPT-3.5
              "system_prompt": "You are a teacher teaching Pro Config. Pro Config is a powerful tool to build AI native applications. Here are some questions and answers about basic concepts of Pro Config: {{context.questions_string}}",
              "user_prompt": "{{user_message}}",
              "memory": "{{context.memory}}",
              "output_name": "reply"
            }
          },
          {
            "name": "generate_voice",
            "module_type": "AnyWidgetModule",
            "module_config": {
              "widget_id": "{{context.tts_widget_id}}",
              "content": "{{reply}}",
              "output_name": "reply_voice"
            }
          }
        ],
        "outputs": {
          "context.memory": "{{[...context.memory, {'user': user_message}, {'assistant': reply}]}}"
        },
        "render": {
          "text": "{{reply}}",
          "audio": "{{reply_voice}}",
          "buttons": [
            {
              "content": "Home",
              "description": "Click to Go Back to Home.",
              "on_click": "go_home"
            }
          ]
        },
        "transitions": {
          "CHAT": "chat_page_state"
        }
      }
    }
  }
```

{% endcode %}

We now elaborate on the above example by first reviewing some learned concepts, and then introducing some advanced features.

### Overview of the Entire Pipeline

Here is the pipeline of the application defined by the above config:

* When the app starts, user will be prompted to input the `intro_message` and `tts_widget_url`, which will be passed through the automata and reused later in the chat page.
* The user is then directed into a quiz page, where they will be answering several questions about the basic concepts of Pro Config.
  * If the user gets all questions correct, the app will end, and a congratulation message will pop up.
  * If the user gets some question wrong, the app will redirect to a chatbot that can interact and answer questions about Pro Config.

<figure><img src="/files/qIhCBRN4ap0DZXJ3up3J" alt=""><figcaption><p>This flowchart demonstrates the major state transfer, input/output in each state, and key variable transition. <br>For demo purpose, some states like "continue_state" "review_state" is not drawn out.</p></figcaption></figure>

### Review of Basic Concepts

#### Inputs, Outputs, and Render

In the above example, we have used two types of inputs `text` and `IM` . `text` inputs prompts the user to input the `intro_message` and `tts_widget_url`. `IM` input is used in the chatbot where user directly send text messages.&#x20;

\
The outputs used in the example are mainly for writing some variables to the context and do some basic calculation (such as increasing the question index). For rendering, we have used text, buttons, and audio in this example.

#### Workflow

We simply use LLM + TTS as the workflow in the `chat_page_state` ,which has been already discussed in previous chapter. We have fed some basic knowledge of Pro Config to the system\_prompt of the LLM, so that the chatbot has it's internal knowledge base to answer questions.

#### Transitions

The above example includes transitions through buttons (controlled by the `on_click` properties) and some reserved action names such as `CHAT` and `ALWAYS` . It also demonstrates how to perform conditional transitions, which we will discuss later.

#### Expressions and Variables

We can find some basic use cases of expressions (JavaScript grammar) to initialize some variables and do some basic calculation. We have also demonstrated how to use context to pass variables across different states.&#x20;

### Advanced Features

#### Conditional Transitions

Please refer to  `continue_state` which determines the state transition based on user's quiz score.

```json
      "transitions": {
        "ALWAYS": [
          {
            "target": "quiz_page_state",
            "condition": "{{context.question_idx > 0}}"
          },
          {
            "target": "finish_state",
            "condition": "{{context.correct_count == context.questions.length}}"
          },
          {
            "target": "review_state",
            "condition": "{{true}}"
          }
        ]
      }
```

In this example, it will redirect to the `quiz_page_state` if the `question_idx` is valid. Otherwise, if the user has answered all the questions correctly, it will jump to the `finish_state`. If the user get any question wrong, it will jump to the `review_state` the let the user chat with a Pro Config tutorial bot. The conditions of the transition cases are evaluated sequentially, and the condition in the last case `{{true}}` is similar to the `default` keyword in C++ `case` .&#x20;

#### Passing parameters through transitions

To decide whether the user has chosen the correct answer, we need to pass the chosen answer as a parameter during the transition. This can be achieved by:

```json
      "quiz_page_state": {
      ...
        "render": {
          "text": "{{context.question_idx + 1}}. {{context.questions[context.question_idx]['question']}}",
          "buttons": [
            {
              "content": "A.",
              "description": "Choose A.",
              "on_click": {
                "event": "check_answer",
                "payload": {
                  "chosen_answer": "A"
                }
              }
            },
            ...
            {
              "content": "D.",
              "description": "Choose D.",
              "on_click": {
                "event": "check_answer",
                "payload": {
                  "chosen_answer": "D"
                }
              }
            }
          ]
        },
        "transitions": {
          "check_answer": {
            "target": "analyze_answer_state",
            "target_inputs": {
              "chosen_answer": "{{payload.chosen_answer}}"
            }
          }
        }
      },
      "analyze_answer_state": {
        "inputs": {
          "chosen_answer": {
            "type": "text",
            "user_input": false
          }
        },
        ...
      }
```

In the above snippet, we first define different payloads for the four buttons (A, B, C, D), and pass the chosen answer through the `target_inputs` of the transition `check_answer`. The variable `chosen_answer` can be used in the target state `analyze_answer_state` later.

#### More Complicated Expressions

In the above example, we have also shown more complicated expressions such as parse a JSON string to the `context.questions`, which is useful to initialize structured data. Our expression also supports slicing of a list or a dict, such as&#x20;

```
"text": "{{context.question_idx + 1}}. {{context.questions[context.question_idx]['question']}}",
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://myshell-wiki.gitbook.io/proconfig-tutorial/tutorial/an-advanced-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
