You need to write a set of mandatory Flow Designer action and subflow scripts to pass the user data to VACS, apply transformations and send the response back to your chat interface endpoint.

Provider and inbound/outbound scripts

A provider, such as Twilio, provides the chat capability. User action scripts perform provider actions, as well as conversational custom chat integration configuration for inbound and outbound transformer actions for your chatbot or custom conversations. Examples of each script are provided. They include a description of what each script does, as well as the action input and action output. You also see examples of the script JSON.

You use Flow Designer to build these scripts to transform server and client messages. The provider, sender, and inbound/outbound transformer scripts are required. You can use the additional scripts to add more functionality to your chat.

Provider attributes action script

The provider attributes action script extracts data from the incoming message. The script knows about the conversational custom chat integration protocol and outputs the content of the incoming message, the user ID of the sender, and an optional authentication token.
Note: If your provider attributes action script has a contextual action, your script must have both the request_context.contextual_action and request_context.typed_value so that the user input (which is matched to a contextual action) is included in the transcript. If you do not set the request_context.typed_value, that message content does not appear in the transcript.
Table 2. Provider attributes action script input/output
Input Output
  • Headers (JSON) - Request headers
  • Payload (JSON) - Request body​
  • Token (String) - Authentication token.
  • provider_user_id (String) - Name of the sender, for example, a user name in a Slack message.
  • request_context (JSON) - Actual content received.
    • typed_value - Typed content such as an answer to a question.
    • attachment_value.url - URL of the attachment.
    • attachment_value.content_type - Content type of the attachment.
    • attachment_value.name - File name of the attachment.
    • contextual action - Action to perform, such as END_CONVERSATION, START_CONVERSATION, AGENT. This script looks at the incoming message. If there is a recognized keyword, then one of the actions can be set, such as outputs.request_context.contextual_action = "END_CONVERSATION";. The framework recognizes this keyword and invokes the contextual action script.
    • context_vars - Contextual variables to pass into a conversation, such as `outputs.request_context.context_vars = {language: "en"};`.
Figure 1. Example: Flow Designer provider attributes action script input, including headers and payload
An Action Input in Flow Designer with Headers and Payload set to use JSON.
Figure 2. Example: Flow Designer provider attributes action script output, including token, request_context, and provider_user_id
An Action Output in Flow Designer specifies the token, request_context, and provider_user_id values.

Example: Provider attributes action script.

(function execute(inputs, outputs) {
    var headers = (inputs.headers);
    var payload = (inputs.payload);

    // check if an authentication token was included. this is optional.
    var smsUtil = new VASMSTwilioUtil();
    outputs.token = JSON.stringify(smsUtil.getToken(headers, payload));

    var data = payload.data;
    var request_context = {}; 
    // inspect the actual message. it could be an MMS (attachment) or raw text
    if (data['MediaUrl0']) {
        var attachment_value = {};
        attachment_value.url = data['MediaUrl0'];
        attachment_value.content_type = data['MediaContentType0'];
        attachment_value.name = smsUtil.getFileName(attachment_value.url , attachment_value.content_type);
        request_context.attachment_value = attachment_value;
    } else {
       request_context.typed_value = data['Body'];
    }

    // set the mandatory outputs
    outputs.request_context = request_context;
    outputs.provider_user_id = data.From;
})(inputs, outputs);

Sender action script (Decommissioned in Quebec see sender subflow)

The sender action script knows how to send a message to the provider. The script should asynchronously invoke a Flow Designer or Integration Hub subflow. The Virtual Agent is freed to continue processing messages rather than trying to send external requests.

Table 3. Sender action script input
Input Output
  • Results (JSON) - Array of messages to send.
  • Payload (JSON) - Last payload received from a requester.
  • app_inbound_id (String) - Identifier of the sender, such as the "From" phone number in an SMS case.
  • channel_user_id (String) - Identifier of the recipient, such as the "To" phone number in an SMS case.
None

Example: Sender action script.

(function execute(inputs, outputs) {
    var results = inputs.results;
    // transform the inputs to something this custom subflow knows about
    var sendInputs = {
        app_inbound_id : inputs["app_inbound_id"],
        channel_user_id: inputs["channel_user_id"],
        messages: JSON.stringify(results)
    };

    // invoke an asynchronous subflow which will send the external request. so this sender script will immediately return,
    // freeing up the chat server thread to do further message processing while putting the external request work on the
    // Flow Designer/Integration Hub
    sn_fd.FlowAPI.startSubflowQuick('sn_va_sms_twilio.va_sms_twilio_adapter_send_sms', sendInputs);
})(inputs, outputs);

Sender subflow script

The sender subflow script knows how to send a message to the provider. The script should asynchronously invoke a Flow Designer or Integration Hub subflow. The Virtual Agent is freed to continue processing messages rather than trying to send external requests. When creating a subflow do not have an action call an action within the subflow.

}else{
  outputs.sendmessage = true;
  messages = inputs.results.results;
  outputs.from = from;
  outputs.to = to;
  outputs.messages = getMessages(messages);
}

Contextual action script

The contextual action script performs special keyword actions such as typing agent while inside a Virtual Agent topic to get immediately handed off to a live agent.

Table 4. Contextual action script Input
Input Output
  • conversation_id (String) - The conversation ID.
  • request_context (JSON) - Request passed from the provider attribute script that contains the action to perform, such as (END_CONVERSATION, START_CONVERSATION, AGENT).
