Category Archives: UX

Chatbots as middlemen

Chatbots typically serve their customers on 1:1 basis. They are not unlike digital assistants (Cortana, Siri, Alexa etc.) except that a chatbot is usually designed to execute a small number of prefined tasks well and focus on a narrow subject like filling a pizza order for example.

Building chatbots is easy, but making them clever is more difficult. Despite all the analytics on user behavior, it is still impossible to anticipate every user reaction. As the technology, Conversation as a Platform (CaaP), evolves, creating more intelligent bots becomes easier and easier, but until Skynet grows self-aware humans still serve a purpose.

Imagine a customer service chat on a website. A bot can probably handle most of the problems a customer could have. For instance, implementing a simple FAQ bot is trivial using Microsoft’s QnA Maker. Add some additional intellect including natural language understanding service and whatnot and you have an efficient customer service bot in your hands that 9 out of 10 customers are perfectly happy with. But for that one customer, you might want to consider a fallback: Let the human – in this case a customer service agent – take over to ensure customer satisfaction.

As long as you have the human labour, implementing this isn’t rocket science. What you need to do is as follows:

  1. Make sure your bot keeps track of all the individuals the bot sees (but remember privacy policies!)
  2. Make sure your bot also keeps track of itself. This might sound weird at first, but I’ll make the reason apparent soon.
  3. Design the handover scenario. It could be based on sentiment analysis or simply a request of help by the user.
  4. Implement the message relaying logic (don’t worry – there are samples available!)

How and why to keep track of people and bots

By keeping track I mean collecting the contact information of a user (and the bot – I’ll explain later) from the bot’s perspective. You can’t send a post card to a person without knowing his or her address. The same applies to the bot framework: You cannot send a message to a user without knowing the IDs of the user and the conversation. What you’ll need at least are:

The aforementioned details may be enough, but this depends on the channel (Skype, MS Teams, Slack etc.) You might as well store all the details as shown in the following tables.

Table 1. Identities in Skype (all values are of type string).
Me Bot
ChannelId skype skype
ChannelAccount.Id 29:1byUvXHHhinNxwnPCHh4MPhpfiJUbadX_Y3_sTkBspdiSke8sX_Ps6riTYRVez5jT 28:f99fa2c3-8834-418e-b293-039205238055
ChannelAccount.Name Tomi Paananen Intermediator Bot Sample
ConversationAccount.Id 29:1byUvXHHhinNxwnPCHh4MPhpfiJUbadX_Y3_sTkBspdiSke8sX_Ps6riTYRVez5jT 29:1byUvXHHhinNxwnPCHh4MPhpfiJUbadX_Y3_sTkBspdiSke8sX_Ps6riTYRVez5jT
ConversationAccount.Name (N/A in direct conversation) (N/A in direct conversation)

The values above are from a direct conversation in Skype between my bot and I. As you can see the channel account ID (read: my user ID) and the conversation account ID match, but that isn’t necessarily the case in other channels.

Table 2. Identities in Slack.
Me Bot
ChannelId slack slack
ChannelAccount.Id U1F3JK9A9:T1F248PJ8 B2NSU1D4Z:T1F248PJ8
ChannelAccount.Name tomi intermediatorbot
ConversationAccount.Id B2NSU1D4Z:T1F248PJ7:C3B1ZK5D0 B2NSU1D4Z:T1F248PJ7:C3B1ZK5D0
ConversationAccount.Name bottest bottest

So why do we need the bot’s identity stored too? As you can see, the same bot has a different identity on different channel and conversation. When we send a message to a user, we need to specify who the message is from, and some channel, for example Slack, doesn’t allow you to send messages from bots that aren’t actually there. So in order to relay a message from a user to another on another channel (e.g. Skype to Slack) we need to know and use the bot’s identity in Slack in the from field.

Briefly about the technical implementation: All the activities flow through the MessagesController class in a bot built with C# and that’s the ideal place to keep track of everything. As for bots, the bot is always the receiving party when it gets a new activity, and that’s how you store the bot identities. See Sending and Receiving Activities for more information.

Finally, store the records of the users and the bot somewhere in web e.g. Azure Table storage service. Note: My sample stores the data locally (in memory), which is never, ever a good idea, because bots are essentially web apps and can have multiple instances!

Comparison to Node.js

The essentials for relaying messages are the same whether you are building your bot using C# or Node.js SDKs. However, there are differences between the SDKs and some things are handled differently.

Table 3. Node.js counterparts for establishing user/bot identity.
C# Node.js Node.js example
Activity.ServiceUrl  IChatConnectorAddress.serviceUrl session.message.address.serviceUrl
Activity.ChannelId IAddress.channelId session.message.address.channelId


