Dynamically Updating Power Virtual Agents
Tags: powerautomate, powervirtualagents, chatbo, lowcode
Published: 2023-10-23 06:22:25

This blog did not go to plan, I hate Teams Dataverse, it's a bad idea and badly implemented, but lets start at the beginning...

So I had this idea, wouldn't it be cool if I could dynamically update the trigger phrases in my chatbot, it would go something like this:

![bot flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iw5ok2k0rk69h08mrpkd.png)

As everything is built in Dataverse my thought was I just need to update the topic row in the relevant table. I had the following challenges/learning opportunities:

1. PVA Dataverse Tables
2. Update Field/Key for Trigger phrases
3. Find Topic

_Quick call out, in case you haven't guessed this in Teams Dataverse, not full PVA, the licence costs are just too much for the full version for internal bots._

---

## 1. PVA Dataverse Tables
So after digging I found:

- Chatbot - All bots
- BotContent - No idea, it was always empty 🤷‍♂️
- Chatbot Subcomponents - Topics & Entity
- Entity - Default Entities
- Conversationtran Script - Chat transcripts

So our 2 key tables are Chatbot and Chatbot subcomponets. Looking at the schema there are some fields that leap out as important:

**Chatbot Table**

| Field                      | Description             |
|----------------------------|-------------------------|
| botid                      | GUID for bot            |
| name                       | Bot name                |
| solutionid                 | GUID for solution       |
| statecode                  | Active(0)/Inactive(1)   |
| bot_conversationtranscript | GUID for bot transcript |

**Chatbot Subcomponents Table**

| Field              | Description            |
|--------------------|------------------------|
| botcomponentid     | GUID for bot component |
| name               | Topic/Entity name      |
| solutionid         | GUID for solution      |
| statecode          | Active(0)/Inactive(1)  |
| _parentbotid_value | GUID for bot           |
| content            | JSON definition        |


![table relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udyirm74vf1j3p5f3q0b.png)

## 2. Update Field/Key for Trigger phrases
So our steps after approval are:

- Get Row
- Update Content
- Update Row

Not too difficult

![flow update dataverse](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7kqhrxpv92y3s0bisa2.png)

For now we are just getting the topic we want and then adding a new trigger phrase.

The List rows subcomponents returns the below in the content:

```
{
  "intents": [
    {
      "triggerQueries": [
        "pay slip",
        "wage slip",
        "wage query",
        "wage",
        "pay",
        "pay slip",
        "pay query",
        "pay issues"
      ],
      "dialogId": "new_topic_789932f9a00999999999",
      "isTriggeringEnabled": true,
      "id": "new_topic_789932f9a0099999999993",
      "displayName": "Pay",
      "createdTime": "2022-07-26T10:17:16.4022364Z",
      "updatedTime": "2022-07-26T12:38:17.765303Z",
      "createdUserId": "999999999-feab-4bff-bc87-999999999",
      "updatedUserId": "999999999-feab-4bff-bc87-999999999"
    }
  ],
  "dialogs": [
    {
      "rootNodeId": "999999999-e047-418b-9735-999999999",
      "messageNodes": [
        {
          "botMessageId": "999999999-ee98-4bfe-9cfb-999999999",
          "nodeType": "BotMessageNode",
          "id": "999999999-e047-418b-9735-999999999",
          "defaultTargetNodeId": "999999999-3819-4a1e-a091-999999999"
        }
      ],
      "dialogChangeNodes": [
        {
          "targetDialogId": "new_topic_2dedddf95d7c4999999999991_aeabea4d071f419999999995424_assumedsuccess",
          "nodeType": "DialogChangeNode",
          "id": "999999999-3819-4a1e-a091-999999999"
        }
      ],
      "id": "new_topic_789932f9a009406999999999",
      "displayName": "Untitled",
      "createdTime": "2022-07-26T10:17:16.4022364Z",
      "updatedTime": "2022-07-26T12:38:17.765303Z",
      "createdUserId": "999999999-feab-4bff-bc87-999999999",
      "updatedUserId": "999999999-feab-4bff-bc87-999999999"
    }
  ],
  "botMessages": [
    {
      "channelContent": {
        "web": {
          "contentFormat": "Markdown",
          "content": "This is a test"
        }
      },
      "id": "999999999-ee98-4bfe-9cfb-999999999",
      "createdTime": "2022-07-26T10:14:26.556Z",
      "updatedTime": "2022-07-26T10:14:26.556Z"
    }
  ]
}
```

We want to add an item in this array:

```
"triggerQueries": [
        "pay slip",
        "wage slip",
        "wage query",
        "wage",
        "pay",
        "pay slip",
        "pay query",
        "pay issues"
      ],
```

But as its a string we just need to do a fancy split concat expressions:

First we split into an array at the top of the triggerQueries array:
```
split(
	outputs('List_rows_subcomponents')?['body/value'][0]?['content']
,
	'"triggerQueries": ['
)
```

Then we concat together with the first item, the split string and open speech marks, new phrase, close speech marks and comma, second item in the array:
```
concat(
    outputs('split_json')[0]
,
    '"triggerQueries": ["'
,
    triggerBody()['text']
,
	'",'
,
	outputs('split_json')[1]
)
```

![update a row](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mukbyb8yd5e5t3bzpx3e.png)

## 3. Find Topic
Cool so we can update our Topic, all we need to do now is find the right Topic (as every bot can have and often does have same named Topics).

This is where the `_parentbotid_value` key comes in as it will be the bots id, so we can have the bot as an environment variable, and filter the subcomponents `_parentbotid_value` by that id. Simple right, well no becuase the `_parentbotid_value` is null.

![subcomponent response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8j8ihu98s6ki07bq82y5.png)

It clearly shouldnt be because it needs the relationship for the Chatbot to work, and the documentation shows that. So whats the issue, well at a guess I don't have access somewhere, and this is where the really annoying part of Dataverse for Teams shows its head. I have full global power platform access and admin to the Team/Environemnt, but I can't use the Dataverse API to query it. I cant set security roles for tables, I can't do anything. 

As a whole this gaping hole in seeing what is going on in the Teams Dataverse environments is so frustrating, and definitely not enterprise friendly.

---

So what's the point of this article, well 

1. Hopefully some learnings from how everything in Power Platform is now built in Dataverse, and you can do some cool stuff editing the Tables directly. 
2. Hopefully someone smarter then me can figure it out and get it working
3. Its Ok to fail, as the learning is journey is just as valuable as an end solution
4. Dataverse for Teams is terrible 😎

---
**Further Reading**

- [MS Learn-entities/bot](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/reference/entities/bot)
- [MS Learn-entities/parentBotId](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/reference/entities/botcomponent#BKMK_ParentBotId)
- [MS Learn-entities/botsubcomponent](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/reference/entities/botcomponent)
- [MS Learn-entities/converstionscript](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/reference/entities/conversationtranscript)