Building Proactive Bot with Power Virtual Agents

Let’s say you own a restaurant business and you have a chatbot to help your customers order food. Once the food is delivered, wouldn’t it be nice for your chatbot to send a quick nudge to the customer to ask how the experience was? – All you are doing is to proactively engage the customer to provide a review all without leaving the conversation UI experience.

Now the bigger question is, how do I do this in the context of Power Virtual Agents?

If you have read my previous blog post, the general theme of that is to leverage the power virtual agents for the most part for its simplified bot maker experience (to author topics) and extend it with the bot framework (Bot Framework Companion app) where ever necessary to add powerful features. We are going to leverage the same technique to develop this Bot.

To quickly refresh your memory, here is the technique on a high level:

Let’s summarize all the moving parts involved:

  1. Create a Food order bot with the Power Virtual Agents that stores the food order in a Power Apps (model driven).
  2. Create a Companion bot (with the bot framework) that acts as a relay bot facing the customer to take the food order.
  3. This Companion bot also intercepts the Conversation Reference when the customer initiates the conversation and stores it in the Power Apps.
  4. When the food order is delivered, the staff will set the status of the food order record to Delivered.
  5. This status change triggers the Power Automate which retrieves the Customer’s Conversation Reference from the Power Apps and notifies the Companion Bot.
  6. The Conversation Reference holds the information about the Conversation Id, Customer Data and all the other metadata that can be used to revive the same conversation channel in order for the companion bot to send a proactive message.

The below picture shows the technique behind storing the Food Order and the Conversation Reference in the Power Apps

The below picture shows the technique behind triggering the Power Automate when the food is delivered, retrieving the conversation reference and sending it to the companion bot.

Food Order Bot

This is a simple topic that you can author with the Power Virtual Agents for your customer to order food.

Create a Power App

Here, we are creating a simple model driven Power Apps that contains three entities –

  1. Customer – Standard Contact entity
  2. Food Order (this is where all the Food Orders reside) – The Power Virtual Agents (PVA) creates the food order record leveraging the Power Automate.
  3. Conversation Reference (this is where all the Conversation References are stored – in other words, this is nothing but the representation of the Conversation Reference object that is intercepted by the Companion Bot). Note that Conversation Reference is just to capture the technical metadata of the conversation and not the actual transcript. One Customer entity can be associated with multiple Conversation Reference records. For the purpose of simplicity, let’s assume that there is only 1 Conversation Reference that is active for a particular customer.

The Companion Bot

This is nothing but a relay bot built with the Bot Framework, which will be deployed to Azure Bot Service to serve the customer. This companion bot is primarily responsible for relaying the customer’s message to Power Virtual Agents and Power Virtual Agents message to the customer. If you have read my previous blog post about the PVA extension, then this will make sense to you 🙂

When a customer initiates the conversation with the Bot, a Conversation Reference is created by the Bot Framework. We are extending the relay bot (Companion Bot), so that during the event of OnConversationUpdate, we are capturing the incoming conversation metadata and invoking the Power Automate with it. The idea here is to persist the Conversation Reference somewhere so that we have to way to reconnect to the same Conversation channel (that was originally initiated by the customer) in order to reach out to the customer to proactively send them a message. The persistence layer can be any other database as well and not just the Power Apps.

