Custom logic light rules

Custom logic light rules are a scope-level configuration that’s used to influence the behavior of contact center flow. These rules are set as a JSON document in the scope-level configuration LightRulesConfig, under Contact Center Integration.

Custom logic light rules are an alternative to the custom logic webhooks that don’t require any kind of externally hosted service. Refer to the following:

Light rules structure

A light rule is a combination of:

  • A condition
  • One or more actions to perform if the condition is true for the current event. It can be one of the following:
    • Set session variables
    • Override a node in the contact center flow
    • Schedule an operation

For example, the following is the rule named disable-record.

{
  "disable-record": {
    "condition": "state.currentEvent == 'CALL_START_EVENT' && cti.kvps.NOAUDIO == 1",
    "sessionVariableUpdates": {
      "state.noaudio": "true"
    },
    "nodesToOverride": [
      {
        "nodeNames": [
          "RecordStartOnCallStarted"
        ],
        "enable": false
      }
    ],
    "actionsToPerform": [
      {
        "action": "DISPLAY_MESSAGE",
        "parameters": {
          "messageType": "warning",
          "titleLabel": "CONSTANT.STATUS.NOT_ELIGIBLE",
          "titleText": "Not Eligible",
          "messageLabel": "CONSTANT.RESULT_TEXT.NOT_ELIGIBLE",
          "messageText": "No voice ID feature required on this call",
          "disableActions": "true",
          "disableRestart": "true"
        }
      }
    ]
  }
}

This rule executes whenever all those conditions are met:

  1. The value of the session variable named state.currentEvent is CALL_START_EVENT. This should happen at most once per call.
  2. The CTI custom data with key NOAUDIO, stored in the session variable cti.kvps.NOAUDIO is 1.

When the conditions are met, the rule performs the following operations:

  1. Set the session variable state.noadio to true.
  2. Disable the built-in flow node RecordStartOnCallStarted.
  3. Display a message to the agent using the DISPLAY_MESSAGE action.

The light rules configuration can have more than one rule defined, with its own name. For example:

{
  "disable-record": {
    ...
  },
  "save-engatement-custom-data": {
 
  }
}

On every event, each rule is evaluated with the same copy of session variables. The operations of the rules with conditions met are applied only after all the rules are evaluated. As such, it is as if all rules are run in parallel to each other. If, for an event, two or more rules have conditions met and attempt to set the same session variable, which of the values is set is undefined.

Evaluated strings

The syntax of the condition string is based on the JSP Evaluation Language, with some modifications.

In addition to the condition string, the following support interpolating sections in the form ${ ... }:

  • All values of sessionVariableUpdates
  • All values of nodeNames in nodesToOverride
  • All values of parameters in actionToPerform

For example, the following sets the session variable state.k1 with the value Hello, 3:

"sessionVariableUpdates": {
    "state.k1": "Hello, ${1 + 2}"
}

If you want to return the character sequence ${ in one of the values that support interpolation, you must evaluate its string value. For example, A ${ '${' }escaping} B is interpolated into the string value A ${escaping} B.

All evaluations have access to the same set of session variables of the current event.

Evaluation language syntax

Grouping

Use ( a ) to group operators at a higher precedence.

Strings

Literals: 'abc' or "abc"

Using single quotes is recommended, as they don’t require to be escaped when placed in a JSON value of the light rules configuration JSON document.

Numbers

Integer: 1, 2, …

Float: 0.1, 1.5, …

Strings automatically casts to a number when used in a binary operator where the other operand is a number.

Boolean

true, false

When casting String to Boolean, only the value true is a positive (true) condition; all other string values are evaluated as false.

Arithmetic operators

Binary: +, -, *, /, %

Unary: -

Relational operators

Binary: ==, !=, <, >, <=, >=

Logical operators

Binary: &&, ||

Unary: !

“empty” unary operator

empty X returns true if X is an empty string; false otherwise.

Conditional operator

C ? A : B: If C is true, evaluate to A, otherwise evaluate to B.

Evaluation language functions

vars.get(k)

Syntax: vars.get(k), where k is a string

Get the session variable with key k. If not found, an empty string is returned.

some.path…

This is a shorthand for vars.get('some.path').

