The CafeX Live Assist SDK provides a means for an automated chat endpoint (a bot) to escalate a conversation such that the visitor can interact with a (human) agent in CafeX Live Assist.
The SDK is designed to be used server-side in a NodeJS environment.
Once a bot has determined that it wants to put the visitor in touch with an agent, the SDK is employed and a call made to request a chat. Subsequent operation involves polling the SDK for data relating to the conversation. Thereafter the bot behaves as a relay between the visitor and the agent.
Basic flow
Create an instance of the CafeX BOT SDK chat object:
// mybot.js
const liveAssist = require('@cafex/liveassist-botsdk-js');
//...
// Provide account id:
const laChat = new liveAssist.Chat(myAccountId);
//...
// Account id must have been set by environment variable
const laChat = new liveAssist.Chat();
See Instance creation
below for more details on SDK instance creation.
Determine agent availability:
// mybot.js
const condition = {
skill: 'xyz_skill'
};
// Check for availability of agents with skill 'xyz_skill'
laChat.getAvailability(condition, (result) => {
if (result.availability) {
ask('Agents are available to help, would you like to chat to one?');
// ...
} else {
send('Sorry, there are no agents available for you to chat to');
}
});
See agent availability options
below for details of condition
. The callback will be made with two arguments. The first is an Error object, which will be null in the case of a successful query. The second is an object with the results; see agent availability result
below for details. Note that if an unknown skill is provided, the Error object will be non-null.
Capturing transcript lines
// mybot.js
const liveAssist = require('@cafex/liveassist-botsdk-js');
//...
let transcript = liveAssist.newTranscript();
//...
liveAssist.addTranscriptLine(transcript, {
timestamp: timestamp,
isBot: isBot,
srcName: isBot ? 'bot': 'visitor',
line: line,
});
The resulting transcript object can be passed as a property of the chat request spec, see Chat request - Options
below. See Transcript capturing
for details of the object passed to addTranscriptLine
.
Instigate a chat with an agent:
// mybot.js
const spec = {
skill: 'xyz_skill',
transcript: transcript,
visitorName: 'MyVisitor',
language: 'es-ES'
};
laChat.requestChat(spec, (err) => {
if (err) {
console.error('Error requesting chat: %s', err.message);
send('Sorry, failed to contact an agent');
} else {
// chat instigated
}
});
See Chat request - Options
below for details of spec
. The callback will be made with an Error object argument, which could be null (in the case of a successful request).
Poll the chat:
// mybot.js
laChat.poll((err, result) => {
let ended = false;
let agentName;
if (err) {
console.error('Error during poll: %s', err.message);
} else {
ended = processEvents(result.events);
agentName = result.info.agentName;
//...
}
});
The callback will be made with two arguments. The first is an Error object, which will be null in the case of a successful poll. The second is an object containing a list of events and an info
object. See Data and Event details
below for details of the returned object.
Processing events:
events.forEach((event) => {
switch (event.type) {
case 'state':
switch (event.state) {
case 'waiting':
waiting();
break;
case 'chatting':
chatting();
break;
case 'ended':
ended();
break;
default:
// Unexpected
break;
}
break;
case 'line':
line(event);
break;
default:
// Unexpected
break;
}
});
See Event details
below for details of events
.
Sending chat lines:
laChat.addLine(text, (err) => {
if (err) {
send('A problem has occurred sending text');
} else {
// Text sent
}
});
text
is interpreted as a String. The callback will be made with a single argument, an Error object, which could be null (in the case of a successful addition).
Ending the chat (from visitor end):
laChat.endChat((err) => {
if (err) {
// Problem occurred, take some action
} else {
// Chat will end (polled events will indicate)
}
});
The callback will be made with a single argument, an Error object, which could be null (in the case of a successful addition).
Instance Creation
An instance of the SDK is created using the Chat()
constructor. The constructor accepts no arguments or one argument.
If no arguments are present, a brand new instance is created. The Live Assist account to which this instance relates must then have been configured through LA_ACCOUNT_ID
(see Configuration
).
If one argument is present and it is not an object, a brand new instance is created and the argument is taken as the Live Assist account to which this instance relates (the environment variable LA_ACCOUNT_ID
is then ignored).
See State data
for the case where a single object argument is present.
State data
The CafeX BOT SDK chat object encapsulates the state of the chat. The state will change over time following operations such as myChat.poll()
. It is important that this state is used consistently across operations.
Depending on the deployment environment, frameworks and other considerations such as HA and scalability, it may not be feasible to constantly use a single instance of a SDK chat object for the duration of a chat. For this reason, the SDK provides an operation to retrieve the state of the chat object which can later be used to ‘reconstitute’ the instance.
The object returned from this operation should not be tampered with in any way, however it can readily be ‘serialized’ to a string for storage and/or transportation (using JSON.stringify
for example).
To get the state data of the chat use myChat.getState()
. To obtain an instance based on that state use new liveAssist.Chat(state)
.
It is important that, when using this feature, the latest state of the chat object be used to create an instance, otherwise unpredictable results may occur. Thus, in terms of interaction with the SDK, the use of new liveAssist.Chat(state)
should always be preceded by a myChat.getState()
(with no other intervening SDK operations).
Code will then use something like the following (which is missing key mechanisms that would be required to achieve a solution):
const liveAssist = require('@cafex/liveassist-botsdk-js');
//...
let myChat = new liveAssist.Chat();
// or
// let myChat = new liveAssist.Chat(myAccountId);
//...
putStore(key, myChat.getState());
//...
let myChat = new liveAssist.Chat(getStore(key));
myChat.poll((err, result) => {
//...
putStore(key, myChat.getState());
})
Agent availability
This provides for checking if an agent (who satisfies some condition) is online and who could be available for chat. This could be preferable to attempting to place a chat and getting an error.
Agent availability options
myChat.getAvailability
requires a condition object to target a set of agents. It has the following properties:
'skill'
- targeting an agent with a specific skill (if omitted, no skill restriction is made). Note that if an unknown skill is provided, an error will result.
Agent availability result
For a non-error response an object with the following properties is passed back:
'availability'
- this will betrue
if an agent is available, andfalse
otherwise.
Transcript capturing
Operation addTranscriptLine
is intended to be used to build up a transcript of the conversation between the visitor and the bot, before escalation to an agent. It takes two arguments. The first is a transcript object - an empty transcript object is returned by newTranscriptLines
. The second must be an object which can have the following properties:
'timestamp'
(mandatory) - an instance of a javascript Date object representing the time at which the line was entered.'isBot'
(optional) - a boolean indicating if the line was sourced from the bot. If omitted or anything other than true, it will be taken that the line was sourced from the visitor.'srcName'
(mandatory) - a string representing a name for the source of the line (eg ‘shopper’ or ‘shoppingBot’)'line'
(mandatory) - a string representing the line of text entered.
The resulting built transcript can be passed as part of a chat request specification.
Chat request
Options
The myChat.requestChat()
method requires a specification of the chat to be started. This must be an object which can have the following properties:
'skill'
- targeting an agent with a specific skill. If omitted, no skill restriction is made.'transcript'
- a built transcript object (seeTranscript capturing
above) recording text lines designated as having occurred before the agent chat began. If omitted, no transcript will be provided.'visitorName'
- the name to give the visitor. If omitted, no visitor name will be set and the non-specific default name will apply.'language'
- the specification of the language in which the chat should be conducted. If omitted, the language will default to English. The language specification must be of the form<lang>-<country>
, see List of Supported Languages for specification codes. Support for the specified language must have been configured in your Live Assist account, otherwise Live Assist will use the default language.'getContextDataSpec'
- an application function that can be called and that will return a specification of CafeX Live Assist chat context data. The data will be posted to the CafeX Live Assist context data service. If omitted, no context data will be posted. SeeContext Data
below.
Context Data
To submit CafeX Live Assist chat context data, the bot can provide a function as part of the chat request options (property 'getContextDataSpec'
). This should return an object specifying the operation to perform. Part of that specification is the data, in the form of a JWT, to be submitted. The function will be called as follows
getContextDataSpec(contextId, callback)
where contextId
is supplied by the SDK and is to be used as the value for the corresponding property of the JWT’s required claims.
The argument callback
is to be used to deliver the result of the getContextDataSpec
invocation, using the standard Node.js error-first callback convention. It will be a function of the form callback(err, contextDataSpec)
.
- In the case of an error, the arg
err
should be set (non-null) and describe the error (the value ofcontextDataSpec
will then be ignored). The whole chat request will then fail. - In the successful case (null
err
),contextDataSpec
should be set to an object with the following properties:'contextData'
- the actual data in the form of a JWT.'contextDataHost'
(optional) - the host/port of the CafeX Live Assist Context Data Server to which context data will be sent (this is the host/port part of the Context Service URL). This is of the form host[:port] where port, if omitted, will default to the standard HTTPS port. The value provided here will override the configured value (LA_CTX_DATA_HOST
) for this chat request. Note that if this property is not set, the value must be configured (LA_CTX_DATA_HOST
, seeConfiguration
below) otherwise the chat request will fail.'contextDataCertificate'
(optional) provides handling for the context data server certificate for non-production scenarios. NOTE: There are security implications in using this property, under normal circumstances it will not require setting. If set to the value'accept'
no authentication of the server certificate will be performed, otherwise the value is taken to specify the context data server certificate, in PEM format. If the value resolves to a readable file, its contents are read and taken as the certificate, otherwise the value is taken as a Nodejs Buffer.
In order to make use of this method you will need to configure the keys through the Live Assist Administration Portal. See our Context Service for more information on the configuration.
Data and Event polling
In the CafeX BOT SDK model, all events that occur within the context of a chat must be polled for using myChat.poll()
. This should be done at regular intervals, subject to processing load and latency considerations.
The SDK does not dictate how a bot within a particular framework would manage such polling, and will depend on aspects of the operating environment related to HA and scalability. The only requirement is that the state encapsulated with an instance of the CafeX BOT SDK chat object (mychat
above) be used consistently between each poll. See State data
below for more information.
The result of a successful poll is an object with the following properties:
'events'
- seeEvent details
below.'info'
- this is information related to the chat, which may change over the life of the chat.
The 'info'
property is an object with the following properties:
'agentName'
- a string representing the name of the agent with whom the visitor is chatting.'isAgentTyping'
- a boolean that will be true if the agent is currently typing and false otherwise.'lastUpdate'
- the last time that any request was sent to the chat session.'chatTimeout'
- the time in seconds from the last update time, after which the chat times out and must be updated again before this timeout.'startTime'
- the time (ISO-8601) the chat started (request was made).
Event details
Within the result of each successful poll is a list of events, possibly empty, that consists of the events that have occurred since the last poll (this gives rise to the consistent state use requirement, described above).
Each event is an object with various properties depending on the event type. Each event will always have the following properties:
'type'
'time'
The various types are described below. The 'time'
property is a ISO-8601 format string indicating the date and time (with timezone info) at which the event occurred with respect to the chat server.
The current set of event types are as follows:
- State events
- Line events
State events
State events have a 'type'
property value of 'state'
. In addition to the standard properties, state events have the following properties:
'state'
- this indicates the state of the conversation, one of:'waiting'
- the visitor is waiting for an agent to answer the chat request.'chatting'
- the visitor is chatting with an agent.'ended'
- the chat has ended (note that this will occur whether the visitor or the agent ended the chat).
Line events
Line events represent messages that have been submitted by any party within the chat. Line events have a 'type'
property value of 'line'
. In addition to the standard properties, line events have the following properties:
'text'
- the text of the message.'source'
- the party that submitted the message, one of:'system'
- this is a message from the chat system (as opposed to any of the participants).'agent'
- a message submitted by the agent.'visitor'
- a message submitted by the visitor.
Configuration
Configuration of the CafeX BOT SDK is achieved using environment variables. Some of these must be provided to use certain SDK features, and some are optional.
LA_ACCOUNT_ID
(optional) - the CafeX account id for CafeX Live Assist. This is used if an instance of the SDK is created with no arguments (otherwise it is ignored). If omitted, then SDK instances must be created by providing an id in the constructor. SeeInstance creation
.LA_APP_KEY
(optional) - the CafeX application key for CafeX Live Assist, if available. If omitted, the SDK will provide a default.LA_CONVERSATION_DOMAIN
(optional) - the domain used in URIs for conversation operation access. If this is not provided, this will be fetched automatically at chat request. If this is known, and set, the fetch will be unnecessary.LA_CTX_DATA_HOST
(optional) - the host/port of the CafeX Live Assist Context Data Server to which context data will be sent on chat request (seeContext Data
above). This is of the form host[:port] where port, if omitted, will default to the standard HTTPS port. This environment variable is required if the'getContextDataSpec'
property is set (to a function) in a chat request options set, and nocontextDataHost
property is set on thecontextDataSpec
returned to the SDK.
The SDK will look in an .env
file for the values and use them if found (see dotenv). Otherwise, these values can be provided through other means particular to the host OS, for example:
Linux/Mac shell:
% LA_ACCOUNT_ID=123456 LA_APP_KEY=abcdef node myapp.js
Windows cmd:
% set "LA_ACCOUNT_ID=123456" & set "LA_APP_KEY=abcdef" & node myapp.js
Alternate async interface
All the SDK methods, except for myChat.getState()
, are asynchronous; their results are delivered at a later time.
All the above examples show the use of the traditional callback technique for dealing with these results. In addition to any other arguments,
each method is provided with a callback function to invoke upon completion. The above examples describe the callback arguments for the various methods.
In addition to this style of async mechanism, the SDK supports a Promise style interface. Whenever the callback method is missing from a call, the corresponding method will return a Promise. When the Promise is resolved, the success callback is invoked with the arguments described in the success cases for the traditional callback alternative. Similarly, the failure callback is invoked with the arguments described in the error cases for the traditional callback alternative.
As examples, requesting and polling a chat might look something like:
function successChat(suc) {...}
function failedChat(err) {...}
myChat.requestChat(spec)
.then(successChat)
.catch(failedChat);
//...
function processEvents(events) {...}
myChat.poll()
.then(processEvents)
.catch((err) => handleError('MyChat', err));