// Invoked when a conversation update activity is received from the external Azure Bot Service channel
// Start a Power Virtual Agents bot conversation and store the mapping
protected override async Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
AddConversationReference(turnContext.Activity as Bot.Schema.Activity);
await s_conversationManager.GetOrCreateBotConversationAsync(turnContext.Activity.Conversation.Id, _botService);
private void AddConversationReference(Bot.Schema.Activity activity)
var conversationReference = activity.GetConversationReference();
var convRefJson = JsonConvert.SerializeObject(conversationReference);
var response = RunFlow(";, convRefJson);

In case you are wondering, here is the snapshot of what is captured as part of the Conversation Reference:

All the Power Automate does is to create a Conversation Reference Record in the Power Apps. Here is the Conversation Reference record snapshot for your reference:

Deliver the Food Order

Let’s change the status of the Food Order to “Delivered”.

Food Order entity record

Power Automate to Notify about the Food Delivery

Develop a simple Power Automate that triggers when the Status of the Food Order record is set to Delivered. This PA will also retrieve the Conversation Reference record associated with the Customer who placed the food order and call the Companion Bot by passing the Conversation Reference.

But wait a minute, how are we supposed to call the Companion Bot? Let’s see that in the following section.

Calling the Companion Bot

Develop a new Controller within the Companion Bot that takes the Conversation Reference details from the Power Automate and resuscitates the Conversation Reference object – in other words, the Notify Controller recreates the conversation channel that originally the customer used to chat with the bot to create the food order.

//This action is called by the Power Automate
public async Task<IActionResult> PostReview(string activityId, string botId, string conversationId, string serviceUrl, string userId, string channelId, string botName)
var convRef = new ConversationReference();
//Revive the conversation reference
convRef.ActivityId = activityId;
convRef.Bot = new ChannelAccount { Id = botId, Name = botName };
convRef.ChannelId = channelId;
convRef.Conversation = new ConversationAccount { Id = conversationId };
convRef.ServiceUrl = serviceUrl;
convRef.User = new ChannelAccount { Id = userId };
//Send the message to the customer using the Conversation Reference
await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, convRef, BotCalbackPostReview, default(CancellationToken));
// Let the caller know proactive messages have been sent
return new ContentResult()
Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
private async Task BotCalbackPostReview(ITurnContext turnContext, CancellationToken cancellationToken)
var reply = MessageFactory.Text("Would you like to share your experience?");
//Providing a few suggested actions to choreograph the customer's move.
reply.SuggestedActions = new SuggestedActions()
Actions = new List<CardAction>()
new CardAction() { Title = "Review Experience", Type = ActionTypes.ImBack, Value = "I'd like to review my experience" },
new CardAction() { Title = "I'll do it later", Type = ActionTypes.ImBack, Value = "I'll do it later" },
await turnContext.SendActivityAsync(reply, cancellationToken);

Once the Conversation Reference object is created, it is as simple as just sending a message using the standard SendActivityAsync and the customer will receive the message magically.

More details about the Proactive notifications with the Bot Framework is documented here.

I have uploaded the Companion Bot’s full source code to github for your reference. Try it out! We are very familiar with the notifications from the phone apps that we use, but getting a notification from the bot opens a whole new world. Because when the Bot sends a message proactively, you can continue the conversation within the Bot itself – as though your friend knocks your door, you allow him in and continue the conversation.

Continuing the Conversation

Create a topic in the Power Virtual Agents for the customers who would like to share their experience.

This way, when the customer is reached out to proactively, the customer can review the experience with the chatbot in the same conversation.

Let’s see this in action.

In the above gif, I want to emphasize the usage of the Suggested Actions Review Experience and I’ll do it later. This plays an important role because we want to get the user to invoke our Power Virtual Agents’ Review Experience topic that we just created seamlessly in the same conversation.

Hope this makes sense. I understand there are a lot of moving parts involved here and one might get overwhelmed very fast. One day, I hope this is baked in with the Power Virtual Agents itself, but for now if you want to take your customer experience to the next level, there you have it.

11 thoughts on “Building Proactive Bot with Power Virtual Agents

      1. unfortunately that gives me a different conversation ID every time it’s called. I was hoping to retrieve this ID on multiple calls. The same conversation ID as reported when something goes wrong “Sorry, something went wrong. I am not able to help you at the moment, please check back later. Conversation ID: 5CKDZeRsoHj4byKm3e6KB0-1. Time (UTC): 5/18/2020 4:47:20 AM.” – any ideas ?


      2. Sorry for the delayed response, Doug. Yes, that would be the default behavior as the interactions are stateless. You will need to store the conversation id and use the same conversation id to reconstruct the conversation channel to send the message as part of the same conversation. I am not sure if you will have all the necessary moving parts to reconstruct the conversation unfortunately without code.

        Liked by 1 person

  1. Hello @dhina,

    thank you very for your post.

    With PVA only, without bot framework, unfortunately, it seems impossible to send a “proactive message” to a user, since it requires a secret to send requests to directline that can only be obtained via Azure Bot Services (thus requiring a subscription). At least I could not obtain this secret by any means.


  2. Hi @dhina,

    I’m trying to follow your example but I keep getting this error: “The name ‘RunFlow’ does not exist in the current context”. What do I need to add to the using statements for this statement to work? Thanks!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s