For example, both of the following returns the value of the session variable state.k1:

  • vars.get('state.k1')
  • state.k1

If the session variable name contains a character normally used in the evaluation language, you must use the function vars.get. For example, if you want to refer to the CTI custom data named exactly SOME-KEY WITH SPACES, then you must use the syntax vars.get('cti.kvps.SOME-KEY WITH SPACES').

String.isEmpty()

Returns true only if the given string has a length of zero characters.

For example, all of these evaluate to true:

  • ''.isEmpty()
  • empty ''
  • ! 'a'.isEmpty()
  • ! empty 'a'

String.replaceAll(regex, replacement)

Replace all segments matching the regular expression with the replacement string.

For example, 'a1b2c3'.replaceAll('[0-9]', 'w') evaluates to awbwcw.

String.find(regex, [group])

Find first segment matching regex. If the group number is specified, return the group value, where each group is numbered starting with 1, and group represents the entire match.

For example:

  • '1234'.find('^[0-9]23') evaluates to 123
  • '1234'.find('^[0-9](23)', 1) evaluates to 23

String.format(…)

Format the given arguments with the format string. The formatting rules follow those of Java’s java.util.Formatter  .

For example, '%05d'.format(1) evaluates to 00001.

To force a string argument to be an integer (for %d) or a floating number (for %f), you can add 0 or 0.0 to it, forcing the result to be an integer or a floating value:

  • '%04d'.format('123' + 0) evaluates to 0123
  • '%.2f'.format('123' + 0.0) evaluates to 123.00

String.split(regex, group)

Split the string using the given regular expression as the delimiter and return the specified element group number.

The group numbers start at 1. If the group number is smaller than 1 or is greater than the number of groups, then an empty string is returned.

For example:

  • 'a-b-c'.split('-', 2) evaluates to 'b'
  • 'a-b--c'.split('-+', 3) evaluates to 'c'

User-defined functions

It’s possible to define functions that can be used by any condition or evaluated string in the configuration. Functions can be called by name using the “f” object.

Functions have a unique name and return an evaluated string.

In addition, functions can also take one or more named positional arguments. In the function’s evaluated string, parameters are accessible by name as properties of the “p” object. All parameters are required; if you try to call a function with an incorrect number of parameters, you receive an error.

Following is an example of a simple function:

{
  "_functions": {
    "sayHello": {
      "function": "Hello!"
    }
  },
  "hello": {
    "condition": "empty state.k1",
    "sessionVariableUpdates": {
      "state.k1": "${f.sayHello()}"
    }
  }
}

Here, the session variable state.k1 would be set to the value Hello!.

The following function’s evaluated string can access any session variable or built-in function:

{
  "_functions": {
    "sayHello": {
      "function": "Hello, ${state.name.replaceAll('[Ee]', 'w')}!"
    }
  },
  "hello": {
    "condition": "empty state.k1",
    "sessionVariableUpdates": {
      "state.k1": "${f.sayHello()}"
    }
  }
}

Here, if state.name was set to Alice, then the session variable state.k1 would be set to Alicw.

A function can call another function. The following example has the same behavior as the previous example, but some of its logic has been moved to another function and also makes use of parameters:

{
  "_functions": {
    "sayHello": {
      "parameters": ["name"],
      "function": "Hello, ${f.replaceEWithW(p.name)}!"
    },
    "replaceEWithW": {
      "parameters": ["stringParam"],
      "function": "${p.stringParam.replaceAll('[Ee]', 'w')}"
    }
  },
  "hello": {
    "condition": "empty state.k1",
    "sessionVariableUpdates": {
      "state.k1": "${f.sayHello(state.name)}"
    }
  }
}

Test the light rules configuration

To test the light rules configuration, do the following:

  1. Log in to the Gatekeeper web application.

  2. On the left-side navigation menu, click Configuration. The Configuration page opens.

  3. Select your scope from the SCOPE CONFIGSET list. A list of scope parameter categories appears.

  4. Select Call Center Integration category. A list of call center integration parameters appears.

  5. Edit the LightRulesConfig parameter. A pop-up dialog opens.

  6. Expand Evaluate rule.

  7. In the Session variables text box, paste a JSON that contains the session variables.

  8. Click Evaluate. A JSON structure that’s similar to a custom logic webhook response is displayed in the Result box.

    If there is no error, the Result box contains the response code 200 and the result actions, else it contains an error message.

