Skip to main content

Global Scripts

Global Scripts are commonly used for controlling and manipulating user input at different stages of a session or when a solution is unloaded or loaded.

The sections in this page cover the following topics:

Concept

Global Scripts are commonly used for controlling and manipulating user input at different stages of a session or when a solution is unloaded or loaded. They are divided between Session Scripts and Engine Scripts and managed at a solution level. The scripting language in Teneo Studio is Groovy, and Teneo Studio provides basic support for syntax highlighting in the [script editor](/studio/build/scripting/scripting#script editor).

It is possible to set the order in which scripts of the same type are executed in the order defined by the user in the Script Ordering. A diagram outlining the order in which Teneo executes scripts (and other tasks) can be found in the reference section: Input processing path.

info

Full details of accessible engine scripting methods is available here and details on which script is accessible from where can be found here.

The Session Scripts and Engine Scripts include different types of scripts, which are all presented in the section below.

Session Scripts

Session scripts are used to control and manipulate user input at different stages of the session. These scripts have read and write access to session data (like Global Variables or the input of the user) and read-only access to solution data. They are therefore connected to the scope of a particular session.

tip

More details on sessions can be found in the Session Management paragraph in the 'Engine API' page.

Begin Dialog

'Begin dialog' scripts are executed at session start and are the very first global scripts to execute when an end-user talks to the solution. Scripts here will be performed only once, at the start of each session, and it is commonly used to perform tasks that need to happen at the beginning. For example, you might use this script to check if a certain parameter was included in the first request.

Depending on how this session began, the next script to execute will be either the 'New session' script or the 'Timed-out' session script.

New Session

This script runs following the 'Begin Dialog' script, but only if the request did not contain a session ID. The absence of a session ID in the request tells the engine it should start a new session and execute this script. This script is not commonly used. You should use it only if you explicitly want it to run at the start of a new clean session.

Timed-out Session

A 'Timed-out Session' script runs when an end-user whose session timed out resumes the dialogue with the AI application. It runs following the 'Begin Dialog' script, but only if the request did contain a session ID and the corresponding session was expired or is unknown. In this case, the engine will assume the session was timed out, start a new session, and execute the 'Timed-out session' script. You should use this script only if you explicitly want it to be executed for timed out or resumed sessions.

info

Usually, a session times out after 10 minutes of inactivity.

Pre-processing

The 'Pre-processing' script is executed on each transaction, before the engine processes any of the input. This means you can manipulate the user input string before it is tested against Flow triggers or transitions. A more common use of the 'Pre-processing' script is to access other elements of the incoming HTTP request. For example, it is very commonly used to store values of URL parameters in Global Variables:

if (engineEnvironment.getParameter("channel")) {
channel = engineEnvironment.getParameter("channel")
}

Pre-matching

A 'Pre-matching' script is executed on each transaction before matching, but after the input is separated for processing (sentence segmentation) and separated into words (tokenization). It is run before the engine tests the user input against flow triggers or transitions. This script is not commonly used.

Post-processing

'Post-processing' scripts are executed after your solution has created a response, and consist of the output text, output URL, emotion, and output parameters. It is commonly used to run scripts that depend on the results of the flow processing, right before the final response is returned to the end-user. It can also be used to change the response data. For example:

if (channel == 'slack' && _.getOutputURL()) {
_.setOutputText(_.getOutputText() + '\nMore details: ' + _.getOutputURL())
}

End Dialog

The 'End dialog' scripts execute once, at the end of each session/dialogue. They could, for example, be used to write session details to an external system or to close database connections.

Pre-logging

The 'Pre-logging' script is executed when the session/dialog has ended, but before the data is written to logs. It allows to modify content fields, for example, input/output text, input/output parameter values and Variable values, and enables the removal of data which should not be logged. Therefore, the script can both see and modify the content captured during the session before it has actually been logged.

One use-case is anonymizing names. We can either remove a name or replace it with a common pseudonym like 'Jane Doe'. In the script below, we change the value in Lib_sUserFirstName, which stores the user's first name, to Jane:

_.getDialogHistoryUtilities().replaceVariables(['Lib_sUserFirstName'], 'Jane');

On Top

'On-top' scripts will be executed whenever a Flow becomes the top flow on the Flow stack (either by being triggered or by regaining the top position after being interrupted by the triggering of another Flow).

On Drop

'On drop' scripts will be executed whenever a Flow is finished and the task is removed.

Engine Scripts

Engine Scripts are only executed when a solution is loaded by the engine (typically when the engine is started) or when a solution is unloaded (typically when the engine is stopped). They have read and write access to solution data and are not connected to nor have access to any particular session. This means you can't directly use session-specific data (like Global Variables) in these scripts. You can, however, pass on the EngineAccess and EngineEnvironment objects to the classes' methods defined here.

Secret

Secret scripts have read and write access to solution data. However, they are not connected to nor have access to any sessions. As they are intended to define utility classes to be used by scripts running later, the Secret script type is executed right before the Solution loaded scripts by the Engine. This script type works just as the Solution loaded scripts, but also has access to and can make use of any Secrets and their values defined in the Account Settings.

On Solution Loaded

This script runs once when the solution is loaded into the engine's memory. It very commonly contains utility classes that are used throughout the solution. For example, you could add a class here that offers various string manipulation methods.

On Solution Unloaded

This script runs once directly before the solution is unloaded. It is not a commonly used script field.

How To

Create

To create a new Global Script in Teneo Studio Web, follow the below steps:

  1. First, either:
    • Click the Create button next to Scripts in the Globals tile on the Solution dashboard, or
    • In the view of Global Scripts , click on Create New Global Script.

Create New Global Script

  1. The Create Global Script opens, select the wanted Global Script type and click Next.
  2. Now, give the Global Script a Name and optionally write a description.
  3. Click Create.
  4. Now, in the Script editor, define the execution script in Groovy.
  5. Remember to Save the Global Script to preserve the changes.

Edit

To edit a Global Script, follow the below steps:

  • Go to the list of Global Scripts (Solution dashboard > Globals tile > Scripts)
  • In the list, select and click the script to open it
  • Now, perform any needed changes
  • Remember to Save the Script to preserve the changes.

Save

To save a Global Script, follow the below steps:

  1. Click Save in the top ribbon.
  2. Optionally, add a comment.
  3. Click Save to confirm the save action or Cancel to abort the save.

Successful save is confirmed with a "Document saved successfully!" message; by clicking elsewhere in the browser window the message is closed.

info

The Save button is only visible when changes are performed to an already existing Global Script or if the Global Script has not been saved earlier.

Close

To close a Global Script in Teneo Studio Web:

  1. First, remember to Save if any changes were performed in the Global Script; Teneo Studio will prompt the user to save if unsaved changes are detected
  2. Next, simply navigate back by using the back arrow of the browser or by clicking a location in the folder path available in the top ribbon.

Delete

To delete a Global Script in Teneo Studio Web, follow the below steps:

  1. Navigate to the list of Global Scripts (Solution dashboard > Globals tile > Scripts).
  2. Hovering over the Script an icon of a recycle bin appears in the right side of the browser window, click on it.
  3. The user is prompt to confirm the deletion of the Global Script, click Delete to confirm the deletion.
note

The deletion of a Global Script currently cannot be undone in Teneo Studio Web, for this action please refer to the Recycle Bin available in Teneo Studio Desktop.

Filter

A text filter is available in the top ribbon of Teneo Studio Web which allows to filter on the displayed list of documents; simply write the wanted letter combination to start filtering on the list.

The filter works on the following columns: Name, Description, Author.

Order

The Script Ordering allows the user to organize the order in which the Scripts are executed, the Scripts can be ordered by dragging/dropping them into the desired order; this is done in the list view of the Global Scripts by pressing the three horizontal lines in the far-left side of a Script and dragging it onto the wanted position where it is then dropped.

Note that it is not possible to drag/drop from one script type to another, only within the given script type. Also the option to drag/drop only appears when two or more Scripts of the same type are available.

When changing the order of one or more Scripts, remember to click Save in the top ribbon to preserve the changes.

Please see Script ordering to see the window where this is done.

UI

View of Global Scripts

The Global Scripts are available on the Solution dashboard in the Globals tile; clicking the right-pointing arrow takes the user to the list of Global Scripts.

web global scripts view

In this view the user will find:

  • The list of existing Global Scripts (if any)
  • The "Order" column indicating the execution order of Global Scripts, read more
  • Create button allowing to create a new Global Script
  • Text filter available in the top ribbon

Global Scripts Window

The Global Script window is accessed from the list of Scripts by either creating a new Global Script or by clicking any existing Global Script.

web global script window

The Global Script contains the following:

  • The path in the top ribbon allowing to easily return to the list of Global Scripts or the Solution dashboard.
  • Script editor to define the execution script.

Script Ordering

The Script Ordering allows the user to organize the order in which scripts of the same type are executed. This is done in the Global Scripts view by dragging and dropping the scripts into the wanted order.

multiple-scripts-web

Practical Examples

Store Input Parameters

info

More details on how client applications can interact with Teneo can be found on the Teneo Engine client API page.

Client applications can have input parameters. In this example, we store the input parameter discountParameter in a Global Variable, so that it can be used by Scripts and Integrations. To do so, we need to do two things:

  1. Create a Global Variable to store the value of the input parameter.
  2. Create a Global Script that populates the variable only if the input parameter is found.

Create a Global Variable

To create the Global Variable to store the discount code of the user, follow these steps:

  1. Open the 'Solution' tab in the solution's window.
  2. Select 'Globals', and then select 'Variables'.
  3. Click 'Add'. Give the variable the name: discountCode, and set its initial value to the empty string: "".
  4. Click 'Save'.

Now we can populate the Global Variable discountCode with the value of the input parameter discountParameter.

tip

Since this is a Global Variable, it can be used by any Flow and it can also be used to assign variable-based context restrictions.

Create a Global Script

To populate the Global Variable, we need to create a Global Pre-processing Script:

  1. Open the 'Solution' tab in the solution's window (if you are not there already).
  2. Select 'Globals' and then select 'Scripts'.
  3. Select the 'Pre-processing' where you want to store your code ('Pre-processing' or 'Begin dialog') and choose 'Edit'.
  4. Paste in this Groovy script:
    if (engineEnvironment.getParameter('discountParameter')) {
    discountCode = engineEnvironment.getParameter('discountParameter')
    }
  5. Give your script a name like Grab discount code and click 'Save'.
info

The getParameter method is part of the Engine scripting API that is available in the EngineEnvironment class.

The end result should look like this:

script name

Test Input Parameters

We can simulate input parameters by adding them to the Inputs panel in the main window of Teneo:

  1. Select the 'Tryout' button located in the top left corner. This will open a new detailed Tryout window.
  2. Select 'Add Parameter' located above the box where you write.
  3. Add a parameter and name it: discountParameter (above).
  4. Add the parameter's value which is the discount code: CyberMon (under).

discount parameter

NAMING PARAMETERS

In Tryout, input parameters are reviewed to ensure correct handling of these based on casing (upper/lower case) and to not allow duplicated parameter names.

PARAM1, param1 and PAraM1 are different parameter names, since the casing is different.

PARAM2 and PARAM2 will raise a warning as the name is duplicated.

Also note that parameter names are always required and the field cannot be left empty.

To see if the Global Variable discountCode got populated as intended, open the Tryout panel and give any input. Then open the Response info panel and inspect the Global Variables. You should see the Global Variable discountCode populated with CyberMon.

test input parameters

Anonymize User Data

When dealing with bots, a user is very often in a position of giving out personal information. Here we see two main ways to anonymize data in Teneo: based on a variable or based on annotations. Both methods make use of Global Scripts.

personal data redacted

Anonymize a Variable

For this example, we will create a Global Script that anonymizes the user's first name by using the Global Variable userFirstName:

  1. While inside your solution, click on the 'Solution' tab.
  2. Click on 'Globals'.
  3. Select the 'Scripts' tab at the top.
  4. Add a new 'Pre-logging' script and name it Replace user name.
  5. Add the following line into the editing window: _.getDialogHistoryUtilities().replaceVariables(['Lib_sUserFirstName'], 'John Doe'). This will automatically replace the variable value to 'John Doe' right before its starts logging it.
  6. Hit 'Save'.

script explained

note

This does not affect the functionality in your solution, the variable is replaced once the conversation is over and the tasks is done. This is also possible with Outputs, Metadata and much more.

Anonymize based on Annotations

You can also take advantage of the Named Entity Recognition and Part-of-speech annotations and anonymize data with them. In the following example, we will go ahead and redact the names mentioned while communicating with our bot, using the PERSON.NER annotation tag.

info

You can find a list of the Part-of-speech (POS) and Named Entity Recognition (NER) tags included in Teneo.

Add a Post-processing Script
note

This example assumes the user has created a Global Variable called toRedact.

We need to add a Post-processing script to capture relevant data, so that it can later be redacted:

  1. Select the 'Scripts' tab at the top.
  2. Add a new 'Post-processing' script and name it Find items to redact.
  3. Add the following groovy script into the editing window:
// Find names that have been mentioned by the user
_.inputAnnotations.getByName('PERSON.NER').each { person ->
def sentence = _.sentences[person.sentenceIndex]
def firstWord = sentence.words[person.wordIndices.min()];
def lastWord = sentence.words[person.wordIndices.max()];
def beginIndex = firstWord.beginIndex
def endIndex = lastWord.endIndex
// Select the items to redact
def itemToRedact = [
'historyIndex': _.dialogHistoryLength,
'beginIndex': beginIndex,
'endIndex': endIndex,
'value': sentence.text.substring(beginIndex, endIndex)
]
toRedact.add(itemToRedact)
}
  1. Hit 'Save'.
tip

The value to store can be changed by replacing the PERSON.NER in line 2, to any other Part-of-speech (POS) or Named-entity recognition (NER) tag.

Add a Pre-logging Script

We will also add a Pre-logging script to redact the values stored in the Global Variable:

  1. While inside the 'Scripts' tab, add a 'Pre-logging' script called Redact names.
  2. Add the following code into the editing window:
// Replace the mentioned name with '*'
toRedact.each {
_.dialogHistoryUtilities.redact(it.historyIndex, it.beginIndex, it.endIndex, '*' as char)
}
def values = [*toRedact.collect {it.value}, Lib_sUserFirstName]
// Replace output
_.dialogHistoryUtilities.replaceResponseText(values, '****')
// Remove the variables
_.dialogHistoryUtilities.removeVariables(['Lib_sUserFirstName', 'toRedact'])
Hit 'Save'.
  1. Hit 'Save'.
tip

Make sure you return to Tryout and reload the engine before continuing on the next step!

Publish and Test Your Bot

In order to see if the scripts work, you will need to publish your bot:

  1. Open the 'Solution' tab in the solution's window.
  2. Select 'Publish' in the left sidebar.
  3. Click the 'Manage' button and in the drop-down you will see a lot of different alternatives. Locate the 'Latest' section and choose 'Publish'.

publish error

info

You might see a warning saying 'Publish to 'Default env' stopped with warnings. ' This is nothing to worry about; the warning is shown when you publish your solution for the first time or when you have made certain global changes. To proceed, just check the checkbox 'Perform full application deployment on Try again' and click the 'Try again' button.

After publishing, it is necessary to test the bot to analyze the anonymization:

  1. Once published, click on the blue 'Open' icon. This will open a chat in a new browser tab.
  2. Click on the blue icon in the bottom right corner to open up the chat window.
  3. Strike up a conversation with the bot, like:
    • Hi, my name is John Doe
    • Goodbye!
  4. Close the chat window to end the conversation.

Read the Logs

Now we will open up Log Data Source to see if the name has been redacted.

  1. Open the 'Solution' tab in the solution's window.
  2. Select 'Optimization' in the left sidebar.
  3. Navigate to 'Log Data' and open up your source by clicking on the 'Manage' button followed by 'Open'.

The Log Data window should be open now. The next step is to open a new Session viewer tab to retrieve the latest session.

  1. In the 'Session Viewer' section, click on 'New Session Viewer Tab'.
  2. Change the values to 'Start date' and 'Descending' to retrieve the most recent session.

You should see the user name anonymized. If not, please repeat the steps above.

Encrypt User Data

In conversations with bots, users are often in a position of giving out personal information. Keeping track of what personal data may be captured by the bot is therefore part of the normal development of bots. The Pre-logging script event can be used to anonymize personal data in a way where the functionality of the bot is not compromised. With the Pre-logging script we can:

  • Remove data before it leaves Teneo Engine
  • Redact, remove, or encrypt sensitive data

The following approach documents how you can use the Pre-logging script to encrypt all user data for use cases where your bot handles sensitive data. We are using asymmetric (or public/private key) encryption, as this enables the bot to encrypt using the public key and allows the developer to keep the private key safe for decryption. This means that the user data stored is never visible in Teneo.

Teneo SaaS

The Teneo SaaS offering already has built-in best practice encryption for data in rest and transit.

  • All traffic to and from Teneo is encrypted via standard techniques like TLS over HTTPS.
  • Data Stores are encrypted using AES256.
  • Static config is encrypted with other techniques.
  • Find a full list of security features in Annex 2 of Data Processing Addendum.

Bring your own key

Bring Your Own Key is an encryption key management system that allows enterprises to encrypt their data and retain control and management of their encryption keys. The data, in this case, are located in sessions inside the solution.

Use cases for which this approach may be advisable include:

This approach is ideal in many cases, including but not limited to companies that:

  • are concerned about legal jurisdictions and data leaving their own economic zones when user data enters the cloud;
  • have extreme data residency concerns;
  • or are used to using SaaS or cloud services but expect to be able to do their own encryption of the data.

Setup structure

The following image describes the setup structure for this approach:

encrypt-view

This setup follows the current best practice by using RSA, OAEP with SHA-256 and MGF-1 padding. This is a standard approach and can be used from modern environments. We've supplied a groovy script for convenience that can be found below.

info

In our implementation, all encrypted values are prefixed and suffixed with €€ to make them easier to search and replace for when decrypting.

Generating keys

As the first step, we need to generate both a private and a public key that will be used to decrypt the logs. This will be done with the help of OpenSSL.

  1. Use OpenSSL and generate your private key with the following line: openssl genpkey -out privatekey.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048
  2. Make sure you store the generated file somewhere safe.
  3. Now it is time to generate a public key by using the following command: openssl rsa -in privatekey.pem -outform PEM -pubout -out publickey.pem

Next, upload the publickey.pem to your solution as a file resource with the path /script_lib:

  1. Return to the Teneo solution you were in and click on 'Solution' in the upper left corner.
  2. Select 'Resources' on the left.
  3. Select 'File' at the top.
  4. Use 'Add' on the upper right to add the publickey.pem file. (Alternatively, you can drag and drop it.)
  5. Set the 'Published Location' for this file from / to /script_lib. This ensures the file can be accessed using a Groovy script later.
  6. Hit 'Save'.

Add a Groovy script

Follow the same steps as above, download the StringEncryptor class and add it to your solution. This will be used for encrypting data.

Pre-logging script

Finally, we will add a Pre-logging script to access the files created above and redact the logs.

  1. Select the 'Scripts' tab at the top.
  2. While inside the 'Scripts' tab, create a new script, selecting 'Pre-logging' from the dropdown. Give the script a name like Redact logs.
  3. Add the following code into the editing window:
def encryptor = new StringEncryptor()

_.getDialogHistoryUtilities().replaceLogVariables(encryptor.variableReplacer())
_.getDialogHistoryUtilities().replaceMetadata(encryptor.variableReplacer())
_.getDialogHistoryUtilities().replaceResponseVariables(encryptor.variableReplacer())

_.getDialogHistoryUtilities().replaceRequestParameters(encryptor.parameterReplacer())
_.getDialogHistoryUtilities().replaceResponseVariables(encryptor.parameterReplacer())

_.getDialogHistoryUtilities().replaceUserInputText(encryptor.valueReplacer())
_.getDialogHistoryUtilities().replaceResponseText(encryptor.valueReplacer())
_.getDialogHistoryUtilities().replaceResponseURL(encryptor.valueReplacer())

_.getDialogHistoryUtilities().replaceVariables(encryptor.objectVariableReplacer())

  1. Save the script.
note

Please note that this code will encrypt all session data. The non-user session log data is kept, so that a Studio user can still see e.g. which flows has been raised or that a users name was captured, but is unable to see details (without the private key). Please edit the code if you want documents such as folder name and flow name to be encrypted as well.

Testing

Make sure there are no errors in your solution before continuing to the next step. This can be done by chatting with the bot in Tryout and verifying that you don’t have any compilations errors:

  1. Return back to the main solution view. If the Tryout panel is not visible, make it appear by clicking the 'Tryout' button on the right side of the window.
  2. Make sure to click on 'Reload Tryout' if shown.
  3. Try to write a couple inputs like,
  • Hello
  • How are you?
  • Goodbye
  1. If you see a warning box appear, please go back and redo the steps above.
tip

Read more about debunking your solution with Tryout here.

Once you have verified that there are no errors, proceed with publishing your bot.

After talking to your published bot, view the logs and you should see that sessions are encrypted:

encrypted-logs

Retrieving sessions from Inquire

Logs in Teneo are now encrypted and cannot be read there. To read them, you must extract and decrypt them locally.

  1. Download teneo-retrieve-inquire-sessions.zip.
  2. Unzip the package and set up an .env file using the .env_sample.
  3. Open your command line and navigate to the relevant folder.
  4. Run npm install, yarn install, or bun install to download the dependencies.
  5. Finally, run node index.js to retrieve the sessions. The code will create one .json file per session retrieved.
note

Note that this code will only return the sessions captured during the previous hour. It is recommended to run this code hourly to retrieve all sessions.

Decrypting the session logs

As a final step, we need to decrypt the session logs.

  1. Download the file decrypt.groovy and place it in the same folder your keys are in.
  2. Run the following script to decrypt the sessions: groovy decrypt.groovy [path with sessions] [output directory].

Your session logs are now decrypted and can be read.