None

Example: Contextual action script.

(function execute(inputs, outputs) {
  var contextual_action = inputs.request_context.contextual_action;
  if (contextual_action === "END_CONVERSATION") {
    sn_cs.VASystemObject.endConversation(inputs.conversation_id);
  } else if (contextual_action === "AGENT") {
    sn_cs.VASystemObject.switchToLiveAgent(inputs.conversation_id);
  } else if (contextual_action === "START_CONVERSATION") {
    sn_cs.VASystemObject.startConversation(inputs.conversation_id);
  }
})(inputs, outputs);

Link account action script

The link account action script contains identifiers for the user who is linking. The script also contains the account that it is linked to.

Table 5. Link account action script Input
Input Output
  • provider_user_id (String) - Identifier of the user who is linking, such as a phone number in an SMS case.
  • status (String) - Success/failure.
  • user_id (String) - ServiceNow user_sys_id for the account that was linked to.
None

Example: Link account action script.

(function execute(inputs, outputs) {
  
  var richControl = (inputs.rich_control);
  var value = richControl.value;
  outputs.result = richControl.header + ': ' + value.action;
  
})(inputs, outputs);

Response processor action script

The response processor action script performs specialty actions that are based on the response to a send message request. The framework already does basic message status tracking.

Table 6. Response processor account action script input
Input Output
  • message_id (String) - Identifier of sys_cs_message record that is associated with this response.
  • headers (JSON) - Headers that are received.
  • body (String) - Body that is received.
  • status code (Integer) - The HTTP status code that is received.
None

Example: Response processor action script.

(function execute(inputs, outputs) {
    gs.debug("Response from provider: message_id = " + inputs.message_id + ", status_code = " +
      inputs.status_code + ", headers = " + JSON.stringify(inputs.headers) + ", body = " + inputs.body);
})(inputs, outputs);

Outbound transformer scripts

The outbound transformer scripts convert outgoing Virtual Agent messages to a protocol that is related to the conversational custom chat integration.

Input.

  • rich_control (JSON) - Virtual Agent server rich control component that must be transformed.
  • payload (JSON) - Last response that was received from a requester.

Output.

result (String) - Provider-appropriate component message to send.

Inbound transformer scripts

The inbound transformer scripts convert incoming conversational custom chat integration messages to a protocol that the Virtual Agent recognizes. It determines the required value to be injected into the rich control that is presented to the user.

Input.

  • request_context (JSON) - The request passed from the Provider Attribute script.
  • rich_control (JSON) - The last rich control sent to the requester that contains the original "question".

Output.

result (JSON) - The result expected by the Virtual Agent server. If the requester is responding to a topic picker, it is the sys_id of the topic. If the requester is responding to an input text, it is the text response.
  • value - sys_id or text value.
  • search_text - Text that is used if the requester selected something that was unexpected. For example, a user typed something that the NLU could assist with, such as, "None of these options match what I want" in response to a topic picker component.
Table 8. Examples: Inbound transformer scripts
Inbound transformer name Script example
Virtual Agent - SMS Twilio Adapter Default Text Inbound Transformer

Purpose: Find the text response to the InputText question posed

(function execute(inputs, outputs) {
  var requestContext = inputs.request_context;
  var richControl = inputs.rich_control;
  var typedValue = requestContext['typed_value'];
  var attachmentValue = requestContext['attachment_value'];
  var smsUtil = new VASMSTwilioUtil();
  var result = {};
  if(richControl['itemType'] == 'image' || richControl['itemType'] == 'file')	{
    if (attachmentValue && attachmentValue.content_type.includes('image')) {
      result.url = attachmentValue.url;
      result.content_type = attachmentValue.content_type;
      result.name = attachmentValue.name;
      result.headers = attachmentValue.headers;
    } else if (typedValue) {
      result.url = typedValue;
      var contentType = smsUtil.getContentType(typedValue);
      if (typeof contentType === 'undefined')
        gs.error('Please enter a valid image link. Inbound image link: {0}', typedValue);
      else
        result.content_type = contentType;
    } else {
      gs.error('Please upload an image or enter a valid image link.');
    }
  }
  result['value'] = typedValue;
  result['search_text'] = '';
  outputs.result = result;
})(inputs, outputs);
Virtual Agent - SMS Twilio Adapter Default Picker Inbound Transformer

Purpose: Find the sys_id of the option that the user selected for this picker question. This script uses the same algorithm of the outbound transformer. If no options are selected, and the user typed something instead, then the "search_text" is set and fed into NLU if it is enabled on this instance.

(function execute(inputs, outputs) {
  var request_context = inputs.request_context;
  var rich_control = inputs.rich_control;
  var selectedValue = request_context["typed_value"];
  var result = {};
  result["value"] = "";
  result["search_text"] = "";
  if (rich_control['options']) {
    var options = rich_control['options'];
    var optionsLength = options.length;
    selectedValue === Number(selectedValue)
    if (selectedValue > 0 && selectedValue <= optionsLength) {
        var selectedOption = options[selectedValue - 1];
        result["value"] = selectedOption.value;
    } else {
        result["search_text"] = request_context["typed_value"];
    }
  }
  outputs.result = result;
})(inputs, outputs);