How to make Hubot understand chat context? - state-machine

Is there any way to make Hubot understand the context of conversation between messages? Such that he could ask me clarifying questions?
For example:
me: hey, create a branch plz
Hubot: How should I name it?
me: super-duper
Hubot: Branch 'super-duper' created
Should I use some kind of state machine? Any advices on that?

You can use robot's brain to persist state.
robot.respond /hey, create a branch plz/i, (res) ->
res.reply "Ok, lets start"
user = {stage: 1}
name = res.message.user.name.toLowerCase()
robot.brain.set name, user
robot.hear /(\w+)\s(\w+)/i, (msg) ->
name = msg.message.user.name.toLowerCase()
user = robot.brain.get(name) or null
if user != null
answer = msg.match[2]
switch user.stage
when 1
msg.reply "How should I name it?"
when 2
user.name = answer
msg.reply "Are you sure (y/n) ?"
when 3
user.confimation=answer
user.stage += 1
robot.brain.set name, user
if user.stage > 3 #End of process
if /y/i.test(user.confimation)
msg.reply "Branch #{user.name} created."
else
msg.reply "Branch creation aborted"
robot.brain.remove name

You could assign something like a session to it.
We are doing this for logins. When I tell him login it is bound to the calling user. Advantage is you can store this in the brain. Disadvantage is that one user can only have one session. (you could overcome this through letting them specifying a id.)

