Use Case - Integrating a Copilot Chatbot with Nimbus via Direct Line API

In this use case, we describe briefly how to configure Copilot in Copilot Studio for integration with Nimbus. We describe how Nimbus Workflows can interact with the Copilot and respond to customer's messages. The Copilot has can understand the intent of your customer and we see how to implement agent handover. The Copilot also keeps the information of a whole conversation. Referencing to something a customer has written before in the same conversation will be recognized by the Copilot.

Preconditions

 Contact Center Service Licensing is required to make use of Nimbus Features such as the the chat modality.

A Microsoft Copilot Studio License is required to create and deploy the copilot in your organization. Please note that this subscription and related cost are not handled or included within Nimbus. For more information, refer to the official Microsoft Copilot Studio site

 

INC Icon Legend Accordion

Show Icon Legend

💡 = A hint to signal learnings, improvements or useful information in context. 🔍 = Info points out essential notes or related page in context.
☝ = Notifies you about fallacies and tricky parts that help avoid problems. 🤔 = Asks and answers common questions and troubleshooting points.
❌ = Warns you of actions with irreversible / data-destructive consequence. ✅ = Intructs you to perform a certain (prerequired) action to complete a related step.
 
 

Create Your Copilot Bot

🔎This variant of connecting Nimbus with Copilot is based on the bot framework Direct Line 3.0 API described here Key concepts in the Bot Framework Direct Line API 3.0 - Azure AI Bot Service - Bot Service | Microsoft Learn

 
  1. Create your bot in Copilot Studio
  2. Deploy the bot.
  3. Define your topics. You need one escalation topic. It is generally created out of the box, under Topics → System.       
  4. Add a fixed text response to it. We do not need more. Nimbus will receive this text and check if it contains the exact agent handover text string. If so, Nimbus will route the conversation to an agent.       
  5. In the settings of the bot, go to “Security” > “Web channel security”.       
     
  6. Copy one of the secret keys.       
     

Create the Nimbus Workflow

✅ We can reuse the Workflow from the other copilot chatbot described in Luware Nimbus - Use Case - Integrating a Copilot Chatbot with Nimbus. Here is an overview of it:

  1. Initialize AIAnswerGenerated parameter
  2. Check initial message and branch:
    1. if there is an initial message, take it as the AIQuestion
    2. If not ask for input.
  3. Trigger Event for the Power Automate Flow.  
  4. Check and Wait for the answer and display.
  5. Check if the answer from the bot was the intent to speak to an agent. Use a fixed phrase set within the topic in Copilot.
  6. Agent handover and queue handling

Create the Power Automate Flow

Part 1: Prepare the variables

Description Screenshot

Within the Connector Flow Actions start with to the UpdatedParameter Trigger Events on the Nimbus trigger “When a task changes state”. 

 

Within the settings set the trigger condition to the AIQuestion parameter using @equals(triggerOutputs()?['body/UpdatedParameterName'], 'AIQuestion'), as we want to run the flow when a question has been asked by the user.

Then we need to initialize variables to use in the flow. 

💡All variables are defined as string.

  • DirectLineSecret1 holds the copied secret from the Copilot Studio
  • GeneratedAnswerFromBot - empty, will hold the generated answer
  • ConversationToken - holds an existing conversation token from a previous request. Will be set with Nimbus Task Information 
  • ConversationId - holds an existing conversation id from a previous request. Will be set with Nimbus Task Information 
  • LenActivitiesBeforeQuestion - is a helper variable to check for new generated replies
  • LenActivitiesAfterQuestion - is a helper variable to check for new generated replies
  • Activities - is a variable that will hold the bot's responses 

 

💡In the next step we set the variables holding information of a previous/ongoing chat conversation ConversationToken and ConversationId.

To set the ConversationId we filter the array of the Nimbus task;

  • From: @{triggerOutputs()?['body/taskInformation/customContextParameters']}
  • Filter Query: equals(item()?['Name'],'ConversationId')

We then store it into the variable using a Set variable

  • Name: ConversationId
  • Value: first(body('Filter_array'))?['Value']

Set the ConversationToken

 