For example, with the following LightRulesConfig:

{
  "hello": {
    "condition": "empty state.k1",
    "sessionVariableUpdates": {
      "state.k1": "Hello, ${empty state.name ? 'world' : state.name}!"
    }
  }
}

And with the following session variable:

{
  "state.name": "Alice"
}

The result will be:

{
   "resultCode": 200,
   "sessionVariableUpdates": [
      {
         "key": "state.k1",
         "value": "Hello, Alice!"
      }
   ]
}

LightRulesConfig JSON schema

Following is an example of LightRulesConfig JSON schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "description": "Custom Logic Light Rules nodes, to executed in no particular order for each event.",
  "type": "object",
  "properties": {
    "$schema": {
      "type": "string"
    },
    "_functions": {
      "description": "User-defined functions. They are accessible by name through the variable \"f\".",
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "$ref": "#/$defs/Function"
      }
    }
  },
  "additionalProperties": {
    "type": "object",
    "$ref": "#/$defs/Rule"
  },
  "$defs": {
    "NodeOverrideAction": {
      "description": "Update the list of Nodes to override in the built-in flow. The disabled nodes, identified by name, will not execute for the rest of the session unless enabled again. By default, all built-in flow nodes are enabled. Note that currently only built-in flow nodes can be disabled.",
      "required": [
        "nodeNames"
      ],
      "type": "object",
      "properties": {
        "nodeNames": {
          "description": "Required. The list of node names to disable or enable. Each name supports evaluation substrings.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "enable": {
          "description": "When set to false, the nodes mentioned in nodeNames are disabled for the rest of the session. When set to true, the listed node names are enabled again. Default is false.",
          "type": "boolean"
        },
        "comment": {
          "description": "",
          "type": "string"
        }
      }
    },
    "OperationAction": {
      "title": "Root Type for OperationAction",
      "description": "Schedule an operation.",
      "required": [
        "parameters",
        "action"
      ],
      "type": "object",
      "properties": {
        "parameters": {
          "description": "Required. The parameters. Each parameter value supports evaluation substrings.",
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "skipParameterIfEmpty": {
          "description": "If a parameter in \"parameters\" has an empty value, do not pass that parameter in the OperationAction (instead of setting that parameter to an empty value).",
          "type": "boolean",
          "default": false
        },
        "action": {
          "description": "Required. The action to execute.",
          "type": "string"
        },
        "comment": {
          "description": "",
          "type": "string"
        }
      }
    },
    "Rule": {
      "description": "A Custom Logic Rule.",
      "required": [
        "condition"
      ],
      "type": "object",
      "properties": {
        "condition": {
          "description": "The condition that triggers this rule if it evaluates to true.",
          "type": "string"
        },
        "comment": {
          "description": "An optional comment",
          "type": "string"
        },
        "actionsToPerform": {
          "description": "Operation actions to perform if the condition is true.",
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/OperationAction"
          }
        },
        "sessionVariableUpdates": {
          "description": "Session variables to set if the condition is true. Each value supports evaluation substrings. Note that the session variables are updated only after all rules for the current event are executed for the current event, which will generate a SESSION_VARIABLE_UPDATE event",
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "minProperties": 1
        },
        "nodesToOverride": {
          "description": "Nodes to override (or re-enable) if the condition is true.",
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/NodeOverrideAction"
          }
        },
        "skipSessionVariableUpdateIfEmpty": {
          "description": "If an entry in sessionVariableUpdates has an empty value, skip updating that variable (instead of setting that variable to an empty value).",
          "type": "boolean",
          "default": false
        }
      }
    },
    "Function": {
      "description": "A user-defined function. It is accessible through the variable \"f\".",
      "required": "function",
      "type": "object",
      "properties": {
        "function": {
          "description": "The result of evaluating this string will be the returned value of the function.",
          "type": "string"
        },
        "comment": {
          "description": "An optional comment",
          "type": "string"
        },
        "parameters": {
          "description": "The names of the expected parameters. In the function, they can be accessed through the variable \"p\".",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    }
  }
}