Use a Microsoft Bot Framework bot with Power Virtual Agents

This article covers how to use the Microsoft Bot Framework dispatcher tool to integrate an existing bot with a Power Virtual Agents bot. It's intended for experienced IT professionals, such as IT admins or developers who have a solid understanding of developer tools, utilities, and integrated development environments (IDEs).


Code samples and dependencies

Code snippets used in this document are available in these articles:

Retrieve topics and utterances from your Power Virtual Agents environment

You'll need to retrieve your Power Virtual Agents bot's content (topics and utterances), your tenant's endpoint, and the direct line secret.

Retrieve bot ID and tenant ID from your bot

  1. In Microsoft Edge, select F12 to open DevTools. (Note: For other browsers, use comparable commands and functionality.)

  2. Sign in to your Power Virtual Agents environment using your Azure Active Directory (Azure AD) credentials.

  3. Go to the Network tab.

    DevTools in Microsoft Edge browser showing the Network tab.

  4. Filter and look for client requests.

  5. Copy the following details.

  6. Store the above information in a file. You will need it later.

Retrieve topics and utterances from your bot

  1. Export BotContent and Annotations from Microsoft Dataverse. Review how to export data.

  2. Download the zip file and unzip it to find two CSV files: annotations.csv and msdynce_botcontents.csv

Convert the exported content to .LU format

  1. Convert your bot content into .lu format using our ContentConverter utility.


    You'll need to download, extract, and have dotnet core runtime to compile and run this utility.

  2. Use the following command to compile and run this code sample.

    dotnet run -p ContentConverter.csproj -c Release -- -i <path to msdynce_botcontents.csv> -c <path to annotations.csv> -b <your bot id>
  3. Convert the file to LUIS JSON file format.

    ludown parse ToLuis --in

Train the dispatcher custom model with your Power Virtual Agents topics

