botium-core 1.13.4 → 1.13.6
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/dist/botium-cjs.js +262 -88
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +262 -88
- package/dist/botium-es.js.map +1 -1
- package/package.json +19 -19
- package/src/helpers/RetryHelper.js +3 -2
- package/src/scripting/CompilerXlsx.js +1 -0
- package/src/scripting/MatchFunctions.js +3 -1
- package/src/scripting/ScriptingMemory.js +41 -2
- package/src/scripting/ScriptingProvider.js +164 -56
- package/src/scripting/helper.js +2 -0
- package/src/scripting/logichook/asserter/BotRepliesConsumedAsserter.js +1 -1
- package/src/scripting/logichook/asserter/BotRepliesUnconsumedCountAsserter.js +1 -1
- package/src/scripting/logichook/asserter/ButtonsAsserter.js +1 -1
- package/src/scripting/logichook/asserter/ButtonsCountAsserter.js +1 -1
- package/src/scripting/logichook/asserter/ButtonsCountRecAsserter.js +1 -1
- package/src/scripting/logichook/asserter/CardsAsserter.js +1 -1
- package/src/scripting/logichook/asserter/CardsCountAsserter.js +1 -1
- package/src/scripting/logichook/asserter/CardsCountRecAsserter.js +1 -1
- package/src/scripting/logichook/asserter/EntitiesAsserter.js +1 -1
- package/src/scripting/logichook/asserter/EntityContentAsserter.js +2 -2
- package/src/scripting/logichook/asserter/EntityValuesAsserter.js +1 -1
- package/src/scripting/logichook/asserter/FormsAsserter.js +1 -1
- package/src/scripting/logichook/asserter/IntentAsserter.js +3 -3
- package/src/scripting/logichook/asserter/IntentConfidenceAsserter.js +4 -4
- package/src/scripting/logichook/asserter/IntentUniqueAsserter.js +2 -2
- package/src/scripting/logichook/asserter/JsonPathAsserter.js +5 -5
- package/src/scripting/logichook/asserter/JsonPathCountAsserter.js +2 -2
- package/src/scripting/logichook/asserter/MediaAsserter.js +1 -1
- package/src/scripting/logichook/asserter/MediaCountAsserter.js +1 -1
- package/src/scripting/logichook/asserter/MediaCountRecAsserter.js +1 -1
- package/src/scripting/logichook/asserter/PauseAsserter.js +1 -1
- package/src/scripting/logichook/asserter/ResponseLengthAsserter.js +3 -2
- package/src/scripting/logichook/asserter/TextContainsAllAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextContainsAllICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextContainsAnyAsserter.js +1 -0
- package/src/scripting/logichook/asserter/TextContainsAnyICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextEqualsAnyAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextEqualsAnyICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextRegexpAllAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextRegexpAllICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextRegexpAnyAsserter.js +1 -0
- package/src/scripting/logichook/asserter/TextRegexpAnyICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextWildcardAllAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextWildcardAllICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextWildcardAnyAsserter.js +1 -0
- package/src/scripting/logichook/asserter/TextWildcardAnyICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextWildcardExactAllAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextWildcardExactAllICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/TextWildcardExactAnyAsserter.js +1 -0
- package/src/scripting/logichook/asserter/TextWildcardExactAnyICAsserter.js +2 -1
- package/src/scripting/logichook/asserter/WerAsserter.js +10 -8
- package/src/scripting/logichook/userinput/MediaInput.js +2 -1
- package/test/compiler/compilercsv.spec.js +9 -2
- package/test/compiler/convos/csv/utterances_variable_row_len.csv +1 -1
- package/test/convo/fillAndApplyScriptingMemory.spec.js +64 -4
- package/test/convo/transcript.spec.js +15 -6
- package/test/scripting/asserters/convos/{wer_threshold_nok.yml → wer_threshold_nok_float.yml} +0 -0
- package/test/scripting/asserters/convos/wer_threshold_nok_percentage.yml +7 -0
- package/test/scripting/asserters/convos/{wer_threshold_ok.yml → wer_threshold_ok_float.yml} +0 -0
- package/test/scripting/asserters/convos/wer_threshold_ok_percentage.yml +7 -0
- package/test/scripting/asserters/entityContentAsserter.spec.js +2 -7
- package/test/scripting/asserters/intentAsserter.spec.js +1 -1
- package/test/scripting/asserters/intentConfidenceAsserter.spec.js +3 -7
- package/test/scripting/asserters/jsonpathAsserter.spec.js +1 -1
- package/test/scripting/asserters/werAsserter.spec.js +25 -5
- package/test/scripting/matching/matchingmode.spec.js +42 -2
- package/test/scripting/scriptingModificator.spec.js +1 -2
- package/test/scripting/scriptingProvider.spec.js +156 -4
- package/test/scripting/utteranceexpansion/associateByIndex.spec.js +15 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botium-core",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.6",
|
|
4
4
|
"description": "The Selenium for Chatbots",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/botium-es.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://www.botium.ai",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@babel/runtime": "^7.
|
|
35
|
+
"@babel/runtime": "^7.19.0",
|
|
36
36
|
"async": "^3.2.4",
|
|
37
37
|
"body-parser": "^1.20.0",
|
|
38
38
|
"boolean": "^3.2.0",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"esprima": "^4.0.1",
|
|
43
43
|
"express": "^4.18.1",
|
|
44
44
|
"globby": "11.0.4",
|
|
45
|
-
"ioredis": "^5.
|
|
45
|
+
"ioredis": "^5.2.3",
|
|
46
46
|
"is-class": "^0.0.9",
|
|
47
47
|
"is-json": "^2.0.1",
|
|
48
48
|
"jsonpath": "^1.1.1",
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
"rimraf": "^3.0.2",
|
|
60
60
|
"sanitize-filename": "^1.6.3",
|
|
61
61
|
"slugify": "^1.6.5",
|
|
62
|
-
"socket.io": "^4.5.
|
|
63
|
-
"socket.io-client": "^4.5.
|
|
62
|
+
"socket.io": "^4.5.2",
|
|
63
|
+
"socket.io-client": "^4.5.2",
|
|
64
64
|
"socketio-auth": "^0.1.1",
|
|
65
|
-
"swagger-jsdoc": "^6.2.
|
|
66
|
-
"swagger-ui-express": "^4.
|
|
67
|
-
"uuid": "^
|
|
68
|
-
"vm2": "^3.9.
|
|
65
|
+
"swagger-jsdoc": "^6.2.5",
|
|
66
|
+
"swagger-ui-express": "^4.5.0",
|
|
67
|
+
"uuid": "^9.0.0",
|
|
68
|
+
"vm2": "^3.9.11",
|
|
69
69
|
"word-error-rate": "0.0.7",
|
|
70
70
|
"write-yaml": "^1.0.0",
|
|
71
71
|
"xlsx": "^0.18.5",
|
|
@@ -73,27 +73,27 @@
|
|
|
73
73
|
"yaml": "^2.1.1"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@babel/core": "^7.
|
|
77
|
-
"@babel/node": "^7.
|
|
78
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
79
|
-
"@babel/preset-env": "^7.
|
|
76
|
+
"@babel/core": "^7.19.3",
|
|
77
|
+
"@babel/node": "^7.19.1",
|
|
78
|
+
"@babel/plugin-transform-runtime": "^7.19.1",
|
|
79
|
+
"@babel/preset-env": "^7.19.3",
|
|
80
80
|
"chai": "^4.3.6",
|
|
81
81
|
"chai-as-promised": "^7.1.1",
|
|
82
82
|
"cross-env": "^7.0.3",
|
|
83
|
-
"eslint": "^8.
|
|
83
|
+
"eslint": "^8.24.0",
|
|
84
84
|
"eslint-config-standard": "^17.0.0",
|
|
85
85
|
"eslint-plugin-import": "^2.26.0",
|
|
86
86
|
"eslint-plugin-mocha": "^10.1.0",
|
|
87
|
-
"eslint-plugin-n": "^15.
|
|
88
|
-
"eslint-plugin-promise": "^6.0.
|
|
87
|
+
"eslint-plugin-n": "^15.3.0",
|
|
88
|
+
"eslint-plugin-promise": "^6.0.1",
|
|
89
89
|
"eslint-plugin-standard": "^4.1.0",
|
|
90
90
|
"license-checker": "^25.0.1",
|
|
91
91
|
"license-compatibility-checker": "^0.3.5",
|
|
92
92
|
"mocha": "^10.0.0",
|
|
93
|
-
"nock": "^13.2.
|
|
94
|
-
"npm-check-updates": "^
|
|
93
|
+
"nock": "^13.2.9",
|
|
94
|
+
"npm-check-updates": "^16.3.4",
|
|
95
95
|
"nyc": "^15.1.0",
|
|
96
|
-
"rollup": "^2.
|
|
96
|
+
"rollup": "^2.79.1",
|
|
97
97
|
"rollup-plugin-babel": "^4.4.0",
|
|
98
98
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
99
99
|
"rollup-plugin-json": "^4.0.0",
|
|
@@ -25,8 +25,9 @@ module.exports = class RetryHelper {
|
|
|
25
25
|
factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (_.isNil(options.factor) ? 1 : options.factor),
|
|
26
26
|
minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (_.isNil(options.minTimeout) ? 1000 : options.minTimeout)
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
if (this.retrySettings.retries > 0) {
|
|
29
|
+
debug(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`)
|
|
30
|
+
}
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
shouldRetry (err) {
|
|
@@ -256,6 +256,7 @@ module.exports = class CompilerXlsx extends CompilerBase {
|
|
|
256
256
|
if (!convo.header.name) {
|
|
257
257
|
convo.header.name = `${convo.header.sheetname}-${this.colnames[convo.header.colindex]}${formatRowIndex(convo.header.rowindex)}`
|
|
258
258
|
}
|
|
259
|
+
// it is not used anymore?
|
|
259
260
|
convo.header.sort = convo.header.name
|
|
260
261
|
scriptResults.push(convo)
|
|
261
262
|
})
|
|
@@ -83,7 +83,9 @@ const equals = (ignoreCase) => (botresponse, utterance) => {
|
|
|
83
83
|
const wer = () => (botresponse, utterance, args) => {
|
|
84
84
|
botresponse = _normalize(botresponse || '')
|
|
85
85
|
utterance = toString(utterance || '')
|
|
86
|
-
|
|
86
|
+
|
|
87
|
+
const threshold = ([',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100)
|
|
88
|
+
return speechScorer.wordErrorRate(botresponse, utterance) <= threshold
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
const getMatchFunction = (matchingMode) => {
|
|
@@ -73,6 +73,32 @@ const SCRIPTING_FUNCTIONS_RAW = {
|
|
|
73
73
|
return Date.now()
|
|
74
74
|
},
|
|
75
75
|
|
|
76
|
+
$tomorrow: (pattern) => {
|
|
77
|
+
if (pattern) {
|
|
78
|
+
return moment().add(1, 'day').format(pattern)
|
|
79
|
+
}
|
|
80
|
+
return moment().add(1, 'day').toDate().toLocaleDateString()
|
|
81
|
+
},
|
|
82
|
+
$yesterday: (pattern) => {
|
|
83
|
+
if (pattern) {
|
|
84
|
+
return moment().subtract(1, 'day').format(pattern)
|
|
85
|
+
}
|
|
86
|
+
return moment().subtract(1, 'day').toDate().toLocaleDateString()
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
$date_add: (amount, unit, pattern) => {
|
|
90
|
+
if (pattern) {
|
|
91
|
+
return moment().add(amount, unit).format(pattern)
|
|
92
|
+
}
|
|
93
|
+
return moment().add(amount, unit).toDate().toLocaleDateString()
|
|
94
|
+
},
|
|
95
|
+
$date_subtract: (amount, unit, pattern) => {
|
|
96
|
+
if (pattern) {
|
|
97
|
+
return moment().subtract(amount, unit).format(pattern)
|
|
98
|
+
}
|
|
99
|
+
return moment().subtract(amount, unit).toDate().toLocaleDateString()
|
|
100
|
+
},
|
|
101
|
+
|
|
76
102
|
$year: () => {
|
|
77
103
|
return new Date().getFullYear()
|
|
78
104
|
},
|
|
@@ -168,7 +194,8 @@ const SCRIPTING_FUNCTIONS_RAW = {
|
|
|
168
194
|
require: false,
|
|
169
195
|
env: caps[Capabilities.SECURITY_ALLOW_UNSAFE] ? process.env : {},
|
|
170
196
|
sandbox: {
|
|
171
|
-
caps
|
|
197
|
+
caps,
|
|
198
|
+
moment
|
|
172
199
|
}
|
|
173
200
|
})
|
|
174
201
|
return vm.run(`module.exports = (${code})`)
|
|
@@ -246,7 +273,19 @@ const _apply = (scriptingMemory, str, caps, mockMsg) => {
|
|
|
246
273
|
for (const match of matches) {
|
|
247
274
|
if (match.indexOf('(') > 0) {
|
|
248
275
|
const arg = match.substring(match.indexOf('(') + 1, match.lastIndexOf(')')).replace(/\\\)/g, ')')
|
|
249
|
-
|
|
276
|
+
let args = [arg]
|
|
277
|
+
if (SCRIPTING_FUNCTIONS[key].numberOfArguments > 1) {
|
|
278
|
+
args = arg.split(',')
|
|
279
|
+
}
|
|
280
|
+
args = args.map(arg => {
|
|
281
|
+
arg = arg.trim()
|
|
282
|
+
if (arg.startsWith('"') && arg.endsWith('"')) {
|
|
283
|
+
return arg.substring(1, arg.length - 1)
|
|
284
|
+
} else {
|
|
285
|
+
return arg
|
|
286
|
+
}
|
|
287
|
+
})
|
|
288
|
+
str = str.replace(match, SCRIPTING_FUNCTIONS[key].handler(caps, ...args, mockMsg))
|
|
250
289
|
} else {
|
|
251
290
|
str = str.replace(match, SCRIPTING_FUNCTIONS[key].handler(caps))
|
|
252
291
|
}
|
|
@@ -135,7 +135,7 @@ module.exports = class ScriptingProvider {
|
|
|
135
135
|
}
|
|
136
136
|
debug(`assertBotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} = ${tomatch} ...`)
|
|
137
137
|
const found = _.find(tomatch, (utt) => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]))
|
|
138
|
-
const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? '
|
|
138
|
+
const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter'
|
|
139
139
|
if (_.isNil(found)) {
|
|
140
140
|
let message = `${stepTag}: Bot response `
|
|
141
141
|
message += meMsg ? `(on ${meMsg}) ` : ''
|
|
@@ -148,13 +148,18 @@ module.exports = class ScriptingProvider {
|
|
|
148
148
|
{
|
|
149
149
|
type: 'asserter',
|
|
150
150
|
source: asserterType,
|
|
151
|
+
params: {
|
|
152
|
+
matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
|
|
153
|
+
args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
|
|
154
|
+
},
|
|
151
155
|
context: {
|
|
152
156
|
stepTag
|
|
153
157
|
},
|
|
154
158
|
cause: {
|
|
155
159
|
expected: tomatch,
|
|
156
160
|
actual: botresponse,
|
|
157
|
-
matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE]
|
|
161
|
+
matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
|
|
162
|
+
args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
|
|
158
163
|
}
|
|
159
164
|
}
|
|
160
165
|
)
|
|
@@ -166,7 +171,7 @@ module.exports = class ScriptingProvider {
|
|
|
166
171
|
}
|
|
167
172
|
debug(`assertBotNotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} != ${nottomatch} ...`)
|
|
168
173
|
const found = _.find(nottomatch, (utt) => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]))
|
|
169
|
-
const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? '
|
|
174
|
+
const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter'
|
|
170
175
|
if (!_.isNil(found)) {
|
|
171
176
|
let message = `${stepTag}: Bot response `
|
|
172
177
|
message += meMsg ? `(on ${meMsg}) ` : ''
|
|
@@ -179,6 +184,10 @@ module.exports = class ScriptingProvider {
|
|
|
179
184
|
{
|
|
180
185
|
type: 'asserter',
|
|
181
186
|
source: asserterType,
|
|
187
|
+
params: {
|
|
188
|
+
matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
|
|
189
|
+
args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
|
|
190
|
+
},
|
|
182
191
|
context: {
|
|
183
192
|
stepTag
|
|
184
193
|
},
|
|
@@ -186,7 +195,8 @@ module.exports = class ScriptingProvider {
|
|
|
186
195
|
not: true,
|
|
187
196
|
expected: nottomatch,
|
|
188
197
|
actual: botresponse,
|
|
189
|
-
matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE]
|
|
198
|
+
matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
|
|
199
|
+
args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
|
|
190
200
|
}
|
|
191
201
|
}
|
|
192
202
|
)
|
|
@@ -868,27 +878,68 @@ module.exports = class ScriptingProvider {
|
|
|
868
878
|
this._sortConvos()
|
|
869
879
|
}
|
|
870
880
|
|
|
871
|
-
ExpandConvos () {
|
|
881
|
+
ExpandConvos (options = {}) {
|
|
882
|
+
options = Object.assign({
|
|
883
|
+
// use skip and keep, or justHeader
|
|
884
|
+
justHeader: false,
|
|
885
|
+
// drop unwanted convos
|
|
886
|
+
convoFilter: null
|
|
887
|
+
}, options)
|
|
888
|
+
const context = { count: 0 }
|
|
872
889
|
const expandedConvos = []
|
|
873
890
|
debug(`ExpandConvos - Using utterances expansion mode: ${this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE]}`)
|
|
874
891
|
this.convos.forEach((convo) => {
|
|
875
892
|
convo.expandPartialConvos()
|
|
876
|
-
this._expandConvo(
|
|
893
|
+
for (const expanded of this._expandConvo(convo, options, context)) {
|
|
894
|
+
expanded.header.assertionCount = this.GetAssertionCount(expanded)
|
|
895
|
+
if (options.justHeader) {
|
|
896
|
+
const ConvoWithOnlyHeader = {
|
|
897
|
+
header: {
|
|
898
|
+
name: expanded.header.name,
|
|
899
|
+
assertionCount: expanded.header.assertionCount
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
expandedConvos.push(ConvoWithOnlyHeader)
|
|
903
|
+
} else {
|
|
904
|
+
expandedConvos.push(expanded)
|
|
905
|
+
}
|
|
906
|
+
}
|
|
877
907
|
})
|
|
878
908
|
this.convos = expandedConvos
|
|
879
|
-
|
|
909
|
+
if (!options.justHeader) {
|
|
910
|
+
this._sortConvos()
|
|
911
|
+
} else {
|
|
912
|
+
this._updateConvos()
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
ExpandConvosIterable (options = {}) {
|
|
917
|
+
options = Object.assign({
|
|
918
|
+
// drop unwanted convos
|
|
919
|
+
convoFilter: null
|
|
920
|
+
}, options)
|
|
921
|
+
debug(`ExpandConvos - Using utterances expansion mode: ${this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE]}`)
|
|
922
|
+
// creating a nested generator, calling the other.
|
|
923
|
+
// We hope this.convos does not changes while this iterator is used
|
|
924
|
+
const _convosIterable = function * (options) {
|
|
925
|
+
const context = { count: 0 }
|
|
926
|
+
for (const convo of this.convos) {
|
|
927
|
+
convo.expandPartialConvos()
|
|
928
|
+
yield * this._expandConvo(convo, options, context)
|
|
929
|
+
}
|
|
930
|
+
}.bind(this)
|
|
931
|
+
|
|
932
|
+
this.convosIterable = _convosIterable(options)
|
|
880
933
|
}
|
|
881
934
|
|
|
882
935
|
/**
|
|
883
|
-
*
|
|
884
|
-
* @param expandedConvos
|
|
936
|
+
* This is a generator function with yield
|
|
885
937
|
* @param currentConvo
|
|
886
938
|
* @param convoStepIndex
|
|
887
939
|
* @param convoStepsStack list of ConvoSteps
|
|
888
|
-
* @param context {width: }
|
|
889
940
|
* @private
|
|
890
941
|
*/
|
|
891
|
-
_expandConvo (
|
|
942
|
+
* _expandConvo (currentConvo, options, context, convoStepIndex = 0, convoStepsStack = []) {
|
|
892
943
|
const utterancePostfix = (lineTag, uttOrUserInput) => {
|
|
893
944
|
const naming = this.caps[Capabilities.SCRIPTING_UTTEXPANSION_NAMING_MODE] || Defaults.capabilities[Capabilities.SCRIPTING_UTTEXPANSION_NAMING_MODE]
|
|
894
945
|
if (naming === 'justLineTag') {
|
|
@@ -908,7 +959,7 @@ module.exports = class ScriptingProvider {
|
|
|
908
959
|
if (currentStep.sender === 'bot' || currentStep.sender === 'begin' || currentStep.sender === 'end') {
|
|
909
960
|
const currentStepsStack = convoStepsStack.slice()
|
|
910
961
|
currentStepsStack.push(_.cloneDeep(currentStep))
|
|
911
|
-
this._expandConvo(
|
|
962
|
+
yield * this._expandConvo(currentConvo, options, context, convoStepIndex + 1, currentStepsStack)
|
|
912
963
|
} else if (currentStep.sender === 'me') {
|
|
913
964
|
let useUnexpanded = true
|
|
914
965
|
if (currentStep.messageText) {
|
|
@@ -925,28 +976,32 @@ module.exports = class ScriptingProvider {
|
|
|
925
976
|
}
|
|
926
977
|
if (this.utterances[uttName]) {
|
|
927
978
|
const allutterances = this.utterances[uttName].utterances
|
|
928
|
-
const processSampleUtterances = (sampleutterances, myContext)
|
|
929
|
-
sampleutterances.
|
|
930
|
-
processSampleUtterance(
|
|
931
|
-
}
|
|
979
|
+
const processSampleUtterances = function * (sampleutterances, myContext) {
|
|
980
|
+
for (let index = 0; index < sampleutterances.length; index++) {
|
|
981
|
+
yield * processSampleUtterance(sampleutterances[index], sampleutterances.length, index, Object.assign({ indexExpansionModeIndex: index }, myContext || context))
|
|
982
|
+
}
|
|
932
983
|
}
|
|
933
|
-
const processSampleUtterance = (sampleutterance, length, index, myContext)
|
|
934
|
-
const lineTag = `${index + 1}`.padStart(`${length}`.length, '0')
|
|
984
|
+
const processSampleUtterance = function * (sampleutterance, length, index, myContext) {
|
|
935
985
|
const currentStepsStack = convoStepsStack.slice()
|
|
936
986
|
if (uttArgs) {
|
|
937
987
|
sampleutterance = util.format(sampleutterance, ...uttArgs)
|
|
938
988
|
}
|
|
939
989
|
currentStepsStack.push(Object.assign(_.cloneDeep(currentStep), { messageText: sampleutterance }))
|
|
940
990
|
const currentConvoLabeled = _.cloneDeep(currentConvo)
|
|
941
|
-
|
|
991
|
+
if (length > 1) {
|
|
992
|
+
const lineTag = `${index + 1}`.padStart(`${length}`.length, '0')
|
|
993
|
+
Object.assign(currentConvoLabeled.header, { name: `${currentConvo.header.name}/${uttName}-${utterancePostfix(lineTag, sampleutterance)}` })
|
|
994
|
+
}
|
|
942
995
|
if (!currentConvoLabeled.sourceTag) currentConvoLabeled.sourceTag = {}
|
|
943
996
|
if (!currentConvoLabeled.sourceTag.origConvoName) currentConvoLabeled.sourceTag.origConvoName = currentConvo.header.name
|
|
944
|
-
this._expandConvo(
|
|
945
|
-
}
|
|
946
|
-
if (
|
|
997
|
+
yield * this._expandConvo(currentConvoLabeled, options, myContext || context, convoStepIndex + 1, currentStepsStack)
|
|
998
|
+
}.bind(this)
|
|
999
|
+
if (allutterances.length === 1) {
|
|
1000
|
+
yield * processSampleUtterances([allutterances[0]], context)
|
|
1001
|
+
} else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'index') {
|
|
947
1002
|
if (_.isNil(context.indexExpansionModeWidth)) {
|
|
948
1003
|
// executed for the first found utterance
|
|
949
|
-
processSampleUtterances(allutterances, Object.assign({}, context, { indexExpansionModeWidth: allutterances.length }))
|
|
1004
|
+
yield * processSampleUtterances(allutterances, Object.assign({}, context, { indexExpansionModeWidth: allutterances.length }))
|
|
950
1005
|
} else {
|
|
951
1006
|
if (_.isNil(context.indexExpansionModeIndex)) {
|
|
952
1007
|
throw new Error('indexExpansionModeIndex must be set!')
|
|
@@ -957,58 +1012,67 @@ module.exports = class ScriptingProvider {
|
|
|
957
1012
|
debug(`While expanding convos by index found in utterance "${uttName}" less examples (${allutterances.length}) as expected (${context.indexExpansionModeWidth})`)
|
|
958
1013
|
}
|
|
959
1014
|
const myContext = Object.assign({}, context, { indexExpansionModeWidth: Math.max(allutterances.length, context.indexExpansionModeWidth) })
|
|
960
|
-
processSampleUtterance(allutterances[localIndex], allutterances.length, localIndex, myContext)
|
|
1015
|
+
yield * processSampleUtterance(allutterances[localIndex], allutterances.length, localIndex, myContext)
|
|
961
1016
|
if (allutterances.length > context.indexExpansionModeWidth && context.indexExpansionModeIndex + 1 === context.indexExpansionModeWidth) {
|
|
962
1017
|
debug(`While expanding convos by index found in utterance "${uttName}" more examples (${allutterances.length}) as expected (${context.indexExpansionModeWidth})`)
|
|
963
1018
|
for (let i = context.indexExpansionModeWidth; i < allutterances.length; i++) {
|
|
964
1019
|
// if we found a utterance with more examples as any utterances before, we have to start new 'thread'
|
|
965
1020
|
const myContext = Object.assign({}, context, { indexExpansionModeWidth: allutterances.length, indexExpansionModeIndex: i })
|
|
966
|
-
processSampleUtterance(allutterances[i], allutterances.length, i, myContext)
|
|
1021
|
+
yield * processSampleUtterance(allutterances[i], allutterances.length, i, myContext)
|
|
967
1022
|
}
|
|
968
1023
|
}
|
|
969
1024
|
}
|
|
970
1025
|
} else {
|
|
971
1026
|
if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
|
|
972
|
-
processSampleUtterances([allutterances[0]])
|
|
1027
|
+
yield * processSampleUtterances([allutterances[0]], context)
|
|
973
1028
|
} else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
|
|
974
|
-
processSampleUtterances(allutterances
|
|
1029
|
+
yield * processSampleUtterances(allutterances
|
|
975
1030
|
.map(x => ({ x, r: Math.random() }))
|
|
976
1031
|
.sort((a, b) => a.r - b.r)
|
|
977
1032
|
.map(a => a.x)
|
|
978
|
-
.slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]))
|
|
1033
|
+
.slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]), context)
|
|
979
1034
|
} else {
|
|
980
|
-
processSampleUtterances(allutterances)
|
|
1035
|
+
yield * processSampleUtterances(allutterances, context)
|
|
981
1036
|
}
|
|
982
1037
|
}
|
|
983
1038
|
useUnexpanded = false
|
|
984
1039
|
}
|
|
985
1040
|
}
|
|
986
1041
|
if (currentStep.userInputs && currentStep.userInputs.length > 0) {
|
|
987
|
-
currentStep.userInputs.
|
|
1042
|
+
for (let uiIndex = 0; uiIndex < currentStep.userInputs.length; uiIndex++) {
|
|
1043
|
+
const ui = currentStep.userInputs[uiIndex]
|
|
988
1044
|
const userInput = this.userInputs[ui.name]
|
|
989
1045
|
if (userInput && userInput.expandConvo) {
|
|
990
1046
|
const expandedUserInputs = userInput.expandConvo({ convo: currentConvo, convoStep: currentStep, args: ui.args })
|
|
991
1047
|
if (expandedUserInputs && expandedUserInputs.length > 0) {
|
|
992
1048
|
// let sampleinputs = expandedUserInputs
|
|
993
|
-
const processSampleInputs = (sampleinputs, myContext, uiIndex)
|
|
994
|
-
sampleinputs.
|
|
995
|
-
processSampleInput(
|
|
996
|
-
}
|
|
1049
|
+
const processSampleInputs = function * (sampleinputs, myContext, uiIndex) {
|
|
1050
|
+
for (let index = 0; index < sampleinputs.length; index++) {
|
|
1051
|
+
yield * processSampleInput(sampleinputs[index], sampleinputs.length, index, Object.assign({ indexExpansionModeIndex: index }, myContext || context), uiIndex)
|
|
1052
|
+
}
|
|
997
1053
|
}
|
|
998
|
-
const processSampleInput = (sampleinput, length, index, myContext, uiIndex)
|
|
999
|
-
const lineTag = `${index + 1}`.padStart(`${length}`.length, '0')
|
|
1054
|
+
const processSampleInput = function * (sampleinput, length, index, myContext, uiIndex) {
|
|
1000
1055
|
const currentStepsStack = convoStepsStack.slice()
|
|
1001
1056
|
const currentStepMod = _.cloneDeep(currentStep)
|
|
1002
1057
|
currentStepMod.userInputs[uiIndex] = sampleinput
|
|
1003
1058
|
|
|
1004
1059
|
currentStepsStack.push(currentStepMod)
|
|
1005
1060
|
const currentConvoLabeled = _.cloneDeep(currentConvo)
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1061
|
+
if (length > 1) {
|
|
1062
|
+
if (sampleinput.convoPostfix) {
|
|
1063
|
+
Object.assign(currentConvoLabeled.header, { name: `${currentConvo.header.name}/${ui.name}-${sampleinput.convoPostfix}` })
|
|
1064
|
+
} else {
|
|
1065
|
+
const lineTag = `${index + 1}`.padStart(`${length}`.length, '0')
|
|
1066
|
+
Object.assign(currentConvoLabeled.header, { name: `${currentConvo.header.name}/${ui.name}-${utterancePostfix(lineTag, (sampleinput.args && sampleinput.args.length) ? sampleinput.args.join(', ') : 'no-args')}` })
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
yield * this._expandConvo(currentConvoLabeled, options, myContext || context, convoStepIndex + 1, currentStepsStack)
|
|
1070
|
+
}.bind(this)
|
|
1071
|
+
if (expandedUserInputs.length === 1) {
|
|
1072
|
+
yield * processSampleInputs([expandedUserInputs[0]], context, uiIndex)
|
|
1073
|
+
} else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'index') {
|
|
1010
1074
|
if (_.isNil(context.indexExpansionModeWidth)) {
|
|
1011
|
-
processSampleInputs(expandedUserInputs, Object.assign({}, context, { indexExpansionModeWidth: expandedUserInputs.length }), uiIndex)
|
|
1075
|
+
yield * processSampleInputs(expandedUserInputs, Object.assign({}, context, { indexExpansionModeWidth: expandedUserInputs.length }), uiIndex)
|
|
1012
1076
|
} else {
|
|
1013
1077
|
if (_.isNil(context.indexExpansionModeIndex)) {
|
|
1014
1078
|
throw new Error('indexExpansionModeIndex must be set!')
|
|
@@ -1019,20 +1083,20 @@ module.exports = class ScriptingProvider {
|
|
|
1019
1083
|
debug(`While expanding convos by index found user input "${ui.name}, ${ui.args}" less examples (${expandedUserInputs.length}) as expected (${context.indexExpansionModeWidth})`)
|
|
1020
1084
|
}
|
|
1021
1085
|
const myContext = Object.assign({}, context, { indexExpansionModeWidth: Math.max(expandedUserInputs.length, context.indexExpansionModeWidth) })
|
|
1022
|
-
processSampleInput(expandedUserInputs[localIndex], expandedUserInputs.length, localIndex, myContext, uiIndex)
|
|
1086
|
+
yield * processSampleInput(expandedUserInputs[localIndex], expandedUserInputs.length, localIndex, myContext, uiIndex)
|
|
1023
1087
|
if (expandedUserInputs.length > context.indexExpansionModeWidth && context.indexExpansionModeIndex + 1 === context.indexExpansionModeWidth) {
|
|
1024
1088
|
debug(`While expanding convos by index found user input "${ui.name}, ${ui.args}" more examples (${expandedUserInputs.length}) as expected (${context.indexExpansionModeWidth})`)
|
|
1025
1089
|
for (let i = context.indexExpansionModeWidth; i < expandedUserInputs.length; i++) {
|
|
1026
1090
|
const myContext = Object.assign({}, context, { indexExpansionModeWidth: expandedUserInputs.length, indexExpansionModeIndex: i })
|
|
1027
|
-
processSampleInput(expandedUserInputs[i], expandedUserInputs.length, i, myContext, uiIndex)
|
|
1091
|
+
yield * processSampleInput(expandedUserInputs[i], expandedUserInputs.length, i, myContext, uiIndex)
|
|
1028
1092
|
}
|
|
1029
1093
|
}
|
|
1030
1094
|
}
|
|
1031
1095
|
} else {
|
|
1032
1096
|
if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
|
|
1033
|
-
processSampleInputs([expandedUserInputs[0]], context, uiIndex)
|
|
1097
|
+
yield * processSampleInputs([expandedUserInputs[0]], context, uiIndex)
|
|
1034
1098
|
} else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
|
|
1035
|
-
processSampleInputs(expandedUserInputs
|
|
1099
|
+
yield * processSampleInputs(expandedUserInputs
|
|
1036
1100
|
.map(x => ({
|
|
1037
1101
|
x,
|
|
1038
1102
|
r: Math.random()
|
|
@@ -1041,35 +1105,49 @@ module.exports = class ScriptingProvider {
|
|
|
1041
1105
|
.map(a => a.x)
|
|
1042
1106
|
.slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]), context, uiIndex)
|
|
1043
1107
|
} else {
|
|
1044
|
-
processSampleInputs(expandedUserInputs, context, uiIndex)
|
|
1108
|
+
yield * processSampleInputs(expandedUserInputs, context, uiIndex)
|
|
1045
1109
|
}
|
|
1046
1110
|
}
|
|
1047
1111
|
useUnexpanded = false
|
|
1048
1112
|
}
|
|
1049
1113
|
}
|
|
1050
|
-
}
|
|
1114
|
+
}
|
|
1051
1115
|
}
|
|
1052
1116
|
if (useUnexpanded) {
|
|
1053
1117
|
const currentStepsStack = convoStepsStack.slice()
|
|
1054
1118
|
currentStepsStack.push(_.cloneDeep(currentStep))
|
|
1055
|
-
this._expandConvo(
|
|
1119
|
+
yield * this._expandConvo(currentConvo, options, context, convoStepIndex + 1, currentStepsStack)
|
|
1056
1120
|
}
|
|
1057
1121
|
}
|
|
1058
1122
|
} else {
|
|
1059
|
-
|
|
1123
|
+
const expanded = Object.assign(_.cloneDeep(currentConvo), { conversation: _.cloneDeep(convoStepsStack) })
|
|
1124
|
+
if (!options.convoFilter || options.convoFilter(expanded)) {
|
|
1125
|
+
context.count++
|
|
1126
|
+
const logPerEntry = context.count < 10 ? 1 : context.count < 100 ? 10 : context.count < 1000 ? 100 : context.count < 10000 ? 1000 : 10000
|
|
1127
|
+
if (context.count % logPerEntry === 0) {
|
|
1128
|
+
debug(`Convo #${context.count} expanded (${expanded.header.name})`)
|
|
1129
|
+
}
|
|
1130
|
+
yield expanded
|
|
1131
|
+
}
|
|
1060
1132
|
}
|
|
1061
1133
|
}
|
|
1062
1134
|
|
|
1063
1135
|
_sortConvos () {
|
|
1064
1136
|
this.convos = _.sortBy(this.convos, [(convo) => convo.header.sort || convo.header.name])
|
|
1137
|
+
this._updateConvos()
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
_updateConvos () {
|
|
1065
1141
|
let i = 0
|
|
1066
1142
|
this.convos.forEach((convo) => {
|
|
1067
|
-
convo
|
|
1068
|
-
|
|
1069
|
-
convo.header.projectname
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
convo.header.testsessionname
|
|
1143
|
+
if (convo) {
|
|
1144
|
+
convo.header.order = ++i
|
|
1145
|
+
if (!convo.header.projectname) {
|
|
1146
|
+
convo.header.projectname = this.caps[Capabilities.PROJECTNAME]
|
|
1147
|
+
}
|
|
1148
|
+
if (!convo.header.testsessionname) {
|
|
1149
|
+
convo.header.testsessionname = this.caps[Capabilities.TESTSESSIONNAME]
|
|
1150
|
+
}
|
|
1073
1151
|
}
|
|
1074
1152
|
})
|
|
1075
1153
|
}
|
|
@@ -1080,7 +1158,11 @@ module.exports = class ScriptingProvider {
|
|
|
1080
1158
|
} else if (convos) {
|
|
1081
1159
|
this.convos.push(convos)
|
|
1082
1160
|
}
|
|
1083
|
-
this.
|
|
1161
|
+
if (this.convos.filter(c => _.isNil(c))) {
|
|
1162
|
+
this._updateConvos()
|
|
1163
|
+
} else {
|
|
1164
|
+
this._sortConvos()
|
|
1165
|
+
}
|
|
1084
1166
|
}
|
|
1085
1167
|
|
|
1086
1168
|
AddUtterances (utterances) {
|
|
@@ -1334,4 +1416,30 @@ module.exports = class ScriptingProvider {
|
|
|
1334
1416
|
...lines,
|
|
1335
1417
|
'}'].join('\r\n')
|
|
1336
1418
|
}
|
|
1419
|
+
|
|
1420
|
+
GetAssertionCount (convo) {
|
|
1421
|
+
if (!convo) {
|
|
1422
|
+
return 0
|
|
1423
|
+
}
|
|
1424
|
+
let counter = 0
|
|
1425
|
+
for (const step of convo.conversation) {
|
|
1426
|
+
if (step.sender === 'bot') {
|
|
1427
|
+
let stepCounter = step.asserters ? step.asserters.length : 0
|
|
1428
|
+
if (step.messageText) {
|
|
1429
|
+
stepCounter++
|
|
1430
|
+
}
|
|
1431
|
+
stepCounter = stepCounter === 0 ? 1 : stepCounter
|
|
1432
|
+
counter += stepCounter
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
if (convo.convoBegin && convo.convoBegin.asserters) {
|
|
1437
|
+
counter += convo.convoBegin.asserters.length
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
if (convo.convoEnd && convo.convoEnd.asserters) {
|
|
1441
|
+
counter += convo.convoEnd.asserters.length
|
|
1442
|
+
}
|
|
1443
|
+
return counter === 0 ? 1 : counter
|
|
1444
|
+
}
|
|
1337
1445
|
}
|
package/src/scripting/helper.js
CHANGED
|
@@ -437,6 +437,8 @@ const convoStepToLines = (step) => {
|
|
|
437
437
|
lines.push('MEDIA ' + step.media[0].mediaUri)
|
|
438
438
|
} else if (step.messageText) {
|
|
439
439
|
lines.push(step.messageText)
|
|
440
|
+
} else if (step.sourceData) {
|
|
441
|
+
lines.push(JSON.stringify(step.sourceData, null, 2))
|
|
440
442
|
}
|
|
441
443
|
step.userInputs && step.userInputs.forEach((userInput) => {
|
|
442
444
|
lines.push(userInput.name + _formatAppendArgs(userInput.args))
|
|
@@ -3,7 +3,7 @@ const BaseCountAsserter = require('./BaseCountAsserter')
|
|
|
3
3
|
module.exports = class BotRepliesConsumedAsserter extends BaseCountAsserter {
|
|
4
4
|
constructor (context, caps = {}) {
|
|
5
5
|
super(context, caps, 'BotReplies')
|
|
6
|
-
this.name = '
|
|
6
|
+
this.name = 'Bot Replies Consumed Asserter'
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
async _getCount (argv) { return argv.container._QueueLength() }
|
|
@@ -3,7 +3,7 @@ const BaseCountAsserter = require('./BaseCountAsserter')
|
|
|
3
3
|
module.exports = class BotRepliesUnconsumedCountAsserter extends BaseCountAsserter {
|
|
4
4
|
constructor (context, caps = {}) {
|
|
5
5
|
super(context, caps, 'unconsumed bot replies')
|
|
6
|
-
this.name = '
|
|
6
|
+
this.name = 'Bot Replies Unconsumed Count Asserter'
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
async _getCount (argv) { return argv.container._QueueLength() }
|
|
@@ -8,7 +8,7 @@ const _buttonsCount = ({ botMsg }) => {
|
|
|
8
8
|
module.exports = class ButtonsCountAsserter extends BaseCountAsserter {
|
|
9
9
|
constructor (context, caps = {}) {
|
|
10
10
|
super(context, caps, 'Buttons')
|
|
11
|
-
this.name = '
|
|
11
|
+
this.name = 'Buttons Count Asserter'
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async _getCount (argv) { return _buttonsCount(argv) }
|
|
@@ -8,7 +8,7 @@ const _buttonsCount = ({ botMsg }) => {
|
|
|
8
8
|
module.exports = class ButtonsCountRecAsserter extends BaseCountAsserter {
|
|
9
9
|
constructor (context, caps = {}) {
|
|
10
10
|
super(context, caps, 'Buttons')
|
|
11
|
-
this.name = '
|
|
11
|
+
this.name = 'Buttons Count (recursive) Asserter'
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async _getCount (argv) { return _buttonsCount(argv) }
|