botium-core 1.13.0 → 1.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +6 -3
- package/dist/botium-cjs.js +305 -123
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +323 -142
- package/dist/botium-es.js.map +1 -1
- package/package.json +17 -15
- package/src/Capabilities.js +2 -1
- package/src/containers/plugins/SimpleRestContainer.js +23 -16
- package/src/grid/inbound/proxy.js +2 -1
- package/src/helpers/RetryHelper.js +13 -7
- package/src/scripting/Convo.js +36 -10
- package/src/scripting/MatchFunctions.js +10 -0
- package/src/scripting/ScriptingProvider.js +106 -37
- package/src/scripting/logichook/LogicHookConsts.js +1 -1
- package/src/scripting/logichook/LogicHookUtils.js +1 -1
- package/src/scripting/logichook/asserter/WerAsserter.js +59 -0
- package/src/scripting/logichook/logichooks/UpdateCustomLogicHook.js +3 -2
- package/test/compiler/compilercsv.spec.js +104 -3
- package/test/compiler/compilerjson.spec.js +0 -2
- package/test/compiler/compilerxlsx.spec.js +1 -1
- package/test/compiler/convos/csv/utterances_liveperson2.csv +12 -0
- package/test/connectors/simplerest.spec.js +1012 -969
- package/test/convo/fillAndApplyScriptingMemory.spec.js +804 -785
- package/test/convo/partialconvo.spec.js +345 -339
- package/test/convo/retryconvo.spec.js +134 -0
- package/test/driver/capabilities.spec.js +156 -151
- package/test/logichooks/hookfromsrc.spec.js +79 -73
- package/test/plugins/plugins.spec.js +44 -42
- package/test/scripting/asserters/buttonsAsserter.spec.js +257 -240
- package/test/scripting/asserters/cardsAsserter.spec.js +214 -212
- package/test/scripting/asserters/convos/wer_threshold_nok.yml +7 -0
- package/test/scripting/asserters/convos/wer_threshold_ok.yml +7 -0
- package/test/scripting/asserters/intentConfidenceAsserter.spec.js +34 -35
- package/test/scripting/asserters/jsonpathAsserter.spec.js +307 -308
- package/test/scripting/asserters/mediaAsserter.spec.js +236 -234
- package/test/scripting/asserters/werAsserter.spec.js +51 -0
- package/test/scripting/logichooks/setClearScriptingMemory.spec.js +202 -192
- package/test/scripting/matching/matchingmode.spec.js +306 -258
- package/test/scripting/scriptingProvider.spec.js +666 -633
- package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +299 -281
- package/test/scripting/scriptingmemory/useScriptingMemoryForAssertion.spec.js +94 -80
- package/test/scripting/userinputs/defaultUserInputs.spec.js +233 -127
- package/test/scripting/userinputs/mediaInputConvos.spec.js +409 -403
- package/test/scripting/utteranceexpansion/associateByIndex.spec.js +259 -0
- package/test/scripting/utteranceexpansion/convos/associate_utterances_by_index.json +33 -0
- package/test/scripting/utteranceexpansion/convos/media.convo.txt +19 -0
- package/test/scripting/utteranceexpansion/files/step0voice0.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step0voice1.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step0voice2.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step1voice0.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step2voice0.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step2voice1.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step2voice2.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step2voice4.wav +0 -0
- package/test/scripting/utteranceexpansion/files/step2voice5.wav +0 -0
- package/test/security/allowUnsafe.spec.js +274 -268
- package/test/utils.spec.js +40 -38
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// const _ = require('lodash')
|
|
2
|
+
const speechScorer = require('word-error-rate')
|
|
3
|
+
const { BotiumError } = require('../../BotiumError')
|
|
4
|
+
|
|
5
|
+
module.exports = class WerAsserter {
|
|
6
|
+
constructor (context, caps = {}) {
|
|
7
|
+
this.context = context
|
|
8
|
+
this.caps = caps
|
|
9
|
+
this.name = 'WerAsserter'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
assertConvoStep ({ convo, convoStep, args, botMsg }) {
|
|
13
|
+
if (!args || args.length < 1) {
|
|
14
|
+
return Promise.reject(new BotiumError(`${convoStep.stepTag}: WerAsserter Missing argument`,
|
|
15
|
+
{
|
|
16
|
+
type: 'asserter',
|
|
17
|
+
subtype: 'wrong parameters',
|
|
18
|
+
source: this.name,
|
|
19
|
+
cause: { args }
|
|
20
|
+
}
|
|
21
|
+
))
|
|
22
|
+
}
|
|
23
|
+
if (args.length > 2) {
|
|
24
|
+
return Promise.reject(new BotiumError(`${convoStep.stepTag}: WerAsserter Too much argument "${args}"`,
|
|
25
|
+
{
|
|
26
|
+
type: 'asserter',
|
|
27
|
+
subtype: 'wrong parameters',
|
|
28
|
+
source: this.name,
|
|
29
|
+
cause: { args }
|
|
30
|
+
}
|
|
31
|
+
))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const utterance = args[0]
|
|
35
|
+
const threshold = args[1]
|
|
36
|
+
|
|
37
|
+
const wer = speechScorer.wordErrorRate(botMsg.messageText, utterance)
|
|
38
|
+
if (wer > threshold) {
|
|
39
|
+
return Promise.reject(new BotiumError(
|
|
40
|
+
`${convoStep.stepTag}: Word error rate ${wer} > ${threshold} for ${utterance}`,
|
|
41
|
+
{
|
|
42
|
+
type: 'asserter',
|
|
43
|
+
source: this.name,
|
|
44
|
+
context: {
|
|
45
|
+
params: {
|
|
46
|
+
args
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
cause: {
|
|
50
|
+
expected: `Word error rate <= ${threshold}`,
|
|
51
|
+
actual: `Word error rate = ${wer}`
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return Promise.resolve()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const util = require('util')
|
|
2
2
|
const _ = require('lodash')
|
|
3
|
+
const { ConvoStepLogicHook } = require('../../Convo')
|
|
3
4
|
|
|
4
5
|
module.exports = class UpdateCustomLogicHook {
|
|
5
6
|
constructor (context, caps = {}, globalArgs = {}) {
|
|
@@ -14,10 +15,10 @@ module.exports = class UpdateCustomLogicHook {
|
|
|
14
15
|
const validConvoSteps = convo.conversation.filter(s => s.sender === 'me')
|
|
15
16
|
for (const convoStep of validConvoSteps) {
|
|
16
17
|
convoStep.logicHooks = (convoStep.logicHooks || [])
|
|
17
|
-
convoStep.logicHooks.push({
|
|
18
|
+
convoStep.logicHooks.push(new ConvoStepLogicHook({
|
|
18
19
|
name: 'UPDATE_CUSTOM',
|
|
19
20
|
args
|
|
20
|
-
})
|
|
21
|
+
}))
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -24,6 +24,41 @@ const buildContext = () => {
|
|
|
24
24
|
return result
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const assertLivepersonV2 = (context) => {
|
|
28
|
+
assert.lengthOf(context.utterances, 4)
|
|
29
|
+
assert.lengthOf(context.convos, 0)
|
|
30
|
+
assert.deepEqual(context.utterances[0], {
|
|
31
|
+
name: 'Cancel Pre-Authorized Payment',
|
|
32
|
+
utterances: [
|
|
33
|
+
'Can I call back to re-start the payment',
|
|
34
|
+
'Can I stop a direct debit',
|
|
35
|
+
'Can you cancel a preauthorized payment for me',
|
|
36
|
+
'Can you help me cancel my pre authorized payment'
|
|
37
|
+
]
|
|
38
|
+
})
|
|
39
|
+
assert.deepEqual(context.utterances[1], {
|
|
40
|
+
name: 'Payee - Correct/Modify',
|
|
41
|
+
utterances: [
|
|
42
|
+
'Can I modify my existing payee?',
|
|
43
|
+
'Can you change the name of the payee?'
|
|
44
|
+
]
|
|
45
|
+
})
|
|
46
|
+
assert.deepEqual(context.utterances[2], {
|
|
47
|
+
name: 'Pre-Authorized Payment - Correct/Modify',
|
|
48
|
+
utterances: [
|
|
49
|
+
'Can I delay my payment to (company)?'
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
assert.deepEqual(context.utterances[3], {
|
|
53
|
+
name: 'E-Transfer Recipient – Delete',
|
|
54
|
+
utterances: [
|
|
55
|
+
'Can you delete my friend as an e-transfer recipient?',
|
|
56
|
+
'Can you delete this e-transfer recipient',
|
|
57
|
+
'Can you delete this recipient'
|
|
58
|
+
]
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
27
62
|
describe('compiler.compilercsv', function () {
|
|
28
63
|
describe('ROW_PER_MESSAGE mode, full', function () {
|
|
29
64
|
it('should read basic case', async function () {
|
|
@@ -357,7 +392,7 @@ describe('compiler.compilercsv', function () {
|
|
|
357
392
|
assert.equal(err.message, 'Failed to parse conversation. Section "goodbye" unknown.')
|
|
358
393
|
}
|
|
359
394
|
})
|
|
360
|
-
it('should not parse multi column uttrances as convos ???', async function () {
|
|
395
|
+
it('should not parse multi column uttrances as convos ??? 2', async function () {
|
|
361
396
|
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_multicolumn5col.csv'))
|
|
362
397
|
const context = buildContext()
|
|
363
398
|
|
|
@@ -459,7 +494,6 @@ describe('compiler.compilercsv', function () {
|
|
|
459
494
|
]
|
|
460
495
|
})
|
|
461
496
|
})
|
|
462
|
-
// maybe we could read it
|
|
463
497
|
it('should read liveperson format with SCRIPTING_CSV_STARTROW', async function () {
|
|
464
498
|
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_liveperson.csv'))
|
|
465
499
|
const context = buildContext()
|
|
@@ -482,6 +516,20 @@ describe('compiler.compilercsv', function () {
|
|
|
482
516
|
]
|
|
483
517
|
})
|
|
484
518
|
})
|
|
519
|
+
it('should read liveperson format 2 with SCRIPTING_CSV_STARTROW', async function () {
|
|
520
|
+
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_liveperson2.csv'))
|
|
521
|
+
const context = buildContext()
|
|
522
|
+
|
|
523
|
+
const caps = {
|
|
524
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW]: 9,
|
|
525
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY]: true,
|
|
526
|
+
[Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF]: true
|
|
527
|
+
}
|
|
528
|
+
const compiler = new Compiler(context, Object.assign({}, DefaultCapabilities, caps))
|
|
529
|
+
|
|
530
|
+
compiler.Compile(scriptBuffer, 'SCRIPTING_TYPE_UTTERANCES')
|
|
531
|
+
assertLivepersonV2(context)
|
|
532
|
+
})
|
|
485
533
|
it('should read liveperson format with SCRIPTING_CSV_STARTROW without stop', async function () {
|
|
486
534
|
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_liveperson.csv'))
|
|
487
535
|
const context = buildContext()
|
|
@@ -501,7 +549,45 @@ describe('compiler.compilercsv', function () {
|
|
|
501
549
|
const context = buildContext()
|
|
502
550
|
|
|
503
551
|
const caps = {
|
|
504
|
-
[Capabilities.
|
|
552
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER]: 'SampleSentences',
|
|
553
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY]: true,
|
|
554
|
+
[Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF]: true
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const compiler = new Compiler(context, Object.assign({}, DefaultCapabilities, caps))
|
|
558
|
+
|
|
559
|
+
compiler.Compile(scriptBuffer, 'SCRIPTING_TYPE_UTTERANCES')
|
|
560
|
+
assert.lengthOf(context.utterances, 18)
|
|
561
|
+
assert.lengthOf(context.convos, 0)
|
|
562
|
+
assert.deepEqual(context.utterances[0], {
|
|
563
|
+
name: 'ask about installation',
|
|
564
|
+
utterances: [
|
|
565
|
+
'about my appointment',
|
|
566
|
+
'book service installation appointment'
|
|
567
|
+
]
|
|
568
|
+
})
|
|
569
|
+
})
|
|
570
|
+
it('should read liveperson format 2 with SCRIPTING_CSV_STARTROWHEADER', async function () {
|
|
571
|
+
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_liveperson2.csv'))
|
|
572
|
+
const context = buildContext()
|
|
573
|
+
|
|
574
|
+
const caps = {
|
|
575
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER]: 'SampleSentences',
|
|
576
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY]: true,
|
|
577
|
+
[Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF]: true
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const compiler = new Compiler(context, Object.assign({}, DefaultCapabilities, caps))
|
|
581
|
+
|
|
582
|
+
compiler.Compile(scriptBuffer, 'SCRIPTING_TYPE_UTTERANCES')
|
|
583
|
+
assertLivepersonV2(context)
|
|
584
|
+
})
|
|
585
|
+
it('should read liveperson format with SCRIPTING_CSV_STARTROWHEADER 2', async function () {
|
|
586
|
+
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_liveperson.csv'))
|
|
587
|
+
const context = buildContext()
|
|
588
|
+
|
|
589
|
+
const caps = {
|
|
590
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER]: 'SampleSentences',
|
|
505
591
|
[Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY]: true,
|
|
506
592
|
[Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF]: true
|
|
507
593
|
}
|
|
@@ -519,6 +605,21 @@ describe('compiler.compilercsv', function () {
|
|
|
519
605
|
]
|
|
520
606
|
})
|
|
521
607
|
})
|
|
608
|
+
it('should read liveperson format 2 with SCRIPTING_CSV_STARTROWHEADER 2', async function () {
|
|
609
|
+
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_liveperson2.csv'))
|
|
610
|
+
const context = buildContext()
|
|
611
|
+
|
|
612
|
+
const caps = {
|
|
613
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER]: 'SampleSentences',
|
|
614
|
+
[Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY]: true,
|
|
615
|
+
[Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF]: true
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const compiler = new Compiler(context, Object.assign({}, DefaultCapabilities, caps))
|
|
619
|
+
|
|
620
|
+
compiler.Compile(scriptBuffer, 'SCRIPTING_TYPE_UTTERANCES')
|
|
621
|
+
assertLivepersonV2(context)
|
|
622
|
+
})
|
|
522
623
|
it('should work with variable length csv', async function () {
|
|
523
624
|
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'utterances_variable_row_len.csv'))
|
|
524
625
|
const context = buildContext()
|
|
@@ -109,9 +109,7 @@ describe('compiler.compilerjson', function () {
|
|
|
109
109
|
assert.equal(context.scriptingMemories[0].header.name, 'scenario1')
|
|
110
110
|
assert.equal(context.scriptingMemories[0].values.$var1, 'var1_1')
|
|
111
111
|
})
|
|
112
|
-
})
|
|
113
112
|
|
|
114
|
-
describe('compiler.decompilerjson', function () {
|
|
115
113
|
it('should decompile convos', async function () {
|
|
116
114
|
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'convos_and_utterances.json'))
|
|
117
115
|
const context = buildContext()
|
|
@@ -473,7 +473,7 @@ describe('compiler.compilerxlsx', function () {
|
|
|
473
473
|
|
|
474
474
|
assert.lengthOf(context.utterances, 0)
|
|
475
475
|
})
|
|
476
|
-
it('should read 3 convos without name (forced)', async function () {
|
|
476
|
+
it('should read 3 convos without name (forced) 2', async function () {
|
|
477
477
|
const scriptBuffer = fs.readFileSync(path.resolve(__dirname, CONVOS_DIR, 'convos_2convos_without_names_noheader.xlsx'))
|
|
478
478
|
const context = buildContext()
|
|
479
479
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Cancel Pre-Authorized Payment,Payee - Correct/Modify,Pre-Authorized Payment - Correct/Modify,E-Transfer Recipient – Delete
|
|
2
|
+
DisplayName,DisplayName,DisplayName,DisplayName
|
|
3
|
+
Cancel Pre-Authorized Payment,Payee - Correct/Modify,Pre-Authorized Payment - Correct/Modify,E-Transfer Recipient – Delete
|
|
4
|
+
KeyPhrases,KeyPhrases,KeyPhrases,KeyPhrases
|
|
5
|
+
,,,
|
|
6
|
+
MetaIntent,MetaIntent,MetaIntent,MetaIntent
|
|
7
|
+
,,,
|
|
8
|
+
SampleSentences,SampleSentences,SampleSentences,SampleSentences
|
|
9
|
+
Can I call back to re-start the payment,Can I modify my existing payee?,Can I delay my payment to (company)?,Can you delete my friend as an e-transfer recipient?
|
|
10
|
+
Can I stop a direct debit,Can you change the name of the payee?,,Can you delete this e-transfer recipient
|
|
11
|
+
Can you cancel a preauthorized payment for me,,,Can you delete this recipient
|
|
12
|
+
Can you help me cancel my pre authorized payment,,,
|