Train and recreate the dispatcher app and add your exported topics and utterances with your existing Cognitive Service intents (for example, LUIS and/or QnA maker) using the dispatch tool. For more information, follow the guidance in the dispatch tool tutorial.

  1. Install the dispatch tool using the NuGet package manager.

    CMD> npm install -g botdispatch
  2. Add topics and utterances that you exported earlier using the Dispatch tool.

    CMD> dispatch add -type file -name l_dynamicsbot -f luis.json
    Enter required fields below.
    What name would you like for your dispatch:
    What's your LUIS authoring key (from
    <enter authoring key from URL above>
    What's your LUIS authoring region [westus, westeurope, australiaeast]:
    <pick your region: eg. westus>
    File: added to l_dynamicsbot.dispatch
  3. Generate a dispatch model that contains exported topics and utterances.


    You'll need to re-train your dispatch model when more topics are added.

    CMD> dispatch create
    Exporting services for dispatch...
    Creating dispatch LUIS model json...
    Creating training data...
    Updating l_dynamicsbot model...
    Importing l_dynamicsbot model...
    Setting up intents to child services mapping for l_dynamicsbot...
    Add subscription key and publish child LUIS apps...
    Training l_dynamicsbot model...
    Publishing l_dynamicsbot model...
    Writing summary file ('test_prediction')...
      "authoringRegion": "westus",
      "hierarchical": true,
      "useAllTrainingData": false,
      "dontReviseUtterance": false,
      "copyLuisData": true,
      "services": [
          "path": "luis.json",
          "type": "file",
          "name": "l_dynamicsbot"
      "serviceIds": [
      "appId": "<REDACTED>",
      "authoringKey": "<REDACTED>",
      "version": "Dispatch",
      "region": "westus",
      "type": "dispatch",
      "name": "l_dynamicsbot"
    Please review your dispatch model in ..\Summary.html

Register and trigger your new dispatch endpoint in code

The following steps require you to add code that registers your new dispatch endpoint and trigger it whenever a user's utterance matches intent. We are using the sample provided by the Microsoft Bot Framework.

  1. Update appsettings.json in your dispatcher app to include the new endpoint for your Power Virtual Agents bot.

      "DynamicsBotId": "<Bot Id>",
      "DynamicsBotTenantId": "<Tenant Id>",
      "DynamicsBotName": "<Bot Name>",
      "DynamicsBotTokenEndpoint": "",
  2. Add a new DynamicsBot class to your project.

    public class DynamicsBotService
      private readonly HttpClient _httpClient;
      public DynamicsBotService(DynamicsBotEndpoint endpoint, string botName)
        Endpoint = endpoint;
        BotName = botName;
        ChannelData = new DynamicsBotChannelData(endpoint.BotId, endpoint.TenantId);
        _httpClient = new HttpClient();
      public string BotName { get; }
      public DynamicsBotChannelData ChannelData { get; }
      public DynamicsBotEndpoint Endpoint { get; }
      public async Task<string> GetTokenAsync()
        var httpRequest = new HttpRequestMessage();
        httpRequest.Method = new HttpMethod("GET");
        httpRequest.RequestUri = Endpoint.TokenUrl;
        var response = await _httpClient.SendAsync(httpRequest);
        var responseStr = await response.Content.ReadAsStringAsync();
        return SafeJsonConvert.DeserializeObject<DirectLineToken>(responseStr).token;
    public class DynamicsBotChannelData
      public DynamicsBotChannelData(string botId, string tenantId)
          DynamicsBotId = botId;
          DynamicsTenantId = tenantId;
      // DO NOT CHANGE property name
      public string DynamicsBotId { get; }
      // DO NOT CHANGE property name
      public string DynamicsTenantId { get; }
    public class DynamicsBotEndpoint
      public DynamicsBotEndpoint(string botId, string tenantId, string tokenEndPoint)
        BotId = botId;
        TenantId = tenantId;
        UriBuilder uriBuilder = new UriBuilder(tokenEndPoint);
        uriBuilder.Query = $"botId={BotId}&tenantId={TenantId}";
        TokenUrl = uriBuilder.Uri;
      public string BotId { get; }
      public string TenantId { get; }
      public Uri TokenUrl { get; }
    public class DirectLineToken
      public string token { get; set; }
  3. Add a reference to the Power Virtual Agents bot in the IBotServices.cs file.

    public interface IBotService
      LuisRecognizer Dispatch { get; }
      QnAMaker SampleQnA { get; }
      DynamicsBotService DynamicsBotService { get; }
  4. Update the BotServices constructor to start DynamicsBotService in the BotServices.cs file.

    DynamicsBotService = new DynamicsBotService(new DynamicsBotEndpoint(
  5. Update DispatchBot.cs to add a trigger for the Power Virtual Agents bot on intent match.

    private async Task ProcessDynamicsBotAsync(ITurnContext<Microsoft.Bot.Schema.IMessageActivity> turnContext, CancellationToken     cancellationToken)
        var token = await _botService.DynamicsBotService.GetTokenAsync();
        using (var directLineClient = new DirectLineClient(token))
            var conversation = await directLineClient.Conversations.StartConversationAsync();
            var conversationtId = conversation.ConversationId;
            var response = await directLineClient.Conversations.PostActivityAsync(conversationtId, new Microsoft.Bot.Connector.DirectLine.Activity()
                Type = Microsoft.Bot.Connector.DirectLine.ActivityTypes.Message,
                From = new Microsoft.Bot.Connector.DirectLine.ChannelAccount { Id = "userId", Name = "userName" },
                Text = turnContext.Activity.Text,
                ChannelData = JObject.FromObject(_botService.DynamicsBotService.ChannelData),
                TextFormat = "plain",
                Locale = "en-Us",
            var activities = await GetActivitiesAsync(directLineClient, conversationtId, _botService.DynamicsBotService.BotName);
            var activity = turnContext.Activity as Microsoft.Bot.Schema.Activity;
            await turnContext.SendActivitiesAsync(
                       .Select(message =>
                           var reply = activity.CreateReply(message.Text);
                           reply.Attachments = message?.Attachments?.Select(a => new Microsoft.Bot.Schema.Attachment()
                               Content = a.Content,
                               ContentType = a.ContentType,
                               ContentUrl = a.ContentUrl
                           reply.SuggestedActions = new Microsoft.Bot.Schema.SuggestedActions()
                               Actions = message?.SuggestedActions?.Actions?.Select(a => new Microsoft.Bot.Schema.CardAction()
                                   Title = a.Title,
                                   Value = a.Value,
                                   Type = a.Type,
                                   Image = a.Image
                           return reply;
    private async Task<List<Microsoft.Bot.Connector.DirectLine.Activity>> GetActivitiesAsync(DirectLineClient directLineClient, string conversationtId, string botName)
        ActivitySet response = null;
        List<Microsoft.Bot.Connector.DirectLine.Activity> result = new List<Microsoft.Bot.Connector.DirectLine.Activity>();
        string watermark = null;
            response = await directLineClient.Conversations.GetActivitiesAsync(conversationtId, watermark);
            watermark = response.Watermark;
            result = response?.Activities?.Where(x =>
              x.Type == Microsoft.Bot.Connector.DirectLine.ActivityTypes.Message &&
                string.Equals(x.From.Name, botName, StringComparison.Ordinal)).ToList();
            if (result != null && result.Any())
            { return result; }
        } while (response.Activities.Any());
        return result;
  6. If you want your Power Virtual Agents bot to handle unmatched intents for a single fallback, update the method DispatchToTopIntentAsync.

    case "l_dynamicsbot":
    case "None":
        await ProcessDynamicsBotAsync(turnContext, cancellationToken);

Deploy your bot and test the dispatcher

You're ready to test your dispatcher to ensure seamless interaction between DynamicsBot and your other bots.

  1. Publish your bot to a demo website.

    Deploy our bot.

  2. Build (Ctrl + Shift + B) and run (F5) your dispatcher app.

  3. Open the Bot Emulator where you add the name and endpoint to your bot.

    Dialog to create new bot in the bot emulator.