Bypass Mode middleware

Description of bypass-mode-middleware, that when Aura Bot is in bypass mode, sends any input message directly to an external service

Introduction

The main functionality of bypass mode, is that once we are in this mode within a conversation, any input message to aura-bot will be directly sent to the external service, without any recognition made by the bot.

Likewise, any message from the external service will be shown to the user without going through aura-bot recognition system.

The source code of this middleware is included in Aura Bot Platform middlewares - Github repository.

The bypass-mode-middleware extends BotFramework class IncommingMessageMiddleware, meaning that certain code is executed on incoming message.

flowchart TD
    A[Request] --> InitMiddleware (Middlewares)
    subgraph Middlewares
        direction LR
        InitMiddleware[...] --> BypassMode
        BypassMode -->|disable| NLPRecognizer
        BypassMode -->|enable| FinalizeRecognizer
        NLPRecognizer --> FinalizeRecognizer
        FinalizeRecognizer --> EndMiddlewares[...]
    end
    EndMiddlewares --> AuraBot[Aura Bot]
    style BypassMode fill:#800,stroke:#300,stroke-width:1px

The bypass-mode-middleware skips the execution of nlp-recognizer-middleware, setting the value of intentResult in the TurnContext to the same that started the bypass mode.

In case of Init state, all the following middlewares are skipped. The dialog can find these messages in channelData conversationHistory.

⚠️ This is an incoming message middleware, so it only handles incoming messages.

📃 Find here practical guidelines for the configuration of aura-bot in bypass mode.

When using the bypass mode

The bypass mode can be used when all messages in a conversation want to be managed by the same dialog, without the bot recognizer system redirecting the request to another dialog.

The bypass mode ensures that, once active, all requests will be sent to the dialog that started this mode and will continue to receive all requests until the bypass mode is deactivated.

The bypass mode can be useful in multiple use cases:

  • Chat with external systems. For example, the handover dialog directly forwards to Genesys (call center) all the messages the user sends once the communication between Aura and Genesys is established.

When the Bypass mode is finished

There are three different ways to exit the bypass mode:

  • It can be decided by the handover dialog itself, using closeBypass method in the bypass object stored in the TurnContext.

  • When certain time (configurable using de expirationTime field in the bypass object) passes without any exchange of messages.

  • When a user message sends one text defined as closeString. Currently, the user can close bypass indicating keywords defined by the bypass_model (using the closeString field). In the bypass model (saved in conversationData), it is possible to indicate the words that close the bypass mode. By default: core:bypass.close.words.

How does it work

The bypass-mode-middleware checks for each request if there is a bypass variable in the user’s conversationData. If the bypass variable exists (type @telefonica/aura-bot-common/models/bypass-model) and its status is different from Off, the middleware will perform the operations depending on the state.

The different possible bypass states are defined in BypassState enum:

export enum BypassState {
    Init = 'init',
    Bypass = 'bypass',
    Closed = 'closed',
    Paused = 'paused',
    Off = 'off'
}

Behavior depending on the state

As previously indicated, the bypass-mode-middleware performs operations based on the state of the bypass variable, which can be modified by the dialog according to the needs:

Init

Perform as in Bypass state. It allows the dialog to execute boot actions.

Bypass

By default, the bypass-mode-middleware sets the intentResult in TurnContext with the intent to start the bypass mode (bypass.intent), so that the dialog can manage the message.

If the bypass has not expired, the last access information (using updateLastAccess method) will be updated, restarting the expiration time again. In this state, the middleware does not close the bypass, this work is delegated to the dialog itself.

In the Bypass state, it is possible to execute an action using an channelData.auraCommand with the following format in the intent field (activity.channelData.auraCommand.value.intent):

<intent>.<action>

The possible actions that can be executed are defined in BypassAction enum:

export declare enum BypassAction {
    Init = "init",
    Start = "start",
    Close = "close",
    Pause = "pause",
    None = "none"
}

Currently, only the following actions have an effect on bypass-mode-middleware:

  • Close. Set bypass in Closed state and continues the normal execution.

As an example, we can send an auraCommand with the example-intent.close value on intent field to close the bypass and send to the dialog that handles the example-intent intent.

{
    "auraCommand": {
        ...
        "value": {
            "intent": "example-intent.close",
            "entities": [
                ...
            ]
        }
    }
}

Closed

Close bypass removing it from conversationData.

Paused

Currently it has no effect, although in the future it will temporarily stop bypass mode and resume it again.

Off

It has no effect.

Bypass model

The bypass model contains the following information:

