---
sourceDocument: Yokohama Conversational Interfaces
sourceDocumentLink: https://servicenow-prod.fluidtopics.net/r/yokohama/conversational-interfaces

 Release :

    - yokohama

ft:locale :

    - en-US

ft:publication_title :

    - Yokohama Conversational Interfaces

ft:clusterId :

    - convint

bundleId :

    - convint

workflow :

    - Platform


---

# Virtual Agent action scripts

# Virtual Agent action scripts {#ariaid-title1}

Release version: Yokohama  
Updated March 3, 2025  
![](https://www.servicenow.com/docs/portal-asset/ico-clock) 9 minutes to read
Summarize  
![AI sparkle icon](https://servicenow.com/docs/portal-asset/ai-sparkle-icon) Summarized using AI  
This content was generated using new OpenAI-powered functionality. Results are provided on an as is basis and are not guaranteed to be accurate or complete.  

## Summary of Virtual Agent action scripts

Virtual Agent action scripts in ServiceNow enable integration between Virtual Agent conversations and external chat providers (e.g., Twilio).
These scripts facilitate passing user data to the Virtual Agent Conversational Service (VACS), transforming messages between server and client formats, and managing communication with chat interfaces.
Using Workflow Studio, customers create mandatory and optional action and subflow scripts to support inbound and outbound message handling, context management, and specialized conversational behaviors.
Show full answer Show less  

## Key Scripts and Their Roles

* **Provider Attributes Action Script (Required):** Extracts data from incoming messages, including user ID, message content, attachments, and authentication tokens. It supports contextual actions that trigger special behaviors (e.g., ending a conversation).
* **Sender Subflow (Required):** Manages sending messages asynchronously to chat providers, handles user selections on message options, and updates message displays accordingly.
* **Outbound Transformer Script (Required):** Converts Virtual Agent messages into provider-specific formats suitable for sending through chat interfaces.
* **Inbound Transformer Script (Required):** Converts incoming messages from chat providers into Virtual Agent-compatible formats. Supports default behaviors with the option to customize if default rich controls do not meet needs.
* **Contextual Action Script (Optional):** Executes special keyword-driven actions during conversations, such as transferring users to live agents or ending conversations.
* **Link Account Action Script (Optional):** Handles account linking callbacks, associating chat users with ServiceNow user accounts.
* **Response Processor Action Script (Optional):** Performs advanced message status tracking and processing based on responses from outbound message requests.

## Practical Use and Configuration

ServiceNow customers must implement the provider attributes, sender, outbound transformer, and inbound transformer scripts to enable functional chat integrations. These scripts manage message extraction, transformation, sending, and reception to ensure seamless interaction between Virtual Agent and chat platforms.

Optional scripts add extra capabilities such as contextual keyword handling, account linking, and enhanced message response processing.

Workflow Studio is used to build and customize these scripts using JSON inputs and outputs, enabling tailored behavior for specific chat providers and conversational scenarios.

## Examples and Script Behavior

* The provider attributes script inspects incoming messages for text or attachments, extracts sender identifiers, and sets contextual variables that influence conversation flow.
* The sender subflow asynchronously sends messages and updates conversations based on user interactions with message options.
* Outbound transformers convert complex Virtual Agent rich controls (e.g., cards, pickers, links) into textual or formatted messages suitable for the chat provider.
* Inbound transformers interpret user responses from chat providers, mapping selections or typed inputs back into Virtual Agent's expected input format, with support for fallback natural language understanding (NLU) when user input does not match predefined options.
* Contextual actions enable commands like STARTCONVERSATION, ENDCONVERSATION, or switching to live agents during chat sessions.

## Customer Benefits

By implementing these Virtual Agent action scripts, ServiceNow customers can:

* Enable robust, bi-directional communication between Virtual Agent and external chat platforms.
* Customize message formats and conversational behaviors to fit specific provider protocols and UI requirements.
* Support advanced conversational features such as account linking and dynamic context handling.
* Maintain message status tracking and response processing for improved chat reliability and user experience.  
You need to write a set of mandatory Workflow Studio 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 {#va-action-scripts__section_c5w_qcb_xlb}

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 Workflow Studio 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.  
{#va-action-scripts__table_qnf_xdb_xlb__entry__3}

| Script name | Purpose | Required (Y/N) |
|-|-|-|
| Provider attribute | Contains a Provider Auth token, a user identifier, user input, and context variables. | Y |
| Sender action | Bundles the request, and sends a response asynchronously via Workflow Studio or Integration Hub. | Y |
| Response processor | Performs platform actions, such as an update message status, that's based on a response received for an outbound message.​ | N |
| Contextual action | Supports contextual actions. | N |
| Link account action | Provides a callback about whether account linking was successful or not​. | N |
| Outbound transformer | Transforms a chat server's supported control to chat interface-specific rendering. | Y |
| Inbound transformer | Optional. You can use the default rich controls if they apply to your chat provider. You do not need to provide a separate inbound transform for each input control. If a default behavior does not work, you can override the default with your own inbound transform for a specific Virtual Agent server control. | Y |
[Table 1. Scripts]

{#va-action-scripts__table_qnf_xdb_xlb}

## Provider attributes action script {#va-action-scripts__section_jqc_y2b_xlb}

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.
{#va-action-scripts__table_dtk_5fb_xlb__entry__2}

| Input | Output |
|-|-|
| * Headers (JSON) - Request headers * Payload (JSON) - Request body {#va-action-scripts__ul_gkf_dgb_xlb} | * 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"};\`. {#va-action-scripts__ul_sqy_pgb_xlb} {#va-action-scripts__ul_rgm_hgb_xlb} |
[Table 2. Provider attributes action script input/output]

{#va-action-scripts__table_dtk_5fb_xlb}  
Figure 1. Example: Workflow Studio provider attributes action script input, including headers and payload  
Figure 2. Example: Workflow Studio provider attributes action script output, including token, request_context, and provider_user_id

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 subflow {#va-action-scripts__section_y2f_3m4_h4b}

Instead of a script, the sender subflow handles the process of sending a message to a provider. The message is contained in a payload string as part of the subflow. The sender has a
service_url and origin_service_url, while the outbound URL varies depending on the provider. For example, a message sent through MS Teams uses the value
tenant_id. When the Virtual Agent sends the message containing options, the recipient selects an option. The subflow updates the message display based on their choice and removes the options. The
conversation continues based on the user's selected option. 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. For more information on
subflows, see .

## Contextual action script {#va-action-scripts__section_avl_hkb_xlb}

The contextual action script performs special keyword actions such as typing
<kbd class="ph userinput">agent</kbd> while inside a Virtual Agent topic to get
immediately handed off to a live agent.
{#va-action-scripts__table_bvl_hkb_xlb__entry__2}

| 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). {#va-action-scripts__ul_cvl_hkb_xlb} | None |
[Table 3. Contextual action script Input]

{#va-action-scripts__table_bvl_hkb_xlb}

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 {#va-action-scripts__section_mvv_skb_xlb}

The link account action script contains identifiers for the user who is linking. The script
also contains the account that it is linked to.
{#va-action-scripts__table_nvv_skb_xlb__entry__2}

| 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. {#va-action-scripts__ul_ovv_skb_xlb} | None |
[Table 4. Link account action script Input]

{#va-action-scripts__table_nvv_skb_xlb}

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 {#va-action-scripts__section_lwm_dlb_xlb}

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.
{#va-action-scripts__table_mwm_dlb_xlb__entry__2}

| 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. {#va-action-scripts__ul_nwm_dlb_xlb} | None |
[Table 5. Response processor account action script input]

{#va-action-scripts__table_mwm_dlb_xlb}

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 {#va-action-scripts__section_sjb_qlb_xlb}

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.
{#va-action-scripts__ul_n1m_y24_xlb}

Output.

result (String) - Provider-appropriate component message to send.
{#va-action-scripts__table_tjb_qlb_xlb__entry__2}

| Outbound transformer name | Script example |
|-|-|
| Virtual Agent - SMS Twilio Adapter Default Text Outbound Transformer | (function execute(inputs, outputs) { var rich_control = inputs.rich_control; outputs.result = rich_control['label']; })(inputs, outputs); |
| Virtual Agent - SMS Twilio Adapter Default Link Outbound Transformer | (function execute(inputs, outputs) { var richControl = (inputs.rich_control); var value = richControl.value; outputs.result = richControl.header + ': ' + value.action; })(inputs, outputs); |
| Virtual Agent - SMS Twilio Adapter Default Picker Outbound Transformer | (function execute(inputs, outputs) { var rich_control = inputs.rich_control; var options = rich_control['options']; if (options && options.length > 0) { var optionsLength = options.length; var picker = rich_control['label'] || ""; for (var x = 0; x < optionsLength; x++) { picker += "\n" + (x+1) +  ": " + options[x].label; } } outputs.text_message = picker; })(inputs, outputs); |
| Virtual Agent - SMS Twilio Adapter Default Multi Link Outbound Transformer | (function execute(inputs, outputs) { var rich_control = inputs.rich_control; var linkResult = rich_control['header']; var totalValues = rich_control['values'].length; for (var i = 0; i < totalValues; i++) { linkResult = linkResult + '\n'; var linkValue = rich_control['values'][i]; linkResult = linkResult + '\n' + linkValue['description'] + ': ' + linkValue['action']; } outputs.result  = linkResult; })(inputs, outputs); |
| Virtual Agent - SMS Twilio Adapter Default Card Outbound Transformer | (function execute(inputs, outputs) { var richControl = (inputs.rich_control); var data = JSON.parse(richControl.data); var tableTitle = data.title; var fields = data.fields; var subtitle = data.subtitle; var url = data.url; var message = subtitle ? getCardLine(tableTitle, subtitle) : tableTitle + "\n"; for (var i= 0; i<fields.length; i++) { message += getCardLine(fields[i].fieldLabel, fields[i].fieldValue); } message += url; outputs.result = message; function getCardLine(key, value) { if (value == '' || value == null || key == '' || key == null) return; return key + ": " + value + "\n"; } })(inputs, outputs); |
[Table 6. Examples: Outbound transformer scripts]

{#va-action-scripts__table_tjb_qlb_xlb}

## Inbound transformer scripts {#va-action-scripts__section_j2g_cmb_xlb}

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".
{#va-action-scripts__ul_whj_yf4_xlb}

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.
{#va-action-scripts__ul_dz1_bg4_xlb}
{#va-action-scripts__table_k2g_cmb_xlb__entry__2}

| 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); |
[Table 7. Examples: Inbound transformer scripts]

{#va-action-scripts__table_k2g_cmb_xlb}

