In this tutorial, we want to show you how to develop your first Extension, which you can upload and install in your existing Cognigy.AI agent.

Requirements

However, in order to start this tutorial, you need the following requirements:

  • Basic TypeScript / JavaScript knowledge
  • Version 16.4.xx of Node.js for building extensions
  • A code editor
  • An existing Cogngiy.AI agent
    • If you don't have an agent yet but want to familiarize yourself with Cognigy, we recommend registering in our Free Trial Cloud. It is totally free and the best way to get in touch with our product.

1. Create the module structure

Every Extension has the same folder and file structure:

module-name/
    README.md
    src/
        nodes/
            reverseSay.ts
connections/
moduleConnection.ts module.ts package.json package-lock.json tslint.json tsconfig.json icon.png

This structure includes all the required resources to build and upload the Extension to Cognigy.AI. The README.md is used to show the code's content. Thus, other developers or interested users can get familiar with the functionality. The entire source code of our exposed Flow Nodes is located in the src/nodes/ folder, in which the next four files (package.json, package-lock.json, tslint.json, tsconfig.json) are used to create the Javascript module and check it for mistakes. The icon is required to show the module's logo in Cognigy. In most cases, the icon shows the logo of the third-party software product which we are integrating with.

Notes:

  • The icon.png needs to have the following dimensions:
    • 64x64 Pixels

The example structure can be copied from the Extension Example.

2. Develop an Extension

We want to introduce you to these new concepts now.

Install NPM @cognigy/extension-tools

In order to provide all functions and types to create and develop an Extension, we published the '@cognigy/extension-tools' NPM package. Therefore, please install it globally on your computer:

  • npm i -g @cognigy/extension-tools

Use the createNodeDescriptor() Method

The method createNodeDescriptor is one of the most central methods exposed by the 'extension-tools' package. If one wants to build a new Extension, we advice to put the source code of a single Flow Node into a separate file, unless you are crafting nodes that contain child-nodes.

Defining a node essentially looks like this (you can find this example in 'example/src/nodes/reverseSay):

import { createNodeDescriptor, INodeFunctionBaseParams } from "@cognigy/extension-tools";

// The interface defines which values the Extension can use in the function below.
export interface IReverseSayParams extends INodeFunctionBaseParams {
	config: {
		text: string;
	}
}

export const reverseSay = createNodeDescriptor({
	type: "reverseSay",
	defaultLabel: "Simple Reverse Say",
	fields: [
		{
			key: "text",
			label: "The text you want to reverse.",
			type: "cognigyText",
			params: {
				required: true
			}
		}
	],

	function: async ({ cognigy, config }: IReverseSayParams) => {
		const { api } = cognigy;
		const { text } = config;

		// Reverse the input text
		const reversedText = text.split("").reverse().join();

		// Execute a SAY Node to output the reversed text to the user
		api.say(reversedText);
	}
});

Let's analyze the different pieces we can see in the code window above:

import { createNodeDescriptor, INodeFunctionBaseParams } from "@cognigy/extension-tools";

Here, we are just importing the createNodeDescriptor method from the extension-tools package. We are also importing a Typescript interface we want to use.

export interface IReverseSayParams extends INodeFunctionBaseParams {
	config: {
		text: string;
	}
}

In this part of the code, we are crafting a new Typescript interface for the config (the arguments) of the new Flow Node. We advise you to do this for your nodes, as you will have a better developer experience when you are actually creating the code (aka the function) of your Flow Node. Make sure that you extend on our INodeFunctionBaseParams interface - this will give you access to:

  • cognigy object with sub-properties:
    • api: This exposes the API your Flow Node can use.
    • input: The Cognigy Input Object, this is a proxy so you can set/get values.
    • context: The Cognigy Context Object is a proxy, so you can set/get values.
    • profile: The Cognigy Contact Profile Object is a proxy, so you can set/get values.
  • nodeId: The actual id of the node that is being executed
  • config: This is the config/arguments of your node - that's why you should overwrite this in your own Interface
  • childConfigs[]: These are the config objects of all children in case your node has children
export const reverseSay = createNodeDescriptor({
	type: "reverseSay",
	defaultLabel: "Simple Reverse Say",
	fields: [
		{
			key: "text",
			label: "The text you want to reverse.",
			type: "cognigyText",
			params: {
				required: true
			}
		}
	],
	fields: [
		{
			key: "text",
			label: "The text you want to reverse.",
			type: "cognigyText"
		}
	],

	function: async ({ cognigy, config }: IReverseSayParams) => {
		const { api } = cognigy;
		const { text } = config;

		// Reverse the input text
		const reversedText = text.split("").reverse().join();

		// Execute a SAY Node to output the reversed text to the user
		api.say(reversedText);
	}
});

Additional Definitions

Now comes the actual definition & implementation of your Flow Node. You essentially pass in an object into createNodeDescriptorand it will create a full node descriptor for you. The method will fill up properties you don't set with safe default values. Let's discuss some of the properties you have to set:

  • type: This is the type of your node. It needs to be a unique string in your Extension.
  • defaults: These are the default values for your Node. If a new Flow Node gets created, it will get these defaults. You must set the label and the config object.
  • fields: This section defines the user interface that will be generated for your node-config. You have to add a field definition per key in your config object. You reference the key in your config using the key property in the field definition. The label is used in the UI as well. The type gives you a variety of possibilities - you can, e.g., say that your field should be of type cognigyText or, e.g., of type JSON or toggle.
  • function: This actually contains the code of your Flow Node. Ensure that you add the async keyword. The execution engine will always await  the execution of your node. We have full Typescript support, please e.g. check the typings of the cognigy object as we don't have full documentation, yet.

createExtension

Whereas the createNodeDescriptor function essentially just fills up default values for your Flow Node, it's the createExtension method's job to bundle all nodes and connection definitions into one large object, which will then be passed into the Cognigy.AI system.

Make sure that you are using the default export syntax for the createExtension's return value, as we need to be able to find the complete object.

I suggest that you always create a module.ts file which essentially looks like the one in example/src/module.ts. Please only import all nodes and connections into this file and assign them to the payload you pass into the create Extension method.

Connections

In Cognigy 3 we have introduced the concept of Secrets which allows you to store configuration in a secure way. Secrets no longer directly exist in Cognigy 4 but were replaced with Connections.

The new part is that there is a strong relationship between a Flow Node that needs a connection and the connection itself. Connections are essentially Secrets and store key/value pairs - so-called fields in an encrypted way.

If you want to use a connection within a node, you have to do the following:

  • add a field with type: connection to your Flow Node; you can see this in 'example/src/nodes/executeCognigyApiRequest.ts'
    {
        key: "connection",
        label: "The api-key connection which should be used.",
        type: "connection",
        params: {
            connectionType: "api-key" // this needs to match the connections 'type' property
        }
    }
  • create a connection definition, see 'example/src/connections/'
  • add the connection into your createExtensions call - if you miss it there, it will not be there.

You have to ensure that the params.connectionType in your Flow Node field definition maps to a connection and a proper type of the connection. You can define multiple connections within a single Extension, and the type field is used to find the correct connections that satisfy the fields your node requires.

After developing your first Extension, it can be installed in your Cognigy environment.


Comments

1 comment

Please sign in to leave a comment.

Was this article helpful?
0 out of 0 found this helpful