Microsoft bot: How to log each conversation step? - node.js

I'm learning how to build a Microsoft Bot and I need to send every message (ie log the user progress through the bot) to an API.
Let's say I have these dialogs with 3 steps each:
/
/welcome
/onboarding
/finish
When a user joins the conversation (Root dialog), I need to make a POST to our API with the following data:
{
"conversationId": "8n21b2mkmdb9abi26",
"dialog": "root",
"step": 1
}
And then, for each following user message, I would update that conversation in our server with the dialog and step.
I tried to use the middleware hook, but it doesn't have the information of which dialog/step the user is currently in.
Any suggestion?

The middleware feature gives you access to the session object. Store the metadata you need in the session object, then access it in your logging middleware.
For a code example, check out: Microsoft/BotBuilder-Samples - Middleware and Logging with BotBuilder Node SDK

Related

Proactive messaging bot in Teams without mentioning the bot beforehand

I'm using the Microsoft bot-framework to create a bot and integrate it into teams.
Part of the bot's requirements include proactively messaging users once per day. From what I understand, I can only message users that has been added to the team/groupChat after the bot, or that have messaged the bot directly.
My question is - can I somehow bypass this limitation?
A friend of my referred me to a new feature of graphAPI, as part of the new beta version - https://learn.microsoft.com/en-us/graph/api/user-add-teamsappinstallation?view=graph-rest-beta&tabs=http.
To me it doesn't seem like it could be related to the solution since I'm not getting any data back in the response, so if I have no conversationReference object I still can't message the user.
At the moment my solution is to simply broadcast a message in the channel when it's added, asking users to "register" with it by messaging it. Anyone has any other suggestion?
The easiest way is to:
Install the bot for the team
Query the Team Roster -- The link in Step 3 has an alternative way to do this towards the bottom
Create a conversation with the user and send a proactive message
There's a lot of code in those links and it's better to just visit them than to copy/paste it here.
The end of Step 3 also mentions trustServiceUrl, which you may find handy if you run into permissions/auth issues when trying to send a proactive message.
Edit for Node:
Install Necessary Packages
npm i -S npm install botbuilder-teams#4.0.0-beta1 botframework-connector
Note: The #<version> is important!
Prepare the Adapter
In index.js
const teams = require('botbuilder-teams');
adapter.use(new teams.TeamsMiddleware());
Get the Roster
// Get Team Roster
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(context.activity.conversation.id);
Send the Proactive Message
const { TeamsContext } = require('botbuilder-teams');
// Send Proactive Message
const teamsCtx = TeamsContext.from(context);
const parameters = {
members: [
roster[0] // Replace with appropriate user
],
channelData: {
tenant: {
id: teamsCtx.tenant.id
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
Trust the ServiceUrl, as Necessary
Read about it. You'd want this before the message is sent.
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
EDIT: The Graph API you've referenced is only necessary if you wish to proactively message a user who is not in a channel/groupChat where the bot is installed. If you need to proactively message only people who are in context where the bot is installed already, the answer from mdrichardson is the easiest possible method.
We've identified a couple of issues with the Graph API beta endpoint you referenced that should be fixed in the near term. In the meantime workarounds are as follows:
Calling:
POST https://graph.microsoft.com/beta/me/teamwork/installedApps/
{"teamsapp#odata.bind":"https://graph.microsoft.com/beta/appcatalogs/teamsapps/APP-GUID"}
Will install an app in the personal scope of a user.
Known issue: Currently, if the app contains a bot, then installation will not lead to creation of thread between the bot and the user. However to ensure that any missing chat threads, get created, call:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Calling:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Gets the chat between a user and an app containing a bot.
Known issue: Calling this API will lead to sending a conversation update event to the bot even though there were no updates to the conversation. Your bot will essentially get two install events and you'll need to make sure you don't send the welcome message twice.
We'll also be adding more detailed documentation for the proactive messaging flow using these Graph APIs

Is there anyway to get the "watermark" value in the bot builder?

I have a webchat for a user connected to the bot through directline.
I want a second user to join to the same conversation, but I want the second user to be able to read the full conversation.
Right now when the second user connects to the conversation it doesn't see anything of the first user conversation because he doesn't join with a watermark value.
I have this code on bot builder v4 right now:
const options = {
method: 'GET',
uri: 'https://myuri/addRow?conversationId='+stepContext.context.activity.conversation.id,
};
await req-promise(options);
I would like to send something like this:
const options = {
method: 'GET',
uri: 'https://myuri/addRow?conversationId='+stepContext.context.activity.conversation.id+'watermark='+watermark,
};
await req-promise(options);
Is there anyway to get that watermark value?
Thanks
Per this GitHub issue.
The cache of messages in the Direct Line connector service is intended to be used as a connection reliability mechanism, not as an actual message history store.
If you require more granular control over conversation history, you will need implement an a transcript store server side. And, you can use the SendConversationHistoryAsync api to send chunks of history messages to the conversation.
We do not currently have a complete example demonstrating this, but it is in the works.
I would recommend using a transcript logger to store and manage your own conversation history instead of trying to pull the messages from the cache. Also, if you try to use the watermark, you'll run into permission issues since one conversation doesn't have the ability to see another conversation's data.
Hope this helps!

Microsoft / Botbuilder for NodeJS: Bind URL Parameters to bot session

SDK
Homepage: https://github.com/Microsoft/BotBuilder
SDK Platform: Node.js
SDK Version: 3.14.0
Issue Description
Hi, I searched for this for a long time now but I haven't found an answer.
I was wondering if there is a way to bind some URL parameters to the User's Bot Session.
For example, if for a specific chat dialog, I set my Endpoint URL to:
http://localhost:3978/api/messages?pronuntiation=british
is there a way to get that url parameter named "pronuntiation" down in the session object like...
bot.dialog("/", function(session){
var desiredPronuntiation = session.someUrlParameters.pronuntiation;
if( desiredPronuntiation == "british"){
///blah
}
});
I think it is possible in C# SDK but I was trying to do this in NodeJS...
I already debugged the proces from the server.post('/api/messages', connector.listen()) down to the ChatConnector.verifyBotFramework() where at the end I found it calls _this.dispatch(req.body, res, next); (ChatbotConnector.js on line 149) passing only the post body but not the request object itself...
So at a first glance I think this is not possible, I just wanted to be sure that I didn't miss anything...
Thanks,
Luis
As far as I know, this isn't supported by the Bot Framework, however I don't see why you need to do it this way. This is something you want to store in the state, for example the userData. You can read more here about managing state in the Bot Framework.
If you want to pass user data to the bot, it depends on the channel. For example Facebook and Webchat allow you to pass data direct to the bot, without user input.

How to detect when bot was added to conversation and other events?

I am testing a bot that I am building using the Bot Framework. The emulator for local testing that Microsoft created has several events that can be provided to the bot to solicit a response.
I looked at the GitHub samples provided for Node.js here, but I can not find any example that responds to the different events within the Bot Framework Emulator.
The states are:
Bot Added to Conversation
Bot Removed from Conversation
User Added to Conversation
User Removed from Conversation
End of Conversation
Ping
Delete User Data
The API also does not make it clear how to achieve any of these actions.
Does anyone have any insight on where I should be looking for a example, or the API entries that I should be using?
In response to one of the answers, I did try code -
.onDefault(function (session) { console.log(session.message.type); }
But it only ever display "message" if a message was sent by the user.
The incoming message.type field will have "BotAddedToConversation" etc.
For the Node SDK, the botConnectorBot is able to trigger custom listeners on events using the on() handler.
Example
var builder = require('botbuilder');
var bot = new builder.BotConnectorBot({ appId: 'APPID', appSecret: 'APPSECRET' });
bot.on('DeleteUserData', function(message) {
// Handle Deleting User Data
});
More information can be found here.
You are also able to configure some standard messages using the configure() method.
Example
bot.configure({
userWelcomeMessage: "Hello... Welcome to the group.",
goodbyeMessage: "Goodbye..."
});
More information on what can be configured through options is located here.
Concerns
This is not part of the question, as the question was to identify how to listen to these events. But as a general concern, the event listener does not return a session object. It is unclear how to act once you handle the event.

Slack API, get current location

Is there any method to get current user location. Let say I created some "slash" command /map. When I am calling this command - POST message being send to my nodejs server, and server returns some json data.
{
"channel": "#map",
"username": "test",
"unfurl_links": true,
"icon_emoji": ":world_map:",
"attachments": [
{
"fallback": "Required plain-text summary of the attachment.",
"pretext": "Beautiful Personalized Map Sharing",
"image_url": "http://static.mapjam.com/yrjkbmb/auto/640x480.jpg",
"thumb_url": "http://static.mapjam.com/yrjkbmb/auto/640x480.jpg"
}
]
}
Because I am authenticated I am able to get some Slack user info:
username
email etc..
How can I access Slack user lat, long if it is possible though
Currently there is nothing available in the user info to get the geographical position of a user from the Slack API.
Please refer to the Users Info Slack API documentation and the User Type documentation.
If you are expecting to create a slash command the slack application would have to have permissions to your devices location. Looking at the permissions on my android app id does not request permissions to the devices location.
Just spit-balling, there could be a way to do it. This is completely hypothetical simplified method. You would have to have a helper application on the device that has permissions to the location of the device. That app would listen for the /location /map request then post to the channel where the request came from.

Resources