Overview

The GetHelp skill template is provided to you in ASK Extension Kit. You can use this template to help you write chat skills in PrecisionLender. You can modify the code in the template or use it as a reference when writing your skill. In this article, we'll walk through the template provided in the kit along with aspects of getHelp functionality that will apply whether you're using this template or using the 'skill' template to write your email skills.

This article assumes you have previously reviewed or have knowledge of the information contained in Navigating Your Andi® Skills Kit in the IDE and Getting Started. 

 

'GetHelp' Skill Template Code

The template skill code is written to deliver a help article from a website when a user mentions "foo deposit" while having a conversation in the Andi® window. Based on the conversation string received, Andi® determines whether or not to run the skill and return the article.

skillmanifest.json

In the template, the skillManifest contains two additional properties to the standard skillManifest properties, skillOverrides and nlpSettings. Although the template contains these settings, when writing GetHelp skills, an override is only needed if desiring to override (either fully or partially) the existing getHelpContent object created by PrecisionLender. Additionally, nlpSettings are only needed if adding additional intents for the skill to respond to beyond the getHelpContent intents.

For this template skill, the existing getHelpContent object is not the desired return result, so a skillOverride is added using the the skillOverrides property and the getHelpContent skill id entered as a string in the array.

{
	"description": "Andi New Skill",
	"locales": ["en-us"],
	"skillConfigKeys": [],
	"skillOverrides": ["8afc5e14-804f-44f0-b8cb-5693e3c4da8a"],

Next the nlpSettings are defined for the skill so that it will run based on the desired intent, otherwise the skill will not run when the intent is defined in the shouldIRun and/or run. When a user enters text in the Andi® window (a conversation event), the text will be compared to "foo deposit" entered in regexString. This is then assigned a name, the intent, which is used to store the object, intentScore for result confidence, and an nluIntentSource name of "test-intent-source".

{
    "description": "Andi New Skill",
    "locales": ["en-us"],
    "skillConfigKeys": [],
    "skillOverrides": ["8afc5e14-804f-44f0-b8cb-5693e3c4da8a"],
    "nlpSettings": {
        "regexMatches": [{
         "regexString": "foo deposit",
         "naturalLanuageUnderstandingResult":{
            "intent": "test-intent",
            "intentScore": 1,
            "nluIntentSource": "test-intent-source"
         }
        }],
        "directMatches": []
    }
}

shouldIRun.ts

In the template, the skill will serve as a partial override, allowing you to append additional information to existing getHelpContent. The shouldIRun will use the getHelpContent power to determine if based on the conversation event, the existing PrecisionLender getHelpContent should run.

return skillContext.powers.precisionLender.skills.getHelpContent.shouldIRun()
        .then((baseIShouldRunResponse) => {
        
            // return true if base conditions are met
            if (baseIShouldRunResponse.shouldIRun)
                return baseIShouldRunResponse;

Next, because the skill should also run based on the intent defined in the skillmanifest, a variable is defined that will check the top scoring intents.

// check for desired intent from desired source is the top scoring intent
            let topScoringIntent: andiSkills.INaturalLanguageUnderstandingResult = skillContext.powers.andi.chat.getTopScoringIntent();

Then, the skill should run if the top scoring intent matches the intent name and source defined in the skillmanifest so that both the response from your skill and getHelpContent will appear.

if (topScoringIntent.intent === 'test-intent' && topScoringIntent.nluIntentSource === 'test-intent-source')
                return skillContext.powers.andi.shouldIRun.shouldIRunTrue(topScoringIntent.intentScore);

Otherwise, the skill written will not run.

// return false if none of the conditions have been met
            return skillContext.powers.andi.shouldIRun.shouldIRunFalse();

In total, the shouldIRun code is as follows:

import * as andiSkills from 'andiskills';
import * as andiExternal from 'andiexternal';

// shouldIRun is used by the andi skills platform to determine if the given
// skill's current context needs to be executed. 
// this particular skill should run if the question asked in andi meets desired intent
export function shouldIRun(skillContext: andiSkills.ISkillContext): andiSkills.ShouldIRunResponse {

    return skillContext.powers.precisionLender.skills.getHelpContent.shouldIRun()
        .then((baseIShouldRunResponse) => {
        
            // return true if base conditions are met
            if (baseIShouldRunResponse.shouldIRun)
                return baseIShouldRunResponse;

            // check for desired intent from desired source is the top scoring intent
            let topScoringIntent: andiSkills.INaturalLanguageUnderstandingResult = skillContext.powers.andi.chat.getTopScoringIntent();
            
            if (topScoringIntent.intent === 'test-intent' && topScoringIntent.nluIntentSource === 'test-intent-source')
                return skillContext.powers.andi.shouldIRun.shouldIRunTrue(topScoringIntent.intentScore);

            // return false if none of the conditions have been met
            return skillContext.powers.andi.shouldIRun.shouldIRunFalse();
        });
}

run.ts 

In the run file, the template returns the promise that when getHelpContent runs, then it also responds with a new article. The new article is added by using the Andi® Chat power.As a result, when the user mentions "foo deposit" in the Andi® window, this article plus any existing getHelpContent articles on deposits will display to the user in the application.

In total, the run code is as follows:

import * as andiSkills from 'andiskills';
import * as andiExternal from 'andiexternal';

// this is main execution of the skill which is called after the andi
// skills platforms determines if it should run
// this particular skill returns an article specified via a url
export function run(skillContext: andiSkills.ISkillContext): andiSkills.RunResponse {
    
    return skillContext.powers.precisionLender.skills.getHelpContent
        .run()
        .then((response) => {
            let text = "Here is a custom article on deposits";
            let url = "http://google.com";

            // add an article to the message
            skillContext.powers.andi.chat.addArticle(text, url, response, "First");

            return response;
        });
}

 

'GetHelp' Skill Template Code - Mocha Test

Mocha unit tests, while a good practice, are not required and will typically be utilized by skill writers with more programming experience.

shouldIRun.spec.ts 

The first unit test verifies that if a conversation event occurs, then the skill should run.

The second unit test verifies that if a conversation event occurs that is not the test-intent, then the skill should not run.

The third unit test verifies that if a conversation event occurs where the nluIntentSource is not the test-intent-source, then the skill should not run.

import * as assert from 'assert';
import { shouldIRun } from '../shouldIRun';
import * as andiSkills from 'andiskills';
import * as andiExternal from 'andiexternal';

describe("Get Help Skill ShouldIRun Tests", () => {
    
    it("A Conversational event should run", (done) => {
        // get the mock that contains a conversational event with a naturalLanguageUnderstandingResult that matches the intent checks in ShouldIRun
        let skillContext: andiSkills.ISkillContext = andiExternal.MockSkillContextBuilder
            .forPrecisionLenderChat()
            .build();
        
        andiExternal.ShouldIRunScenario
            .forGiven(skillContext)
            .execute(shouldIRun)
            .then((result) => {
                assert.equal(result,true);
                done();
            });

    })

    it("A Conversational event with an intent that is not test-intent should not run", (done) => {        
        let skillContext: andiSkills.ISkillContext = andiExternal.MockSkillContextBuilder
            .forPrecisionLenderChat()
            .setDefaultPLGetHelpContextShouldIRun(false)
            .addNaturalLanguageUnderstandingResult({intent: "fake-intent", intentScore:1, nluIntentSource: "test-intent-source"})
            .build();
        
        andiExternal.ShouldIRunScenario
            .forGiven(skillContext)
            .execute(shouldIRun)
            .then((result) => {
                assert.equal(result,false);
                done();
            });

    })

    it("A Conversational event with a nluIntentSource that is not test-intent-source should not run", (done) => {

        let skillContext: andiSkills.ISkillContext = andiExternal.MockSkillContextBuilder
            .forPrecisionLenderChat()
            .setDefaultPLGetHelpContextShouldIRun(false)
            .addNaturalLanguageUnderstandingResult({intent: "test-intent", intentScore:1, nluIntentSource: "fake-source"})
            .build();
        
        andiExternal.ShouldIRunScenario
            .forGiven(skillContext)
            .execute(shouldIRun)
            .then((result) => {
                assert.equal(result,false,"Top scoring nluIntentSource is not test-intent-source")
                done();
            });

    })
});

run.spec.ts 

This unit test verifies that the message for the run function matches the expected value.

import * as assert from 'assert';
import { run } from '../run';
import * as andiSkills from 'andiskills';
import * as andiExternal from 'andiexternal';

describe("Get Help Skill Run Tests", () => {

    it("Question (rawText) condition in the skill matches. Result returned contains expected article.", (done) => {
        
        let skillContext: andiSkills.ISkillContext = andiExternal.MockSkillContextBuilder
            .forPrecisionLenderChat()            
            .build();
        
        let expected: andiSkills.AndiBotResponseModel = { attachments: [{ articles: [] }] };

        andiExternal.RunScenario
            .forGiven(skillContext)
            .execute(run)
            .then((result) => {
                var msg = result.message.message as any;
                assert.deepEqual(msg, expected);
                done();
            });

    });

});

 

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