Search code examples
botframeworkbotsazure-language-understandingadaptive-cards

Need some guidance on how to properly use bot framework SDK


I'm in the process of building a bot and the experience has been challenging for me so far. This is most likely since I'm coming from v1 and I'm trying to rebuild my bot in v4 style, which is pretty much a completely different framework it seems.

I find there's quite a lot of documentation out there, but it's been split up into theory and practice, probably due to the different development frameworks you can use (i.e. Node, C#). But having to go back and forth between these articles is not helping,

After quite a bit of messing around, I got to a point where things are beginning to get a bit more decent, but I still feel there's lots of room for improvement. I can't share the whole project at the moment, but I've created a gist of the most important code here: https://gist.github.com/jsiegmund/831d5337b1a438133991070daba8a27e

So my issues/questions with this code are the following:

  1. The way to add dialogs and mainly the need to add prompts for retrieving the answers is confusing. I get the idea, but not the inner workings. For instance: I now have the prompts named after the same method names of the corresponding dialog step, is that the way it's supposed to work? There seems to be some magic code linking everything together, by convention? It would make much more sense to me when the waterfall steps would also include the prompts.

  2. What's the right way of feeding the dialog with information so it can skip steps? I've got LUIS intents set-up in the main dialog which then open up this dialog for hour booking. Suppose my user says "I'd like to book 8 hours on customer X", I'd like the dialog to pre-populate the amount to 8 and the customer to X.

  3. The customer/project resolving is maybe a not-so-standard requirement here. These come from a third party application, retrieved through API/SDK. So based on the logged-in user I need to go out to that application and retrieve the data for this user. This comes back in key/value pairs, where the key is a GUID. I don't want the user to type in GUIDs, so I have created these action buttons with the names of the customers, but to get the ID value into the next step it now 'writes' the GUID in the chat instead of the customer name. Using the name is tricky as I can't fully rely on those being unique. Also, for selecting the project I need the customer GUID and saving the final entry I also need the ID's. But I don't want the user to see those.

  4. The way I now have the cards built is also weird to me. I first need to add a dialog for the card, and later when calling stepContext.PromptAsync I need to supply the card as an attachment as well. Feels duplicate to me, but removing either one of the steps fails. The normal style prompt doesn't work for me as that doesn't handle key/value but just strings (see number 3).

Okay, so those are some of the things I'm struggling with. I'm getting there and it works for now, but as said I can't escape the feeling that I'm not doing it right. If anyone could shine a light on this that would be highly appreciated.


Solution

  • Yeah, there is a lot of changes from version to version. Do you really mean v1?! 😲 Or v3?

    1. The way to add dialogs and mainly the need to add prompts for retrieving the answers is confusing. I get the idea, but not really the inner workings. For instance: I now have the prompts named after the same method names of the corresponding dialog step, is that the way it's supposed to work? There seems to be some magic code linking everything together, by convention? It would make much more sense to me when the waterfall steps would also include the prompts.

    Essentially. The steps listed in the waterfall array are the names of the method names you've created. Basically, this is where you are giving the order of the steps that should be done by the bot. Prompts are classes used to retrieve data and are populated into the ("main") dialog using AddDialog() and are stored in dialog state with unique names so that they can be retrieved correctly. I see your point on how it might be simple to have everything setup in one "call" or declaration, and there probably could have been other approaches to how this was implemented; but this is what we got.

    1. What's the right way of feeding the dialog with information so it can skip steps? I've got LUIS intents set-up in a main dialog which then open up this dialog for hour booking. Suppose my user says "I'd like to book 8 hours on customer X", I'd like the dialog to pre-populate the amount to 8 and the customer to X.

    Typically, steps use the previous steps value to reply, act or continue. In simple scenarios, skipping steps can be done by checking the state for those values. In the multiturn sample, if the user does not want to supply their age, it goes on to the next step and then it checks for the value and skips the step (it really doesn't skip it, it reports no age given, but you could just continue without any reply). Assuming the LUIS side of things is correct and getting the right intent+entities (let's say 'booking' intent and entities ['time' and 'customer']), then that should be doable. You would populate state info for both of those entities and then the later step (say prompting for the customer step) would just skip/bypass.

    But, what you really want to do is look at adaptive dialogs. They are new and make this type of scenarios much more dynamic and flexible. Look here:

    1. The customer / project resolving is maybe a not-so-standard requirement here. These come from a third party application, retrieved through API/SDK. So based on the logged in user I need to go out to that application and retrieve the data for this user. This comes back in key/value pairs, where the key is a GUID. Obviously I don't want the user to type in GUIDs, so I have created these action buttons with the names of the customers, but to get the ID value into the next step it now 'writes' the GUID in the chat instead of the customer name. Using the name is tricky as I can't fully rely on those being unique.

    I'm not 100% sure on this part. Let me look into it and get back to you.

    Also, for selecting the project I need the customer GUID and saving the final entry I also need the ID's. But I don't want the user to see those.

    State (conversation|user|etc) would be a good place to manage this.

    1. The way I now have the cards built is also weird to me. I first need to add a dialog for the card, and later when calling stepContext.PromptAsync I need to supply the card as an attachment as well. Feels duplicate to me, but removing either one of the steps ends in failure. The normal style prompt doesn't work for me as that doesn't handle key/value but just strings (see number 3).

    Nope, that's correct. I know it feels weird, but that is the way to do it. Basically, anything but simple text will be an attachment. Cards are JSON, therefore an attachment and you need to send that to the user/client.

    You're doing it all correct. Again; I would suggest on looking at adaptive dialogs as that's the newer tech and the move forward. But otherwise; you're on the right path!