Bot Escalation SDK - .NET - Quickstart Guide
Stage 1: Build and deploy basic “Echo” bot
-
Follow Microsoft’s quickstart guide: “Create a bot with the Bot Builder SDK for .NET” https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-quickstart This quickstart builds a simple “Echo” bot and explains testing using Microsoft’s Bot Framework emulator.
-
Deploy this bot to Azure and test by following Microsoft’s guide: https://docs.microsoft.com/en-us/bot-framework/deploy-bot-visual-studio
Stage 2: Add Live Assist escalation to “Echo” bot
-
Obtain a Live Assist account number here
-
Configure Live Assist Agent skill here
-
Add the Live Assist Chat SDK package to the project via NuGet
-
Edit RootDialog.cs to add the following code elements to the RootDialog class:
- Add following Usage declarations:
using Microsoft.Bot.Builder.ConnectorEx;
using Newtonsoft.Json;
using System.Timers;
using Cafex.LiveAssist.Bot;
- Declare class instance variable sdk. An instance of Sdk is the link to a particular Live Assist account, all Live Assist chat operations are performed via methods of Sdk.
private static Sdk sdk;
- Declare class instance variable chatContext. An instance of ChatContext references a particular chat with a Live Assist agent. For simplicity, this sample handles just one concurrent chat.
private static ChatContext chatContext;
- Declare class instance variable conversationRef. This will reference a Microsoft Bot conversation and is used to reply to the end user.
private static string conversationRef;
- Declare class instance variable timer. This will reference a timer used to periodically poll for Live Assist chat events.
private static Timer timer;
- Within the StartAsync method, instantiate and configure Sdk with a Live Assist account number
public Task StartAsync(IDialogContext context) { Sdk = sdk ?? new Sdk(new SdkConfiguration() { AccountNumber = "__CHANGE_ME__" }); context.Wait(MessageReceivedAsync); return Task.CompletedTask; }
- Add method MessageRecievedAsync, this will either: pass the incoming message to a Live Assist agent if the chat has already been escalated, escalate to a Live Assist agent if the incoming message contains the word “help”, or echo the incoming message back to the end user if the first two conditions are not met.
private async Task MessageReceivedAsync( IDialogContext context, IAwaitable<object> result) { var activity = await result as Activity; if (chatContext != null) { // As chatContext is not null we already have an escalated chat. // Post the incoming message line to the escalated chat await sdk.PostLine(activity.Text, chatContext); } else if (activity.Text.Contains("help")) { // "help" within the message is our escalation trigger. await context.PostAsync("Escalating to agent"); await Escalate(activity); // Implemented in next step. } else { // Bot just Echos await context.PostAsync($"You sent {activity.Text}"); } context.Wait(MessageReceivedAsync); }
- Add method Escalate, this encapsulates the requesting of a chat via the live Assist SDK, assignment of values to class variables conversationRef and chatContext and starting of a timer to poll for Live Assist chat events.
private async Task Escalate(Activity activity) { // This is our reference to the upstream conversation conversationRef = JsonConvert.SerializeObject( activity.ToConversationReference()); var chatSpec = new ChatSpec() { // Set Agent skill to target Skill = "__CHANGE_ME__", VisitorName = activity.From.Name }; // Start timer to poll for Live Assist chat events if (timer == null) { timer = timer ?? new Timer(5000); // OnTimedEvent is implemented in the next step timer.Elapsed += (sender, e) => OnTimedEvent(sender, e); timer.Start(); } // Request a chat via the Sdk chatContext = await sdk.RequestChat(chatSpec); }
- Add method OnTimedEvent, to handle events from the periodic timer constructed in the previous step. When triggered, this will poll for Live Assist chat events. Events will include changes of chat state: "waiting", "chatting", "ended" and lines of text received from Live Assist.
async void OnTimedEvent(Object source, ElapsedEventArgs eea) { if (chatContext != null) { // Create an upstream reply var reply = JsonConvert .DeserializeObject<ConversationReference>(conversationRef) .GetPostToBotMessage() .CreateReply(); // Create upstream connection on which to send reply var client = new ConnectorClient(new Uri(reply.ServiceUrl)); // Poll Live Assist for events var chatInfo = await sdk.Poll(chatContext); if (chatInfo != null) { // ChatInfo.ChatEvents will contain events since last call to poll. if (chatInfo.ChatEvents != null && chatInfo.ChatEvents.Count > 0) { foreach (ChatEvent e in chatInfo.ChatEvents) { switch (e.Type) { // type is either "state" or "line". case "line": // Source is either: "system", "agent" or "visitor" if (e.Source.Equals("system")) { reply.From.Name = "system"; } else if (e.Source.Equals("agent")) { reply.From.Name = chatInfo.AgentName; } else { break; } reply.Type = "message"; reply.Text = e.Text; client.Conversations.ReplyToActivity(reply); break; case "state": // State changes // Valid values: "waiting", "chatting", "ended" if (chatInfo.State.Equals("ended")) { chatContext = null; } break; } } } } } }
- Publish to Azure, using the configuration created in Step 2.
- Test your bot.
-
Log in to the Dynamics CRM Web Client, see this help page for how to do this.
-
Test using Microsoft’s Bot framework emulator, as in Step 2.
-
Complete RootDialog.cs