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:
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:
- PVA Dataverse Tables
- Update Field/Key for Trigger phrases
- 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 |
2. Update Field/Key for Trigger phrases
So our steps after approval are:
- Get Row
- Update Content
- Update Row
Not too difficult
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]
)
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.
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
- 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.
- Hopefully someone smarter then me can figure it out and get it working
- Its Ok to fail, as the learning is journey is just as valuable as an end solution
- Dataverse for Teams is terrible 😎
Further Reading
Top comments (5)
I like the way you work, you propose an application to learn the tech behind. It's a marvelloues way to understand how things works and the limits and boundaries of it.
Apart from this, did you try to reach the community to see if there is any possibility to solve the issues you found? DM me and I can give you some links.
Thank you for kind words, to be honest was more a learning experience then a needed solution, though would be cool to find out how to fix it
I like your idea. That's a good one.
Can you pull the chatbot into a solution... or is that not possible in a Teams dataverse environment? Might unlock a mystery or two if you can gather up all the tables and entities into one container.
Yep you can pull it into a solution, it normally adds an abstract layer (e.g shows as Topic instead of Dataverse row). But it is definitely worth investigating as adding to the solution pulls in the right components, so might help explain how it identifies those components. Thank you for the inspiration
Right back atcha