This can also be done with the Hubot Conversation plugin. This adds a dialog object which you can interact with. The dialog is scripted, not "natural", but it can be used to create chatbot pathways to execute simple workflows.
Your example might work as follows:
var Conversation = require("hubot-conversation");
module.exports = function(robot) {
var switchBoard = new Conversation(robot);
robot.respond(/create a branch/, function(msg) {
var dialog = switchBoard.startDialog(msg);
msg.reply("How should I name it");
dialog.addChoice(/[a-z]+/i, function(msg2) {
msg2.reply("Branch #{msg2.match[1]} created");
});
dialog.addChoice(/bathroom/i, function(msg2) {
msg.reply("Do I really have to?");
dialog.addChoice(/yes/, function(msg3) {
msg3.reply("Fine, Mom!");
});
});
});

Related

How to make a skypebot kick someone?

So if I say for example 'live:1234567_89' I want the bot to kick a certain member.
This is the code by now , it just send a message to group("/kick live:1234567_89"), no kick the member out of the group? how can kick member out of the group by skype Bot?
var activity2 = new Microsoft.Bot.Connector.Activity()
{
Type = ActivityTypes.Message,
Recipient = new ChannelAccount() { Id = conversationGroupId },
From = new ChannelAccount() { Id = botID },
Text = "/kick live:1234567_89"
};
var createMessage = new ConversationParameters()
{
Members = new ChannelAccount[] { new ChannelAccount() { Id = conversationGroupId }
},
Bot = new ChannelAccount() { Id = botID },
};
var conversation2 = await connector.Conversations.CreateConversationAsync(createMessage);
var response2 = await connector.Conversations.SendToConversationAsync(activity2, conversation2.Id);
I tested this and it doesn't appear to be the source of your issue with the BotFramework SDK. I don't know for certain, but it doesn't look to me that bots can perform slash commands in Skype. They either require special permissions (or are blanket restricted) or the commands are only recognized via keyboard entry (i.e., meaning the slash command is typed in first and then is followed by any other values vs. the whole text simply being entered in by the bot).
This doc lists all available commands, including '/kick' which is an admin level command. Regardless, any slash command I attempted to have the bot issue only came thru as text.
There are several resources available at the bottom of the link included above. Perhaps one of them can help shed more light on if, and how, this can be achieved.

Announce a members role ADDED to a specific role in a specific channel

I'd like to have my bot announce in our specific channel called family-talk, which I do have the channel ID of as well but not sure where to put it, but I'd want this to only happen when a role has been added to a member, is my below code correct or wrong? I don't have a lot of good ways of testing this so i'm hoping for some big help here. I also would like to know where the best place would be to place the code. Thank you!
if(!oldMember.roles.has('539208166563643407') && newMember.roles.has('561773668439687179'))
client.channels.get("550197572178935809").send("This member got the special role!");
Your code should work, BUT you have 2 diffrent IDs in the if, so to make this a bit cleaner just do:
const roleID = '539208166563643407';
const channelID = '550197572178935809';
client.on('guildMemberUpdate', (oldMember, newMember) => {
if(!oldMember.roles.has(roleID) && newMember.roles.has(roleID)) {
client.channels.get(channelID).send(newMember.displayName + ' got the special role!');
}
});

dynamic prompt choices in bot-framework v4 (node.js)

I've got a prompt for an SMS bot in which the user can make multiple choices. I'm looking for a pattern for a ChoicePrompt that allows me to do this:
show multiple selections
then after the user selects and answer, re-prompt them to answer again
Remove their previous choice(s) and add an "exit" option to move on
Automatically end the step if they've selected everything.
I'd like to avoid creating a new prompt w/switch cases for each answer tier, as this pattern needs to be implemented in a lot of places...
Example:
bot: User, what do you do to relax?
Exercise
Read a book
Nothing
user: Exercise
bot: Exercise, cool. What else?
Read a book
Nothing else
user: Read a book
bot: OK, you've done everything so we're moving on!
The botframework don't have a ListPrompt that I can see, at least for v4. They do however, have Suggested Actions you can use for this!!! The Botbuilder-Samples repo has a Suggested Action sample that shows a list of three colors:
async onTurn(turnContext) {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
if (turnContext.activity.type === ActivityTypes.Message) {
const text = turnContext.activity.text;
// Create an array with the valid color options.
const validColors = ['Red', 'Blue', 'Yellow'];
// If the `text` is in the Array, a valid color was selected and send agreement.
if (validColors.includes(text)) {
await turnContext.sendActivity(`I agree, ${ text } is the best color.`);
} else {
await turnContext.sendActivity('Please select a color.');
}
// After the bot has responded send the suggested actions.
await this.sendSuggestedActions(turnContext);
} else if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
await this.sendWelcomeMessage(turnContext);
} else {
await turnContext.sendActivity(`[${ turnContext.activity.type } event detected.]`);
}
}
An option would be to programatically create the array (in the example above, it's "const validColors") and if the reply is in the list of colors, recreate the array however you want without the chosen option.

How to add additional dialog in bot framework

How can I have 2 conversations going concurrently? I'm currently using TextBot and LuisDialog to build a bot. I start off by having a conversation with the user to obtain data. Then while doing some processing in a different method, I discover that I need additional information from the user. How can I create a new conversation with the user just to get that additional information? I have some code below that attempts to show what I want to do. Thanks for your suggestions.
File 1: foo.js
var dialog = new builder.LuisDialog(model);
var sonnyBot = new builder.TextBot();
sonnyBot.add('/', dialog);
dialog.on('intent_1', [
function(session, args, next) {
name = builder.Prompts.text(session,"What is your name?");
},
function(session, result) {
session.dialogData.name= results.response;
getFamilyTree(session.dialogData.name);
}
]);
File 2: getFamilyTree.js
function getFamilyTree(name) {
find family tree for name
if (need place of birth) {
begin new dialog
prompt user place of birth
get place of birth from user
end dialog
}
finish getting the family tree
}
i guess you could pass session object and then use that object to start a new dialog .
Edit 1
can't you use some thing like
session.beginDialog('/getFamilyTree',{name:result.response});
and then you can access name like
args.name
inside 'getFamilyTree' dialog
I posted the same question on GitHub and received the answer from Steven Ickman, who is involved in the development of the node.js SDK. The link to the answer is https://github.com/Microsoft/BotBuilder/issues/394#issuecomment-223127365

How do i get user role details from WhoAmIRequest in MS CRM 2011

I am trying to find whether a user has worked on given case before in CRM 2011.
I am trying write unit test to get an user id as follows
var userid = ((WhoAmIResponse)_orgservice.Execute(new WhoAmIRequest())).UserId;
and then trying to get user details as follows:
var systemuser = _service.Retrieve(
"systemuser",
user.Id,
new ColumnSet(true)
);
My user stub as follows:
var id = new Guid("2974f072-e02a-45e8-b060-4811f24283c0");
SystemUser user = new SystemUser
{
FirstName = "FirstName_Test",
LastName = "LastName_Test",
Id = id
};
return user;
When run the test, I see different UserId, not the one I set. I am not sure what is going here. Any help will be appreciated.
Thank you
Did you try FakeXrmEasy for unit testing? No need to stub or mock anything... it's already done for you.
That's specially handy for queries, because they might have many different joins, filters, and so on, which would be hard to replicate using your own mocks from scracth. Example here
For the above example, there is also an implementation of the WhoAmIRequest which will return the user you set in the CallerId property of the context.
Here's an example.

Resources