Skip to content

Commit

Permalink
New release 2.6.5 (#40)
Browse files Browse the repository at this point in the history
- Added support for REST service event handlers
- Added support for userInputReceived event
  • Loading branch information
stevendavelaar committed May 17, 2023
1 parent f07617c commit 876b3b9
Show file tree
Hide file tree
Showing 24 changed files with 682 additions and 34 deletions.
1 change: 1 addition & 0 deletions ENTITY_EVENT_HANDLER.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ The table below lists all entity level events currently supported:
| `attachmentReceived`| A function that gets called when the user sends an attachment. If the attachment can be mapped to a composite bag item, the validate function of that item will be called first. | <ul><li><b>value</b>: The attachment JSON object with `type` and `url` properties.</li></ul>
| `locationReceived`| A function that gets called when the user sends a location. If the location can be mapped to a composite bag item, the validate function of that item will be called first. | <ul><li><b>value</b>: The location JSON object with `latitude` and `longitude` properties.</li></ul>
| `disambiguateBagItem` | A handler that can be used to modify the message that is shown to disambiguate between bag items when an entity match applies to more than one bag item. Note that this handler only fires when the skill configuration parameter `Use Enhanced Slot Filling` is switched on. | <ul><li><b>matchValue</b>: The entity value matched based on the user input</li><li><b>matchedBagItems</b>: list of the names of the bag items that are matched against the entity value.</li><li><b>userInput</b>: the last user input message that matched to multiple bag items.</li></ul>
| `userInputReceived` | A handler that can be used to inspect and modify new item matches and disambiguation values before the bag items are validated and updated. The handler is invoked on every turn while resolving the composite bag entity. | <ul><li><b>currentItem</b>: The full name of the bag item currently being resolved.</li><li><b>userInput</b>: the last user input message.</li><li><b>newItemMatches</b>: a key-value map where each key is the full name of a bag item, and the value the candidate value for the item. The new item matches can be changed using `context.setItemMatches` and `context.clearItemMatch`.</li><li><b>disambiguationValues</b>: a key-value map where each key is the full name of a bag item, and the value a list of matched values for the item. The disambiguation values for an item can be changed using `context.setDisambiguationValues()` or `context.clearDisambiguationValues()`</li><li><b>disambiguationItems</b>: a key-value map where each key is the full name of a bag item, and the value a map with two properties: <ul><li><b>matchValue</b>: an entity value that matches against multiple bag items</li><li> <b>matchedBagItems</b>: list of the names of all the bag items that match against the entity value. The first item in the list is used as the key in the disambiguationItems map.</li></ul> A disambiguation value that matches multiple items can be removed by calling `context.clearDisambiguationItems()` and passing the full name of the first item in the list as argument.</li></ul>

### Entity-Item Level Events <a name="itemEvents">
The table below lists all entity-item level events currently supported:
Expand Down
14 changes: 14 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Release Notes

- [Version 2.6.5](#v265)
- [Version 2.6.4](#v264)
- [Version 2.6.3](#v263)
- [Version 2.6.2](#v262)
Expand All @@ -14,6 +15,19 @@
- [Version 2.4.3](#v243)
- [Version 2.4.2](#v242)

## Version 2.6.5 <a name="v265">

### New Features

- **New UserInputReceived Entity Event Handler Method**: See [Writing Entity Event Handlers](https://github.com/oracle/bots-node-sdk/blob/master/ENTIY_EVENT_HANDLER.md) for more information.

- **REST Service Event Handlers**: REST service event handlers can be used to transform the REST request and response body when using the Call REST component in your flow. See [Writing REST Service Event Handlers](https://github.com/oracle/bots-node-sdk/blob/master/REST_SERVCICE_EVENT_HANDLER.md) for more information. This feature is only available in the Limited Availability release of Oracle Digital Assistant version 23.06.

### Fixed Issues

- Fixed TypeScript definition of EntityValidateEvent
- Added TypeScript definition for DisambiguateItemEvemt

## Version 2.6.4 <a name="v264">

### New Features
Expand Down
127 changes: 127 additions & 0 deletions REST_SERVICE_EVENT_HANDLER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Writing REST Service Event Handlers

## Table of contents
- [Introduction](#introduction)
- [REST Service Handler Structure](#structure)
- [Using Javascript](#js)
- [Using Typescript](#ts)
- [Writing REST Service Handler Functions](#writing)
- [Supported Events](#events)

## Introduction <a name="introduction">

A REST Service Event Handler (RSEH) enables you to transform customize the REST request body before the REST call is made, and to transform the response body after the REST call is made.

<br/><br/>
The RSEH is deployed as part of a component service. The built-in Call REST component checks whether an event handler is registered
and if so, the component invokes the event handler methods to transform the request and/or response body.

## RESTService Event Handler Structure <a name="structure">

### Using Javascript <a name="js">

A REST service event handler exports two objects: the `metadata` object that provides the name of the component and the `eventHandlerType` (which should be set to `RestService`), and the `handlers` object that contains the event handler functions.

```javascript
module.exports = {
metadata: {
name: 'myRestServiceEventHandler',
eventHandlerType: 'RestService'
},
handlers: {

/**
* Handler to transform the request payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed request payload
*/
transformRequestPayload: async (event, context) => {
return event.payload;
},

/**
* Handler to transform the response payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed response payload
*/
transformResponsePayload: async (event, context) => {
return event.payload;
}
}
};
```

If needed, you can define the `metadata` and `handlers` members as functions rather than as an objects.

### Using TypeScript <a name="ts">

In TypeScript, the event handler class implements the `RestServiceEventHandler` interface. This interface requires both of the following methods:

- The `metadata` method that returns an object of type `RestServiceEventHandlerMetadata`.
- The `handlers` method that returns an object of type `RestServiceEventHandlers`.

```typescript
import { RestServiceContext, RestServiceEventHandler, RestServiceEventHandlers, RestServiceEventHandlerMetadata, TransformPayloadEvent } from '@oracle/bots-node-sdk/lib';

export class MyRestServiceEventHandler implements RestServiceEventHandler {

public metadata(): RestServiceEventHandlerMetadata {
return {
name: 'myRestServiceEventHandler',
eventHandlerType: 'RestService'
};
}

public handlers(): RestServiceEventHandlers {
return {

/**
* Handler to transform the request payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed request payload
*/
transformRequestPayload: async (event: TransformPayloadEvent, context: RestServiceContext): Promise<any> => {
return event.payload;
},

/**
* Handler to transform the response payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed response payload
*/
transformResponsePayload: async (event: TransformPayloadEvent, context: RestServiceContext): Promise<any> => {
return event.payload;
}

};
}

}
```

## Writing Event Handler Functions <a name="writing">

The first argument of each event method is the `event` object. The properties available in this object depend on the type of event.
See the [list of supported entity events](#events) for information on which properties are available with which event.

The second argument of each event method is the `context` object. This object references the [RestServiceContext](https://oracle.github.io/bots-node-sdk/RestServiceContext.html) that provides access to convenience methods you can use to create your event handler logic.

<b>TIP</b>: if you are using a JavaScript IDE like Visual Studio Code, you can get code insight and code completion support by defining the types used in the event handlers as follows in your JavaScript handler file:
```javascript
const { RestServiceContext, RestServiceEventHandler, RestServiceEventHandlers, RestServiceEventHandlerMetadata, TransformPayloadEvent } = require ('@oracle/bots-node-sdk/lib');
```
When using TypeScript, you will automatically get code completion support if your IDE supports it.

## Supported Events <a name="events">

The table below lists the event methods that can be implemented:

| Event | Description | Event Properties |
|--|--|--|
| `transformRequestPayload` | A handler that can be used to trasnform the REST request body. | <ul><li><b>payload</b>: The request body object.</li></ul>
| `transformResponsePayload` | A handler that can be used to trasnform the REST response body. | <ul><li><b>payload</b>: The response body object.</li></ul>

27 changes: 21 additions & 6 deletions bin/commands/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@ function nameOpt(name) {

function componentTypeOpt(type) {
let t = type.toLowerCase();
t = t === 'c' ? 'custom' : (t === 'e' ? 'entityeventhandler' : (t === 's' ? 'sqlqueryeventhandler' : t));
if (!~['custom', 'entityeventhandler', 'sqlqueryeventhandler'].indexOf(t)) {
throw new Error(`Invalid component type: ${type}, allowable values are [c]ustom or [e]ntityEventHandler or [s]qlQueryEventHandler..`);
if (t === 'c') {
t = 'custom';
} else if (t === 'e') {
t = 'entityeventhandler';
} else if (t === 's') {
t = 'sqlqueryeventhandler';
} else if (t === 'r') {
t = 'restserviceeventhandler';
}
if (!~['custom', 'entityeventhandler', 'sqlqueryeventhandler', 'restserviceeventhandler'].indexOf(t)) {
throw new Error(`Invalid component type: ${type}, allowable values are [c]ustom or [e]ntityEventHandler or [s]qlQueryEventHandler or [r]estServiceEventHandler.`);
}
return t;
}
Expand All @@ -42,7 +50,7 @@ class CCInit extends CommandDelegate {
.option('-r --run', 'Start service when init completes (with defaults)')
.option('-n --name <name>', 'Specify a name for the new project', null, nameOpt)
.option('-c --component-name <name>', 'Name for the first custom component', 'helloWorld', nameOpt)
.option('-t --component-type <type>', 'Specify the component type [c]ustom or [e]ntityEventHandler or [s]qlQueryEventHandler', 'custom', componentTypeOpt);
.option('-t --component-type <type>', 'Specify the component type [c]ustom or [e]ntityEventHandler or [s]qlQueryEventHandler or [r]estServiceEventHandler', 'custom', componentTypeOpt);
// add child command 'init component'
this.command.delegate(CCInitComponent, 'component');
}
Expand Down Expand Up @@ -174,7 +182,7 @@ class CCInitComponent extends CommandDelegate {
this.command
.ignore('componentName').ignore('run').ignore('skipInstall') // inherited from parent
.argument('name', 'Specify a name for the component', true, nameOpt)
.argument('type', 'Specify the component type [c]ustom or [e]ntityEventHandler or [s]qlQueryEventHandler', true, componentTypeOpt)
.argument('type', 'Specify the component type [c]ustom or [e]ntityEventHandler or [s]qlQueryEventHandler or [r]estServiceEventHandler', true, componentTypeOpt)
.argument('dest', 'Destination directory where component should be added', false)
.option('-q --quiet', 'Suppress outputs')

Expand Down Expand Up @@ -225,7 +233,14 @@ class CCInitComponent extends CommandDelegate {
if (!fs.existsSync(to)) {
let className = name.charAt(0).toUpperCase() + name.slice(1);
className = className.replace('.','');
let eventHandlerType = type === 'entityeventhandler' ? 'ResolveEntities' : 'DataQuery';
let eventHandlerType;
if (type === 'entityeventhandler') {
eventHandlerType = 'ResolveEntities';
} else if (type === 'sqlqueryeventhandler') {
eventHandlerType = 'DataQuery';
} else if (type === 'restserviceeventhandler') {
eventHandlerType = 'RestService';
}
writeTemplate(from, to, {
name,
className: className,
Expand Down
4 changes: 2 additions & 2 deletions bin/templates/components/entityeventhandler/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ module.exports = {
context.addCandidateMessages();
},
/**
* This handler is called when the composite bag entity is resolved
* This handler is called when the composite bag entity is resolved
* @param {EntityBaseEvent} event
* @param {EntityResolutionContext} context
*/
*/
resolved: async (event, context) => { // eslint-disable-line no-unused-vars
// add your back-end REST API call here
}
Expand Down
43 changes: 43 additions & 0 deletions bin/templates/components/restserviceeventhandler/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* eslint-disable no-unused-vars */

'use strict';

// Documentation for writing REST Service query event handlers: https://github.com/oracle/bots-node-sdk/blob/master/REST_SERVICE_EVENT_HANDLER.md

// You can use your favorite http client package to make REST calls, however, the node fetch API is pre-installed with the bots-node-sdk.
// Documentation can be found at https://www.npmjs.com/package/node-fetch
// Un-comment the next line if you want to make REST calls using node-fetch.
// const fetch = require("node-fetch");

module.exports = {
metadata: {
name: '{{name}}',
eventHandlerType: '{{eventHandlerType}}'
},
handlers: {

/**
* Handler to transform the request payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed request payload
*/
transformRequestPayload: async (event, context) => {
return event.payload;
},

/**
* Handler to transform the response payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed response payload
*/
transformResponsePayload: async (event, context) => {
return event.payload;
}
}
};

/* eslint-enable no-unused-vars */


50 changes: 50 additions & 0 deletions bin/templates/components/restserviceeventhandler/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { RestServiceContext
, RestServiceEventHandler
, RestServiceEventHandlers
, RestServiceEventHandlerMetadata
, TransformPayloadEvent

} from '@oracle/bots-node-sdk/lib';

// Documentation for writing SQL query event handlers: https://github.com/oracle/bots-node-sdk/blob/master/REST_SERVICE_EVENT_HANDLER.md

// You can use your favorite http client package to make REST calls, however, the node fetch API is pre-installed with the bots-node-sdk.
// Documentation can be found at https://www.npmjs.com/package/node-fetch
// Un-comment the next line if you want to make REST calls using node-fetch.
// import fetch from 'node-fetch';

export class {{className}} implements RestServiceEventHandler {

public metadata(): RestServiceEventHandlerMetadata {
return {
name: '{{name}}',
eventHandlerType: '{{eventHandlerType}}'
};
}

public handlers(): RestServiceEventHandlers {
return {

/**
* Handler to transform the request payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed request payload
*/
transformRequestPayload: async (event: TransformPayloadEvent, context: RestServiceContext): Promise<any> => {
return event.payload;
},

/**
* Handler to transform the response payload
* @param {TransformPayloadEvent} event
* @param {RestServiceContext} context
* @returns {object} the transformed response payload
*/
transformResponsePayload: async (event: TransformPayloadEvent, context: RestServiceContext): Promise<any> => {
return event.payload;
}

};
}
}
Loading

0 comments on commit 876b3b9

Please sign in to comment.