we filter the array of the Nimbus task

  • From: @{triggerOutputs()?['body/taskInformation/customContextParameters']}
  • Filter Query: equals(item()?['Name'],'ConversationToken')

We store it into the variable using a Set variable

  • Name: ConversationToken
  • Value: first(body('Filter_array-token'))?['Value']

Part 2: Create a new conversation

Now we want to check if there is an existing conversation. 

  • If this conversation starts, we need to open a new one on the Direct Line. 
  • If there is an existing ongoing conversation we do not open anything new. 

💡Note:  in this example we do not handle expired tokens, we should implement it in the true case but omitted it for simplicity.

Overview

Steps

Description Screenshot
We need to check if an old ConversationId is existing. The respective variable is holding the information.

In the FALSE branch we will now request the Copilot Direct Line API to get a new conversation starting.

 

Use a HTTP Element to get a token

  • URI: https://directline.botframework.com/v3/directline/tokens/generate
  • Method: POST
  • Headers:       
    Authorization: Bearer @{variables('DirectLineSecret1'}
Parse the response body using Parse JSON

Now use an HTTP element to start the conversation

  • URI: https://directline.botframework.com/v3/directline/conversations
  • Method: POST
  • Headers:       
    Authorization: Bearer @{variables('DirectLineSecret1'}
Parse the response body using Parse JSON
Store the ConversationID from the response into the variable
Store the ConversationToken from the response into the variable

Part 3: Interact with the AI model and update the Nimbus task

Now that we have a conversation going, we can send the question from the chat to the bot. 

  • We will check how many activities exist and recheck again and again until we discovered a new response from the bot. 
  • We then leave the loop and update the Nimbus task with the reply, the conversation id and the conversation token.

Overview

Steps

Description Screenshot

Use an HTTP Element with the following setting to send the question to the bot

Use another HTTP Element to get all activities of the conversation

 

 

Put the response into the Activities array variable using a Set variable Element  

@{body('GetActivities')?['activities']}

 

Then filter the array to return only activities of type “message”

We want to count the message activities before the question was answered. This is done with another variable.

Name: LenActivitiesBeforeQuestion       
Value: length(body('Filter_array_messages'))

Now, add a Loop until element to the flow and…

  • … loop until       
    less(variables('LenActivitiesBeforeQuestion'), variables('LenActivitiesAfterQuestion'))
  • Count: 60
  • Timeout: PT1H

 

💡"PT1H" means the loop will continue to iterate until the specified condition is fulfilled 

 or the loop runs for a maximum of 1 hour.

Within the loop we do the same actions again: we get the list of activities. Set the array,   filter the array on type “message”  and then set the variable LenActivitiesAfterQuestion to get the final length of the response array.

Finally, we set the GeneratedAnswerFromBot to the text of the last (thus latest) message from the array.

 

 

Use another HTTP Element to get all activities of the conversation

 

Put the response into the Activities array variable using a Set variable Element  

@{body('GetActivitiesAgain')?['activities']}

Filter the array to return only items with type “message”

  • item()?['type'] equals message

Now set the variable

Name: LenActivitiesAfterQuestion        
Value: length(body('Filter_array_Messages2'))

Set the value of the variable “GeneratedAnswerFromBot” to the text of the response

Name: GeneratedAnswerFromBot       
Value: outputs('Compose')?['text']

Finally, we can update the Nimbus Task using the TaskId from the trigger and setting the following Custom Context Parameters:

[
                                                                                                                                            {
                                                                                                                                            "name": "AIAnswerIsGenerated",
                                                                                                                                            "value": "True"
                                                                                                                                            },
                                                                                                                                            {
                                                                                                                                            "name": "AIAnswer",
                                                                                                                                            "value": variables('GeneratedAnswerFromBot')
                                                                                                                                            },
                                                                                                                                            {
                                                                                                                                            "name": "ConversationId",
                                                                                                                                            "value": variables('ConversationId')
                                                                                                                                            },
                                                                                                                                            {
                                                                                                                                            "name": "ConversationToken",
                                                                                                                                            "value": variables('ConversationToken')
                                                                                                                                            }
                                                                                                                                            ]

Table of Contents