After a certain period of inactivity from the user, you can have WebChat or BotChat send a back-channel event to the bot, and the bot can respond by asking the user if they are still there. Note, I would recommend using WebChat since BotChat has been depreciated and the implementation in WebChat is slightly cleaner.
WebChat
In WebChat, we are going to create a custom store and middleware to listen for events where the user sends a message and when the bot sends a message - WEB_CHAT/SEND_MESSAGE
and DIRECT_LINE/INCOMING_ACTIVITY
respectively.
When the bot sends a message that isn't asking the user if they are still there, we will create a timeout that executes a callback after a set time frame - in this case, five seconds. The callback will dispatch a back-channel event to notify the bot that the user has been inactivity for more than the allotted time interval and the bot can respond accordingly. We will add a name to the back channel event - 'inactive' - so we can identify it on the bot side.
When the user sends a message, we will clear the timeout that was created when the bot sent a message, so the callback won't be executed since the user responded within the allotted time frame. See the code snippet below for more details.
let interval;
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'WEB_CHAT/SEND_MESSAGE') {
// Message sent by the user
clearTimeout(interval);
} else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' && action.payload.activity.name !== "inactive") {
// Message sent by the bot
clearInterval(interval);
interval = setTimeout(() => {
// Notify bot the user has been inactive
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'inactive',
value: ''
}
});
}, 5000)
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store,
}, document.getElementById('webchat'));
BotChat
We can create the same effect in BotChat - creating a timeout when the bot sends a message and clearing the timeout when the user sends a message; however, we have to create a custom DirectLine Object to see when the user sends a message and subscribe to and filter the activities so we can identify when the bot sent a message. See the code snippet below for more details.
let timeout;
let dl = new BotChat.DirectLine({ secret: <Secret> });
BotChat.App({
botConnection: { ...dl,
postActivity: activity => {
// Listen for when the user sends a message and clear the timeout;
clearTimeout(timeout);
return dl.postActivity(activity);
}
},
user: { id: 'userid' },
bot: { id: 'botid' },
resize: 'detect'
}, document.getElementById("bot"));
// Listen for incoming activities from the bot and create timeout
dl.activity$
.filter(activity => activity.name !== 'inactive')
.filter(activity => activity.from.id !== 'userid')
.subscribe(activity => {
clearTimeout(timeout);
timeout = setTimeout(() => {
// Notify bot the user has been inactive
dl.postActivity({
type: 'Event',
value: '',
from: {
id: 'userid'
},
name: 'inactive'
})
.subscribe()
}, 5000);
})
Bot Code - Node
In the Bot's onTurn
method, we are going to check if any incoming activities are named 'inactive.' If the activity is named inactive, send an activity asking if the user is still there; otherwise, continue with the normal bot dialog. We are also going to name the activity asking the user if they're there 'inactive' so we don't create a new timeout every five seconds while the user doesn't respond. See the code snippet below.
async onTurn(turnContext) {
if(turnContext.activity.type === ActivityTypes.Event) {
if (turnContext.activity.name && turnContext.activity.name === 'inactive') {
await turnContext.sendActivity({
text: 'Are you still there?',
name: 'inactive'
});
}
...
}
...
}
Hope this helps!