We broke the conversation workflow up into various components. Each component is defined with a set of editable properties. Properties can be some primitive values, arrays, or other components (children). When a developer creates a component, they also create the component’s definition in which they specify what kind of values each property expects. That way, the GUI can restrict some property to accept only certain types of components (defined by supported interfaces).
There are several main types of components depending on their role in the workflow.
Let’s start with conversation blocks, which represent different steps in our conversation.
It’s all like building a website
It’s considered good practice to define a sitemap when you are creating a web application. Each page in the sitemap reveals to the user exactly one main topic. When the user lands on a particular page, it presents him with topic information and possible actions/navigation options they may take from that point.
Let’s consider a simple product catalogue. On the home page we introduce ourselves and we display a search box and category list links. Each particular category page has a list of category products, while a product page displays full product info.
Building a chat service with Convoworks works the exact same way. You define steps in the conversation (which is analogous to a sitemap), where each step is defined using the conversation block, and it has one main topic. Technically, each block can do several things, but there will always be one main topic you will use to name this block and have a nice meaningful sitemap and workflow.
For the sake of simplicity, our initial Convoworks version does not treat a sitemap as a tree. Instead, it is just a list of blocks. Our estimate is that in most cases you will have less than a dozen blocks in your workflow. We plan on supporting a tree-like structure in the future, but for now, you can achieve similar results by reordering blocks and giving them meaningful names.
Single block execution
Here is a small difference between classic webpage and Convoworks blocks: we do not have “links” to move focus to another page without any processing. Instead, we have to process every user request and then move focus if it is requested of us.
Each block has two main parts. One is the initial read phase and it serves for displaying or telling initial information to the user. After that, the system waits for the user’s request. When the user makes a request, the service will try to execute the second phase of the current block, called the “process” phase. It will search among block processors if any one of them can accept the current request. If none can be found, the “fallback” flow will be triggered. If any processor accepts the request, the service will run it, meaning it will execute one of its sub elements flows.
Service workflow and components
We've explained what blocks are and how they're similar to a website's pages. There are several more types of components that you'll use when building your skills, so we'll go over them.
Elements are the "actions" that your skill performs. There's no strict separation within the groups, but you could loosely describe them in 3 styles:
- Display – Present some kind of information to the user. Most often speech, or visuals on devices with a display.
- Data – Fetch data from databases, via HTTP requests, read from a JSON file… Anything that is to do with data manipulation.
- Control – Flow control structures that dictate what your skill will do based on some conditions. The If element belongs here, in addition to the various loop elements.
The Display and Data categories of elements are somewhat dependent on the platform and/or device they're running on, as well as where Convoworks is installed, i.e. WordPress plugin or some local integration. Control elements are platform-agnostic, meaning they will do the same thing regardless of which platform they're running on.
Elements are run in sequence, one after another. An element might have a container for other sub-elements, e.g. If Element having a container for Else If sub-elements.
We've talked about what a processor is already, so we'll just do a quick summary. A processor contains at least two parts: a flow to be executed if the processor is triggered, and a set of filters that dictate what the processor should trigger on. If the processor runs, you will receive information about it inside the executed flow.
More specialized filters might contain more flows, and they might eliminate the filter container altogether since a developer can build processors with pre-defined filters that activate it. For example, the Yes/No Processor from our core package does just that. It offers a flow for when the user says "Yes" or anything affirmative, and a flow for "No" or negatives.
When a request comes in, each processor in the current block is taken into consideration in sequence, sort of like elements. If none are matched, then the service will check for a special type of block called
Service Processors, and if it exists, will try looking for matching processors in there. If there are no matches, then the Fallback flow of the current block is executed.