export interface BypassModel {
    state: BypassState
    intent: Intent;
    duration: number;
    recipient: ChannelAccount;
    userId: string;
    data: any;
    closeReason: BypassCloseReason;
    payloadName: string;
    closeString: string | string[];
    expirationTime: number;
    recognizersEnabled: boolean;
    recognizersBreakIntents: Map<string, string[]>;
}
Property Description
BypassState Current Bypass State
intent Intent that initiates the Bypass
duration Bypass life time in minutes
recipient Recipient to return the message to
userId Identifier of the user who activated the Bypass
data Specify information for dialog
closeReason Reason for closure. If unknown, the dialog must find out what the cause was
payloadName Name of the property in the channelData.payload. Used to send data to the bypass.ex: ‘handover’
closeString Comma-separated string or array of string with the words that directly close the bypass
expirationTime Date of timeout for bypass
recognizersEnabled Flag to indicate whether or not recognizers must be executed and the final result stored, although the bypass is enabled.
recognizersBreakIntents Recognized intents to replace dialog with

State diagram

The following diagram shows the state transition of bypass mode:

stateDiagram-v2
    [*] --> Init : Dialog init bypass (Bypass.initialize)
    Init --> Bypass : Dialog update
    Bypass --> Closed : Dialog update or BypassAction.Close is received
    Init --> Closed : Dialog update or BypassAction.Close is received
    Closed --> [*] : Bypass model is removed
    %% note left of Init : Dialog perform startup tasks
    %% note left of Bypass : Dialog manages all incoming conversation requests

Examples

Dialog using bypass

Starting bypass mode

In an initial state, the user’s conversationData does not have bypass information. The dialog must create the bypass object to start the bypass mode.

sequenceDiagram
    actor User
    Note right of User: No bypass
    User->>Bot: "First message"
    Bot->>BypassModeMiddleware: request context
    Note right of BypassModeMiddleware: does nothing (no bypass model)
    BypassModeMiddleware->>NLPRecognizerMiddleware: recognize from context
    NLPRecognizerMiddleware->>NLPRecognizerMiddleware: recognized intent: "intent.example"
    NLPRecognizerMiddleware->>ExampleDialog: request context
    ExampleDialog->>ExampleDialog: OnInit
    Note right of ExampleDialog: Create bypass model (bypass state: Init)

Receiving messages with Init or Bypass state

The bypass mode can remain in Init state until the dialog itself ends up performing startup tasks, or it can directly set the Bypass state (if the dialog does not have to execute any task).

In this state, nlp-recognizer will not do anything, since the bypass-mode-middleware will have set intentResult with the intent.example value.

sequenceDiagram
    actor User
    loop
        Note right of User: Bypass on Init/Bypass state
        User->>Bot: "New message X"
        Bot->>BypassModeMiddleware: request context
        Note right of BypassModeMiddleware: intentResult = "intent.example"
        BypassModeMiddleware->>NLPRecognizerMiddleware: does nothing
        Note right of NLPRecognizerMiddleware: does nothing
        NLPRecognizerMiddleware->>ExampleDialog: request context
        Note right of ExampleDialog: Message received
    end
    ExampleDialog->>ExampleDialog: OnBypass
    Note right of ExampleDialog: When the dialog finishes startup tasks, it can change the bypass state (state: Bypass)

Close bypass

The bypass mode can be closed directly by the dialog, when it has completed its tasks, or by sending the auraCommand with the value intent.example.close:

sequenceDiagram
    actor User

    Note right of User: Bypass on Init/Bypass state
    User->>Bot: "Message with auraCommand: intent.example.close"
    Bot->>BypassModeMiddleware: request context
    Note right of BypassModeMiddleware: Close bypass and set intentResult to "intent.example"
    BypassModeMiddleware->>NLPRecognizerMiddleware: does nothing
    Note right of NLPRecognizerMiddleware: does nothing
    NLPRecognizerMiddleware->>ExampleDialog: request context
    Note right of ExampleDialog: Message received
    ExampleDialog->>ExampleDialog: OnClose
    Note right of ExampleDialog: Execute close tasks

Recognizers enabled

The bypass mode, by default, is designed to avoid the execution of the recognizers of aura-bot, but starting in release 9.10.0 (delivered in March 25) it can be configured, using the dialog flag recognizersEnabled, to allow the execution of the recognizers, but the result is just stored in the context to be available for the dialog, and not to overwrite the bypassed dialog execution.

sequenceDiagram
    actor User

    Note right of User: Bypass on Bypass state
    User->>Bot: "Message from the user: I want to watch channel four"
    Bot->>BypassModeMiddleware: request context
    BypassModeMiddleware->>NLPRecognizerMiddleware: call to nlp
    FinalizeRecognizers->>BypassModeMiddleware: Store the IntentResult for intent.tv.display_channel
    Note right of ExampleDialog: Message received
    ExampleDialog->>ExampleDialog: Execute next step of the bypass dialog
    ExampleDialog->>ExampleDialog: Check if IntentResult is in recognizersBreakIntents
    ExampleDialog->>ExampleDialog: Close bypass
    ExampleDialog->>DisplayChannelDialog: Execute dialog
    DisplayChannelDialog->>Bot: Return display channel response
    Bot->>User: Return display channel response