# Implementation

## Terminology

Term | Meaning
-------- | -------
| `bot` | Deployment of wingbot together with the genbot solution |
| `router` | Routing part of the webchat repository |
| `webchat` | UI part of the webchat repository |
| `assistant` | Watson Assistant instance |

## Anonymization

The anonymization may be switched on/off by the configuration `watson.anonymize`
(`true` or `false`). This switch affects both the pattern anonymization and
the on-demand anonymization. With `watson.anonymize == false` all anonymization
hints in the conversation (including the on-demand anonymization hint) are
ignored.

The dictionary of the anonymized values is stored in the router shared context
variable `anonymizationDict`. This key is skipped during the mapping of the
router context to the Watson context variable `$shared-router`.

## Watson Cache

There are two types of Watson Cache implemented:

1. **Configuration Cache**. The **configuration cache** gathers information from
the Watson context variables prefixed with `genbot-config-`. It is stored in
`DialogAdapterWatsonFactory` and it is initialized with the first conversation
request before creating an instance of `DialogAdapterWatson`. This cache does
not have any timeout as it is updated frequently - whenever the Watson response
contains relevant context variables the configuration cache is refreshed.
The main purpose of this cache is to save API calls in case of technical
requests – there are many technical requests (i. e. not user utterances) sent
to the conversation that are ignored. However in order to decide whether to
ignore the request or not the adapter must know the Watson configuration. With
the **configuration cache** it can ignore the request without raising an API
call to Watson.

2. **Conversation Cache**. The conversation cache is currently intended for
development only. It is stored in `DialogAdapterWatsonFactory` and on filesystem
in `cache/watson_cache.json`.

## Session Management

Every bot application handles three kinds of sessions:

1. **Shared context** - a session that is shared among all bot instances that
participate in a multi-bot solution. The communication with this session is
ensured by the Wingbot `req.sharedContext` and `res.setSharedContext()`
properties.

2. **Bot session** - a session that is specific for each combination of a
deployment and an `appId` and `senderId` coming from the request. It is
similar to the **Wingbot state** but the winbot state is just `senderId`
specific.  The adapters communicate with this session using
`this.session.get()` and `this.session.set()`.

3. **Conversation session**. For the `DialogAdapterWatson` there is not
a one-to-one relationship between the bot session and the conversation session.
This is caused by the fact that the watson session may be very short (depending
on the plan). Whenever the short life of this session expires it is renewed
from the genbot session. During the renewal the conversation session id changes
while the genbot session id is still the same. Conversation session is
always related only to the dialog adapter.

For the **bot session** there are the following session storages available
(configured as `sessionStorage`):

1. `wingbot` - in this case the *wingbot state* is used to store the genbot
session.

2. `redis` - session is stored in redis. It is necessary to add the redis
configuration (see `config/index.js` for the configuration properties).

3. `process` - session is stored in the process memory. This method can be
used only for deyployments with one application instance.

## Routing

The genbot implementation supports both a mode with one NLP as well as a routing
mode with a master classifier and child assistants. The basic non-routing mode
requires the following configuration:

```
watson: {
    assistantId: [STRING]
    apikey: [STRING]
}
```

**Note:** The values may be also promises.

The routing mode has three variants:

1. The routing is controlled by the router and each bot has
a separate deployment.
2. The routing is controlled by the router and there is only one bot deployment
orchestrating all assistants.
3. The routing is internal in the bot and the router does not know about it
(development option only - simplifies configuration)

For option 1. the master bot will have the following configuration:

```
topology: {
    MASTER_APP_ID: {
        CHILD_APP_ID_1: 'watson',
        CHILD_APP_ID_2: 'watson',
        ...
    }
}
watson: {
    assistantId: MASTER_ASSISTANT_ID
    apikey: MASTER_ASSISTANT_APIKEY
}
```
and the child bots will have the configuration:
```
topology: { CHILD_APP_ID: null }
watson: {
    assistantId: CHILD_ASSISTANT_ID
    apikey: CHILD_ASSISTANT_APIKEY
}
```

In case 2. and 3. the configuration will look like this:

```
topology: {
    MASTER_APP_ID: {
        CHILD_APP_ID_1: 'self',
        CHILD_APP_ID_2: 'self',
        ...
    }
}
watson: {
    assistantId: {
        MASTER_APP_ID: MASTER_ASSISTANT_ID,
        CHILD_APP_ID_1: CHILD_ASSISTANT_ID_1,
        CHILD_APP_ID_2: CHILD_ASSISTANT_ID_2,
        ...
    },
    apikey: {
        MASTER_APP_ID: MASTER_ASSISTANT_APIKEY,
        CHILD_APP_ID_1: CHILD_ASSISTANT_APIKEY_1,
        CHILD_APP_ID_2: CHILD_ASSISTANT_APIKEY_2,
        ...
    }
}
```

For case 3 there must be an extra directive:

```
routing: { bypassRouter: true }
```

From implementation perspective the data like caches, sessions etc. are
separeted based on the application id.

**NOTE**: Webchat enables to configure channels. Although channels are not
supported by genbot we can create a common deployment handling more channels
in option  2. or 3. – the `topology` elements in the configuration may be
independent.

### Routing API

The routing making use of the router (not the internal one) is initiated
by sending the request

```
res.passThread(APP_ID, { ACTION, { ADDITIONAL_DATA } })
```

`APP_ID` corresponds to some `WATSON_ALIAS` introduced in the
`watson` section of the configuration (in webchat it must be configured in
the MSSQL tables `APPS` and `CHANNEL_APPLICATIONS`). The application uses
two types of `ACTION`:

1. `genbot.route` for routing without a forced intent.
2. `genbot.route_with_intent.INTENT_NAME` for routing with some intent.

`ADDITIONAL_DATA` uses the following keys:

Key | Meaning
-------- | -------
| `target` | APP_ID |
| `text` | The utterance passed to the target bot. |
| `params` | Object of parameters that are propagated to the target Watson Assistant in context as `$genbot-request-routing_params` (and it is valid only for the routing request as all `$genbot-request-*` context variables are refreshed before each Watson call |
| `shared_params` | Object of parameters that are propagated to the target Watson Assistant as `$genbot-shared` (it is being merged with its previous content) |

**NOTE:** For external routing the `target` parameter would not be needed as it
it being passed to `passThread()` as a separate parameter. However we follow
the convention that for internal routing (which is realized using a postback)
the data are passed exactly in the same format as to the `passThread()` call
and postback does not have any separate parameter for the target.

The incoming request from the router (after routing) is a postback with data
that was passed to `passThread()` as `ADDITIONAL_DATA`. The `ACTION` passed
to `passThread()` can be found in `req.event.postback.payload.action`,
`APP_ID` in `res.data.appId`.
