Skip to content

Commit 08fa258

Browse files
committed
Updated LKG build, unit tests, and package.json version.
1 parent 43f8166 commit 08fa258

15 files changed

+306
-48
lines changed

Node/examples/basics-validatedPrompt/app.js

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var bot = new builder.TextBot();
1515
bot.add('/', [
1616
function (session) {
1717
// call custom prompt
18-
session.beginDialog('/meaningOfLifePrompt', { maxRetries: 3 });
18+
session.beginDialog('/meaningOfLife', { prompt: "What's the meaning of life?" });
1919
},
2020
function (session, results) {
2121
// Check their answer
@@ -25,34 +25,10 @@ bot.add('/', [
2525
session.send("Sorry you couldn't figure it out. Everyone knows that the meaning of life is 42.");
2626
}
2727
}
28-
2928
]);
3029

31-
bot.add('/meaningOfLifePrompt', function (session, results) {
32-
results = results || {};
33-
34-
// Validate response
35-
var valid = false;
36-
if (results.response) {
37-
valid = (results.response == '42');
38-
}
39-
40-
// Return results or prompt the user
41-
if (valid || (results.resumed == builder.ResumeReason.canceled)) {
42-
// The user either answered the question correctly or they canceled by saying "nevermind"
43-
session.endDialog(results);
44-
} else if (!session.dialogData.hasOwnProperty('maxRetries')) {
45-
// First call to the pormpt so process args passed to the prompt
46-
session.dialogData.maxRetries = results.maxRetries || 2;
47-
builder.Prompts.text(session, "What's the meaning of life?");
48-
} else if (session.dialogData.maxRetries > 0) {
49-
// User guessed wrong but they have retries left
50-
session.dialogData.maxRetries--;
51-
builder.Prompts.text(session, "Sorry that's not it. Guess again. What's the meaning of life?");
52-
} else {
53-
// User to failed to guess in alloted number of tries
54-
session.endDialog({ resumed: builder.ResumeReason.notCompleted });
55-
}
56-
});
30+
bot.add('/meaningOfLife', builder.DialogAction.validatedPrompt(builder.PromptType.text, function (response) {
31+
return response === '42';
32+
}));
5733

5834
bot.listenStdin();

Node/lib/Message.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
var session = require('./Session');
2+
var Message = (function () {
3+
function Message() {
4+
}
5+
Message.prototype.setLanguage = function (language) {
6+
var m = this;
7+
m.language = language;
8+
return this;
9+
};
10+
Message.prototype.setText = function (ses, msg) {
11+
var args = [];
12+
for (var _i = 2; _i < arguments.length; _i++) {
13+
args[_i - 2] = arguments[_i];
14+
}
15+
var m = this;
16+
args.unshift(msg);
17+
m.text = session.Session.prototype.gettext.apply(ses, args);
18+
return this;
19+
};
20+
Message.prototype.setNText = function (ses, msg, msg_plural, count) {
21+
var m = this;
22+
m.text = ses.ngettext(msg, msg_plural, count);
23+
return this;
24+
};
25+
Message.prototype.addAttachment = function (attachment) {
26+
var m = this;
27+
if (!m.attachments) {
28+
m.attachments = [];
29+
}
30+
m.attachments.push(attachment);
31+
return this;
32+
};
33+
Message.prototype.setChannelData = function (data) {
34+
var m = this;
35+
m.channelData = data;
36+
return this;
37+
};
38+
return Message;
39+
})();
40+
exports.Message = Message;

Node/lib/Session.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ var Session = (function (_super) {
1313
this.args = args;
1414
this.msgSent = false;
1515
this._isReset = false;
16+
this.lastSendTime = new Date().getTime();
17+
this.sendQueue = [];
1618
this.dialogs = args.dialogs;
19+
if (typeof this.args.minSendDelay !== 'number') {
20+
this.args.minSendDelay = 1000;
21+
}
1722
}
1823
Session.prototype.dispatch = function (sessionState, message) {
1924
var _this = this;
@@ -75,9 +80,8 @@ var Session = (function (_super) {
7580
if (ss.callstack.length > 0) {
7681
ss.callstack[ss.callstack.length - 1].state = this.dialogData || {};
7782
}
78-
this.msgSent = true;
7983
var message = typeof msg == 'string' ? this.createMessage(msg, args) : msg;
80-
this.emit('send', message);
84+
this.delayedEmit('send', message);
8185
return this;
8286
};
8387
Session.prototype.getMessageReceived = function () {
@@ -95,6 +99,9 @@ var Session = (function (_super) {
9599
throw new Error('Dialog[' + id + '] not found.');
96100
}
97101
var ss = this.sessionState;
102+
if (ss.callstack.length > 0) {
103+
ss.callstack[ss.callstack.length - 1].state = this.dialogData || {};
104+
}
98105
var cur = { id: id, state: {} };
99106
ss.callstack.push(cur);
100107
this.dialogData = cur.state;
@@ -153,7 +160,7 @@ var Session = (function (_super) {
153160
this.emit('error', r.error);
154161
}
155162
else {
156-
this.emit('quit');
163+
this.delayedEmit('quit');
157164
}
158165
}
159166
return this;
@@ -221,6 +228,34 @@ var Session = (function (_super) {
221228
}
222229
return true;
223230
};
231+
Session.prototype.delayedEmit = function (event, message) {
232+
var _this = this;
233+
var now = new Date().getTime();
234+
var delaySend = function () {
235+
setTimeout(function () {
236+
var entry = _this.sendQueue.shift();
237+
_this.lastSendTime = now = new Date().getTime();
238+
_this.emit(entry.event, entry.msg);
239+
if (_this.sendQueue.length > 0) {
240+
delaySend();
241+
}
242+
}, _this.args.minSendDelay - (now - _this.lastSendTime));
243+
};
244+
if (this.sendQueue.length == 0) {
245+
this.msgSent = true;
246+
if ((now - this.lastSendTime) >= this.args.minSendDelay) {
247+
this.lastSendTime = now;
248+
this.emit(event, message);
249+
}
250+
else {
251+
this.sendQueue.push({ event: event, msg: message });
252+
delaySend();
253+
}
254+
}
255+
else {
256+
this.sendQueue.push({ event: event, msg: message });
257+
}
258+
};
224259
return Session;
225260
})(events.EventEmitter);
226261
exports.Session = Session;

Node/lib/botbuilder.d.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,9 @@ export interface ISessionArgs {
416416

417417
/** Optional localizer to use when localizing the bots responses. */
418418
localizer?: ILocalizer;
419+
420+
/** Optional minimum delay between messages sent to the user from the bot. */
421+
minSendDelay?: number;
419422
}
420423

421424
/** Signature of error events fired from a session. */
@@ -484,6 +487,9 @@ export interface IBotConnectorOptions {
484487

485488
/** Optional localizer used to localize the bots responses to the user. */
486489
localizer?: ILocalizer;
490+
491+
/** Optional minimum delay between messages sent to the user from the bot. Default value is 1000. */
492+
minSendDelay?: number;
487493

488494
/** Dialog to launch when a user initiates a new conversation with a bot. Default value is '/'. */
489495
defaultDialogId?: string;
@@ -514,6 +520,9 @@ export interface ISkypeBotOptions {
514520

515521
/** Optional localizer used to localize the bots responses to the user. */
516522
localizer?: ILocalizer;
523+
524+
/** Optional minimum delay between messages sent to the user from the bot. Default value is 1000. */
525+
minSendDelay?: number;
517526

518527
/** Dialog to launch when a user initiates a new conversation with a bot. Default value is '/'. */
519528
defaultDialogId?: string;
@@ -544,6 +553,9 @@ export interface ISlackBotOptions {
544553

545554
/** Optional localizer used to localize the bots responses to the user. */
546555
localizer?: ILocalizer;
556+
557+
/** Optional minimum delay between messages sent to the user from the bot. Default value is 1500. */
558+
minSendDelay?: number;
547559

548560
/** Dialog to launch when a user initiates a new conversation with a bot. Default value is '/'. */
549561
defaultDialogId?: string;
@@ -553,6 +565,9 @@ export interface ISlackBotOptions {
553565

554566
/** Maximum time (in milliseconds) that a bot continues to recieve ambient messages after its been @mentioned. Default 5 minutes. */
555567
ambientMentionDuration?: number;
568+
569+
/** Optional flag that if true will cause a 'typing' message to be sent when the bot recieves a message. */
570+
sendIsType?: boolean;
556571
}
557572

558573
/** Address info passed to SlackBot.beginDialog() calls. Specifies the address of the user or channel to start a conversation with. */
@@ -583,6 +598,9 @@ export interface ITextBotOptions {
583598

584599
/** Optional localizer used to localize the bots responses to the user. */
585600
localizer?: ILocalizer;
601+
602+
/** Optional minimum delay between messages sent to the user from the bot. Default value is 1000. */
603+
minSendDelay?: number;
586604

587605
/** Dialog to launch when a user initiates a new conversation with a bot. Default value is '/'. */
588606
defaultDialogId?: string;
@@ -852,6 +870,47 @@ export class Session {
852870
public createMessage(text: string, args?: any[]): IMessage;
853871
}
854872

873+
/**
874+
* Message builder class that simplifies building reply messages with attachments.
875+
*/
876+
export class Message implements IMessage {
877+
/**
878+
* Sets the messages language.
879+
* @param language The language of the message.
880+
*/
881+
setLanguage(language: string): Message;
882+
883+
/**
884+
* Sets the localized text of the message.
885+
* @param session Session object used to localize the message text.
886+
* @param text Text or template string for the reply. This will be localized using session.gettext().
887+
* @param args Optional arguments used to format the message text when Text is a template.
888+
*/
889+
setText(session: Session, text: string, ...args: any[]): Message;
890+
891+
/**
892+
* Loads the plural form of a localized string for the messages language. The output string will be formatted to
893+
* include the count by replacing %d in the string with the count.
894+
* @param session Session object used to localize the message text.
895+
* @param msg Singular form of the string to use as a key in the localized string table. Use %d to specify where the count should go.
896+
* @param msg_plural Plural form of the string to use as a key in the localized string table. Use %d to specify where the count should go.
897+
* @param count Count to use when determining whether the singular or plural form of the string should be used.
898+
*/
899+
setNText(session: Session, msg: string, msg_plural: string, count: number): Message;
900+
901+
/**
902+
* Adds an attachment to the message.
903+
* @param attachment The attachment to add.
904+
*/
905+
addAttachment(attachment: IAttachment): Message;
906+
907+
/**
908+
* Sets the channelData for the message.
909+
* @param data The channel data to assign.
910+
*/
911+
setChannelData(data: any): Message;
912+
}
913+
855914
/**
856915
* Base class for all dialogs. Dialogs are the core component of the BotBuilder
857916
* framework. Bots use Dialogs to manage arbitrarily complex conversations with
@@ -988,6 +1047,31 @@ export class DialogAction {
9881047
* @param steps Steps of a waterfall.
9891048
*/
9901049
static waterfall(steps: IDialogWaterfallStep[]): (session: Session, args: any) => void;
1050+
1051+
/**
1052+
* Returns a closer that wraps a built-in prompt with validation logic. The closure should be used
1053+
* to define a new dialog for the prompt using bot.add('/myPrompt', builder.DialogAction.)
1054+
* @example
1055+
* <pre><code>
1056+
* var bot = new builder.BotConnectorBot();
1057+
* bot.add('/', [
1058+
* function (session) {
1059+
* session.beginDialog('/meaningOfLife', { prompt: "What's the meaning of life?" });
1060+
* },
1061+
* function (session, results) {
1062+
* if (results.response) {
1063+
* session.send("That's correct! The meaning of life is 42.");
1064+
* } else {
1065+
* session.send("Sorry you couldn't figure it out. Everyone knows that the meaning of life is 42.");
1066+
* }
1067+
* }
1068+
* ]);
1069+
* bot.add('/meaningOfLife'. builder.DialogAction.validatedPrompt(builder.PromptType.text, function (response) {
1070+
* return response === '42';
1071+
* }));
1072+
* </code></pre>
1073+
*/
1074+
static validatedPrompt(promptType: PromptType, validator: (response: any) => boolean): (session: Session, args: any) => void;
9911075
}
9921076

9931077
/**
@@ -1635,6 +1719,7 @@ export class SlackBot extends DialogCollection {
16351719
* - reply: A reply to an existing message was sent. [IBotMessageEvent]
16361720
* - send: A new message was sent to start a new conversation. [IBotMessageEvent]
16371721
* - quit: The bot has elected to ended the current conversation. [IBotMessageEvent]
1722+
* - typing: The bot is sending a 'typing' message to indicate its busy. [IBotMessageEvent]
16381723
* - message_received: The bot received a message. [IBotMessageEvent]
16391724
* - bot_channel_join: The bot has joined a channel. [IBotMessageEvent]
16401725
* - user_channel_join: A user has joined a channel. [IBotMessageEvent]
@@ -1692,6 +1777,11 @@ export class SlackSession extends Session {
16921777
/** Data that's persisted on a per channel basis. */
16931778
channelData: any;
16941779

1780+
/**
1781+
* Causes the bot to send a 'typing' message indicating its busy.
1782+
*/
1783+
isTyping(): void;
1784+
16951785
/**
16961786
* Escapes &, <, and > characters in a text string. These characters are reserved in Slack for
16971787
* control codes so should always be escaped when returning user generated text.

Node/lib/botbuilder.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var session = require('./Session');
2+
var message = require('./Message');
23
var dialog = require('./dialogs/Dialog');
34
var actions = require('./dialogs/DialogAction');
45
var collection = require('./dialogs/DialogCollection');
@@ -13,6 +14,7 @@ var skype = require('./bots/SkypeBot');
1314
var slack = require('./bots/SlackBot');
1415
var text = require('./bots/TextBot');
1516
exports.Session = session.Session;
17+
exports.Message = message.Message;
1618
exports.Dialog = dialog.Dialog;
1719
exports.ResumeReason = dialog.ResumeReason;
1820
exports.DialogAction = actions.DialogAction;

Node/lib/bots/BotConnectorBot.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ var BotConnectorBot = (function (_super) {
1616
endpoint: process.env['endpoint'] || 'https://api.botframework.com',
1717
appId: process.env['appId'] || '',
1818
appSecret: process.env['appSecret'] || '',
19-
defaultDialogId: '/'
19+
defaultDialogId: '/',
20+
minSendDelay: 1000
2021
};
2122
this.configure(options);
2223
}
@@ -130,6 +131,7 @@ var BotConnectorBot = (function (_super) {
130131
if (message.type == 'Message') {
131132
var ses = new BotConnectorSession({
132133
localizer: this.options.localizer,
134+
minSendDelay: this.options.minSendDelay,
133135
dialogs: this,
134136
dialogId: dialogId,
135137
dialogArgs: dialogArgs

Node/lib/bots/SkypeBot.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ var SkypeBot = (function (_super) {
1414
this.botService = botService;
1515
this.options = {
1616
maxSessionAge: 14400000,
17-
defaultDialogId: '/'
17+
defaultDialogId: '/',
18+
minSendDelay: 1000
1819
};
1920
this.configure(options);
2021
var events = 'message|personalMessage|groupMessage|attachment|threadBotAdded|threadAddMember|threadBotRemoved|threadRemoveMember|contactAdded|threadTopicUpdated|threadHistoryDisclosedUpdate'.split('|');
@@ -86,6 +87,7 @@ var SkypeBot = (function (_super) {
8687
};
8788
var ses = new SkypeSession({
8889
localizer: this.options.localizer,
90+
minSendDelay: this.options.minSendDelay,
8991
dialogs: this,
9092
dialogId: dialogId,
9193
dialogArgs: dialogArgs

0 commit comments

Comments
 (0)