How to create dynamic FormFlow

You might’ve guessed it from the title – Yes, this is one of my no-nonsense posts. Strictly business and by business I mean code-talk.

This post is about a building block in Microsoft Bot Framework called FormFlow and namely how to add dynamic behavior to the flow when building bots using C#. If you are not familiar with FormFlow, I suggest your study the basics before reading further. Just the basics though, that’s enough.

Building simple FormFlows is… well, simple! This is a method that creates a basic form:

public static IForm<MyClass> BuildForm()
    var builder = new FormBuilder<MyClass>();

    return builder

Not difficult at all! And you can influence the behavior using, for instance, property attributes like:

public class MyClass
    [Prompt("What would you like the value of this property to be?")]
    public string Property1 { get; set; }


But what if you want to do some of the following:

  • Skip the questions you already know the answer to based on what the user said earlier?
  • Define the options presented for the user dynamically?
  • Change the way the question and options are presented to the user?
  • Validate the user’s response?
  • Customize the behavior of the form in the fly?

Some of the aforementioned things FormFlow tries to do for you automatically. However, usually to achieve a great experience you have to do a bit more work, and luckily, it is possible. See the resources available under Microsoft.Bot.Builder.FormFlow.Advanced namespace. One very useful class under there is called FieldReflector. Whilst you can still add ActiveDelegate and ValidateAsyncDelegate using the overloaded Field method in FormBuilder, FieldReflector allows you to do more:

.Field(new FieldReflector<MyClass>(nameof(MyClass.PropertyX))
    .SetActive((state) => SetFieldActive(state, nameof(MyClass.PropertyX)))
    .SetDefine(async (state, field) => await SetOptionsForFieldsAsync(state, nameof(MyClass.PropertyX), field))
    .SetAllowsMultiple(true) // Single selection vs. multi-selection
    .SetPrompt(new PromptAttribute("What type of values should this property have? {||}"))
    .SetValidate(async (state, value) => await ValidateResponseAsync(value, state, nameof(MyClass.PropertyX))))

…where SetFieldActive, SetOptionsForFieldAsync and ValidateResponseAsync are methods defined and implemented by the developer. See this class implementing the building of the form from my Dynamic FormFlow Sample. The snippet provides solution to all the questions presented in the bullet point list above. In case you are curious how this enables customizing the behavior in the fly, notice that you can run any arbitrary code in your response validation method (ValidateResponseAsync in the snippet).

In my Dynamic FormFlow Sample I use FormFlow to narrow down a spaceship selection from a static catalog of spaceships. Therefore, it is important that I don’t bother the user with unnecessary options; the user might’ve already told me that he/she is looking for a small ship and thus I shouldn’t later ask to select from options only available for large ships. That’s simply bad UX! Some queries I can skip in case there is only one option available. In my response validation method I do a search against the catalog using the details I’ve gathered from the user so far and  if the response is valid, I store the search results for later. With this approach I can narrow down the selection with as few questions as possible and without presenting the user with options that make no sense.

The caveats

Playing with FormFlow is not all bed of roses. I had to fight few errors, that for first seemed odd, until I got the hang of it. Here are some of the things to keep in mind:

  • After you build your form, it is built. It now exists. And you cannot really control the instance anymore. Why is this important to understand? Because you cannot say for certain when the methods (delegates) in your form are called. It’s now in the hands of the Bot Framework. So make sure your methods (delegates) work in any situation! For starters, have null checks.
  • Do not use the IList interface as a property type in the class where you are collecting user input (Spaceship.cs in the sample). It won’t work and you’ll get a FormCanceledException with “Cannot create an instance of an interface” message. Use List instead, it works.
  • Realize that you don’t have to do everything in the form; after the form is complete, you can continue with the data in a Dialog and ask further questions etc. That’s what I did in my sample, see SpaceshipSelectionDialog.cs.

And a top tip: If you are new to FormFlow, implement and test one complex field at a time.

So it’s a magic bullet?

No, it is not. FormFlow is a handy building block, but will not solve all problems. Duh.

If you feel like your FormFlow code is turning into horrible, uncontrollable mess and you feel like you need to compromise the UX, stop. Stop using FormFlow. You can do the same using Dialogs too and with really complex scenarios it will be – most likely – much easier too. FormFlow is a solution for fairly straightforward forms – it was never meant to be used with overly complex flows. Or at least I think that’s the case.

I should have a post about managing dialog flows out soon, but in the meanwhile, here’s the big secret: IDialogContext.Wait(<method name>) lets you define the next method that will process the next user response.