botium-core 1.14.1 → 1.14.4

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.
Files changed (39) hide show
  1. package/dist/botium-cjs.js +341 -126
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +359 -144
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +11 -11
  6. package/src/Capabilities.js +2 -0
  7. package/src/scripting/BotiumError.js +40 -3
  8. package/src/scripting/CompilerMarkdown.js +2 -1
  9. package/src/scripting/CompilerTxt.js +1 -4
  10. package/src/scripting/Convo.js +113 -19
  11. package/src/scripting/MatchFunctions.js +30 -8
  12. package/src/scripting/ScriptingMemory.js +7 -0
  13. package/src/scripting/ScriptingProvider.js +87 -36
  14. package/src/scripting/helper.js +3 -2
  15. package/src/scripting/logichook/LogicHookConsts.js +5 -2
  16. package/src/scripting/logichook/LogicHookUtils.js +8 -6
  17. package/src/scripting/logichook/logichooks/ConvoStepParametersLogicHook.js +6 -0
  18. package/src/scripting/logichook/logichooks/OrderedListToButtonLogicHook.js +37 -0
  19. package/test/compiler/compilermarkdown.spec.js +3 -3
  20. package/test/compiler/compilertxt.spec.js +1 -1
  21. package/test/compiler/convos/txt/convos_emptyrow_just_emptyrow.convo.txt +1 -1
  22. package/test/convo/fillAndApplyScriptingMemory.spec.js +11 -0
  23. package/test/logichooks/orderedListToButton.spec.js +35 -0
  24. package/test/scripting/asserters/convoStepParameters.spec.js +151 -0
  25. package/test/scripting/asserters/convos/TEXT_GOOD.convo.txt +6 -0
  26. package/test/scripting/asserters/convos/convo_step_parameter_matchmode_failed.convo.txt +8 -0
  27. package/test/scripting/asserters/convos/convo_step_parameter_matchmode_failed_wer.convo.txt +9 -0
  28. package/test/scripting/asserters/convos/convo_step_parameter_retry_asserters_all_good.convo.txt +9 -0
  29. package/test/scripting/asserters/convos/convo_step_parameter_retry_asserters_botium_timeout.convo.txt +9 -0
  30. package/test/scripting/asserters/convos/convo_step_parameter_retry_asserters_good.convo.txt +9 -0
  31. package/test/scripting/asserters/convos/convo_step_parameter_retry_asserters_good_global.convo.txt +9 -0
  32. package/test/scripting/asserters/convos/convo_step_parameter_retry_main_and_asserter.convo.txt +10 -0
  33. package/test/scripting/asserters/convos/convo_step_parameter_retry_main_botium_timeout.convo.txt +9 -0
  34. package/test/scripting/asserters/convos/convo_step_parameter_retry_main_but_no_button.convo.txt +10 -0
  35. package/test/scripting/asserters/convos/convo_step_parameter_retry_main_good.convo.txt +9 -0
  36. package/test/scripting/asserters/convos/convo_step_parameter_retry_main_good_begin.convo.txt +11 -0
  37. package/test/scripting/logichooks/convos/scripting_memory_overwrite_and_check.convo.txt +2 -2
  38. package/test/scripting/matching/matchingmode.spec.js +4 -1
  39. package/test/scripting/scriptingProvider.spec.js +38 -12
@@ -14,7 +14,7 @@ var randomatic = require('randomatic');
14
14
  var lodash = require('lodash');
15
15
  var boolean$1 = require('boolean');
16
16
  var events = require('events');
17
- var debug$n = require('debug');
17
+ var debug$o = require('debug');
18
18
  var isClass = require('is-class');
19
19
  var crypto = require('crypto');
20
20
  var globby = require('globby');
@@ -52,7 +52,7 @@ var randomatic__default = /*#__PURE__*/_interopDefaultLegacy(randomatic);
52
52
  var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
53
53
  var boolean__default = /*#__PURE__*/_interopDefaultLegacy(boolean$1);
54
54
  var events__default = /*#__PURE__*/_interopDefaultLegacy(events);
55
- var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$n);
55
+ var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$o);
56
56
  var isClass__default = /*#__PURE__*/_interopDefaultLegacy(isClass);
57
57
  var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
58
58
  var globby__default = /*#__PURE__*/_interopDefaultLegacy(globby);
@@ -77,7 +77,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
77
77
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
78
78
 
79
79
  var name = "botium-core";
80
- var version$1 = "1.14.1";
80
+ var version$1 = "1.14.4";
81
81
  var description = "The Selenium for Chatbots";
82
82
  var main = "index.js";
83
83
  var module$1 = "dist/botium-es.js";
@@ -108,12 +108,12 @@ var bugs = {
108
108
  };
109
109
  var homepage = "https://www.botium.ai";
110
110
  var dependencies = {
111
- "@babel/runtime": "^7.23.2",
111
+ "@babel/runtime": "^7.23.5",
112
112
  async: "^3.2.5",
113
113
  "body-parser": "^1.20.2",
114
114
  boolean: "^3.2.0",
115
115
  bottleneck: "^2.19.5",
116
- "csv-parse": "^5.5.2",
116
+ "csv-parse": "^5.5.3",
117
117
  debug: "^4.3.4",
118
118
  express: "^4.18.2",
119
119
  globby: "11.0.4",
@@ -122,7 +122,7 @@ var dependencies = {
122
122
  "is-json": "^2.0.1",
123
123
  jsonpath: "^1.1.1",
124
124
  lodash: "^4.17.21",
125
- "markdown-it": "^13.0.2",
125
+ "markdown-it": "^14.0.0",
126
126
  "mime-types": "^2.1.35",
127
127
  mkdirp: "^3.0.1",
128
128
  moment: "^2.29.4",
@@ -148,23 +148,23 @@ var dependencies = {
148
148
  yaml: "^2.3.4"
149
149
  };
150
150
  var devDependencies = {
151
- "@babel/core": "^7.23.3",
151
+ "@babel/core": "^7.23.5",
152
152
  "@babel/node": "^7.22.19",
153
- "@babel/plugin-transform-runtime": "^7.23.3",
154
- "@babel/preset-env": "^7.23.3",
153
+ "@babel/plugin-transform-runtime": "^7.23.4",
154
+ "@babel/preset-env": "^7.23.5",
155
155
  chai: "^4.3.10",
156
156
  "chai-as-promised": "^7.1.1",
157
157
  "cross-env": "^7.0.3",
158
- eslint: "^8.53.0",
158
+ eslint: "^8.55.0",
159
159
  "eslint-config-standard": "^17.1.0",
160
160
  "eslint-plugin-import": "^2.29.0",
161
161
  "eslint-plugin-mocha": "^10.2.0",
162
- "eslint-plugin-n": "^16.3.1",
162
+ "eslint-plugin-n": "^16.4.0",
163
163
  "eslint-plugin-promise": "^6.1.1",
164
164
  "eslint-plugin-standard": "^4.1.0",
165
165
  mocha: "^10.2.0",
166
- nock: "^13.3.8",
167
- "npm-check-updates": "^16.14.6",
166
+ nock: "^13.4.0",
167
+ "npm-check-updates": "^16.14.11",
168
168
  nyc: "^15.1.0",
169
169
  rollup: "2.79.1",
170
170
  "rollup-plugin-babel": "^4.4.0",
@@ -367,6 +367,8 @@ var Capabilities = {
367
367
  // varnames, testcasenames
368
368
  SCRIPTING_MEMORY_COLUMN_MODE: 'SCRIPTING_MEMORY_COLUMN_MODE',
369
369
  // Botium Lifecycle Hooks
370
+ SCRIPTING_CONVO_STEP_PARAMETERS: 'SCRIPTING_CONVO_STEP_PARAMETERS',
371
+ // Botium Lifecycle Hooks
370
372
  CUSTOMHOOK_ONBUILD: 'CUSTOMHOOK_ONBUILD',
371
373
  CUSTOMHOOK_ONSTART: 'CUSTOMHOOK_ONSTART',
372
374
  CUSTOMHOOK_ONUSERSAYS: 'CUSTOMHOOK_ONUSERSAYS',
@@ -528,6 +530,7 @@ Capabilities.SCRIPTING_UTTEXPANSION_NAMING_UTTERANCE_MAX;
528
530
  Capabilities.SCRIPTING_MEMORYEXPANSION_KEEP_ORIG;
529
531
  Capabilities.SCRIPTING_MEMORY_MATCHING_MODE;
530
532
  Capabilities.SCRIPTING_MEMORY_COLUMN_MODE;
533
+ Capabilities.SCRIPTING_CONVO_STEP_PARAMETERS;
531
534
  Capabilities.CUSTOMHOOK_ONBUILD;
532
535
  Capabilities.CUSTOMHOOK_ONSTART;
533
536
  Capabilities.CUSTOMHOOK_ONUSERSAYS;
@@ -1076,6 +1079,12 @@ var LogicHookConsts = {
1076
1079
  }, {
1077
1080
  name: 'CONDITIONAL_STEP_JSON_PATH_BASED',
1078
1081
  className: 'ConditionalJsonPathBasedLogicHook.js'
1082
+ }, {
1083
+ name: 'CONVO_STEP_PARAMETERS',
1084
+ className: 'ConvoStepParametersLogicHook.js'
1085
+ }, {
1086
+ name: 'ORDERED_LIST_TO_BUTTON',
1087
+ className: 'OrderedListToButtonLogicHook'
1079
1088
  }],
1080
1089
  DEFAULT_USER_INPUTS: [{
1081
1090
  name: 'BUTTON',
@@ -1086,14 +1095,16 @@ var LogicHookConsts = {
1086
1095
  }, {
1087
1096
  name: 'FORM',
1088
1097
  className: 'FormInput'
1089
- }]
1098
+ }],
1099
+ LOGIC_HOOK_EVENTS: ['onConvoBegin', 'onMeStart', 'onMePrepare', 'onMeEnd', 'onBotStart', 'onBotEnd', 'onBotPrepare', 'onConvoEnd']
1090
1100
  };
1091
1101
  LogicHookConsts.LOGIC_HOOK_INCLUDE;
1092
1102
  LogicHookConsts.DEFAULT_ASSERTERS;
1093
1103
  LogicHookConsts.DEFAULT_LOGIC_HOOKS;
1094
1104
  LogicHookConsts.DEFAULT_USER_INPUTS;
1105
+ LogicHookConsts.LOGIC_HOOK_EVENTS;
1095
1106
 
1096
- const debug$m = debug__default["default"]('botium-core-asserterUtils');
1107
+ const debug$n = debug__default["default"]('botium-core-asserterUtils');
1097
1108
  const {
1098
1109
  DEFAULT_ASSERTERS,
1099
1110
  DEFAULT_LOGIC_HOOKS,
@@ -1145,7 +1156,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1145
1156
  _fetchAsserters() {
1146
1157
  this.caps[Capabilities.ASSERTERS].forEach(asserter => {
1147
1158
  if (this.asserters[asserter.ref]) {
1148
- debug$m(`${asserter.ref} asserter already exists, overwriting.`);
1159
+ debug$n(`${asserter.ref} asserter already exists, overwriting.`);
1149
1160
  }
1150
1161
  this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
1151
1162
  if (asserter.global) {
@@ -1156,7 +1167,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1156
1167
  _fetchLogicHooks() {
1157
1168
  this.caps[Capabilities.LOGIC_HOOKS].forEach(logicHook => {
1158
1169
  if (this.logicHooks[logicHook.ref]) {
1159
- debug$m(`${logicHook.ref} logic hook already exists, overwriting.`);
1170
+ debug$n(`${logicHook.ref} logic hook already exists, overwriting.`);
1160
1171
  }
1161
1172
  this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook');
1162
1173
  if (logicHook.global) {
@@ -1167,7 +1178,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1167
1178
  _fetchUserInputs() {
1168
1179
  this.caps[Capabilities.USER_INPUTS].forEach(userInput => {
1169
1180
  if (this.userInputs[userInput.ref]) {
1170
- debug$m(`${userInput.ref} userinput already exists, overwriting.`);
1181
+ debug$n(`${userInput.ref} userinput already exists, overwriting.`);
1171
1182
  }
1172
1183
  this.userInputs[userInput.ref] = this._loadClass(userInput, 'userinput');
1173
1184
  });
@@ -1242,6 +1253,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1242
1253
  throw new Error(`Logic Hook specification ${ref} ${hookType} (${packageName}) invalid: ${err.message}`);
1243
1254
  }
1244
1255
  }
1256
+ const typeAsText = hookType === 'asserter' ? 'Asserter' : hookType === 'logichook' ? 'Logic Hook' : hookType === 'userinput' ? 'User Input' : 'Unknown';
1245
1257
  if (isClass__default["default"](src)) {
1246
1258
  try {
1247
1259
  const CheckClass = src;
@@ -1250,7 +1262,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1250
1262
  ...this.buildScriptContext
1251
1263
  }, this.caps, args);
1252
1264
  } catch (err) {
1253
- throw new Error(`Logic Hook specification ${ref} from class invalid: ${err.message}`);
1265
+ throw new Error(`${typeAsText} specification ${ref} from class invalid: ${err.message}`);
1254
1266
  }
1255
1267
  }
1256
1268
  if (lodash__default["default"].isFunction(src)) {
@@ -1260,7 +1272,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1260
1272
  ...this.buildScriptContext
1261
1273
  }, this.caps, args);
1262
1274
  } catch (err) {
1263
- throw new Error(`Logic Hook specification ${ref} from function invalid: ${err.message}`);
1275
+ throw new Error(`${typeAsText} specification ${ref} from function invalid: ${err.message}`);
1264
1276
  }
1265
1277
  }
1266
1278
  if (lodash__default["default"].isObject(src) && !lodash__default["default"].isString(src)) {
@@ -1278,7 +1290,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1278
1290
  }, {});
1279
1291
  return hookObject;
1280
1292
  } catch (err) {
1281
- throw new Error(`Logic Hook specification ${ref} ${hookType} from provided src (${util__default["default"].inspect(src)}) invalid: ${err.message}`);
1293
+ throw new Error(`${typeAsText} specification ${ref} ${hookType} from provided src (${util__default["default"].inspect(src)}) invalid: ${err.message}`);
1282
1294
  }
1283
1295
  }
1284
1296
  if (lodash__default["default"].isString(src)) {
@@ -1339,7 +1351,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1339
1351
  try {
1340
1352
  return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName);
1341
1353
  } catch (err) {
1342
- loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1354
+ loadErr.push(`${typeAsText} specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1343
1355
  }
1344
1356
  }
1345
1357
  }
@@ -1348,13 +1360,13 @@ var LogicHookUtils_1 = class LogicHookUtils {
1348
1360
  try {
1349
1361
  return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName);
1350
1362
  } catch (err) {
1351
- loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1363
+ loadErr.push(`${typeAsText} specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1352
1364
  }
1353
1365
  }
1354
1366
  }
1355
- loadErr.forEach(debug$m);
1367
+ loadErr.forEach(debug$n);
1356
1368
  }
1357
- throw new Error(`Logic Hook specification ${ref} ${hookType} from "${util__default["default"].inspect(src)}" invalid : no loader available`);
1369
+ throw new Error(`${typeAsText} specification ${ref} ${hookType} from "${util__default["default"].inspect(src)}" invalid : no loader available`);
1358
1370
  }
1359
1371
  };
1360
1372
 
@@ -1563,10 +1575,11 @@ var Enums = {
1563
1575
  };
1564
1576
  Enums.E_SCRIPTING_MEMORY_COLUMN_MODE;
1565
1577
 
1566
- const debug$l = debug__default["default"]('botium-core-scripting-helper');
1578
+ const debug$m = debug__default["default"]('botium-core-scripting-helper');
1567
1579
  const {
1568
1580
  E_SCRIPTING_MEMORY_COLUMN_MODE: E_SCRIPTING_MEMORY_COLUMN_MODE$1
1569
1581
  } = Enums;
1582
+ const WHITE_SPACES_EXCEPT_SPACE_CHAR_AT_THE_END = /[\n\t\r]+$/;
1570
1583
  const normalizeText$1 = (str, doCleanup) => {
1571
1584
  if (str && lodash__default["default"].isArray(str)) {
1572
1585
  str = str.join(' ');
@@ -1808,7 +1821,7 @@ const linesToConvoStep$5 = (lines, sender, context, eol, singleLineMode = false)
1808
1821
  if (eol === null) {
1809
1822
  throw new Error('eol cant be null');
1810
1823
  }
1811
- convoStep.messageText = textLines.join(eol).trim();
1824
+ convoStep.messageText = textLines.join(eol).replace(WHITE_SPACES_EXCEPT_SPACE_CHAR_AT_THE_END, '');
1812
1825
  }
1813
1826
  }
1814
1827
  } else {
@@ -2025,7 +2038,7 @@ const convoStepToLines$2 = step => {
2025
2038
  lines.push(logicHook.name + _formatAppendArgs(logicHook.args));
2026
2039
  });
2027
2040
  }
2028
- return lines.map(l => l.trim());
2041
+ return lines;
2029
2042
  };
2030
2043
  const linesToScriptingMemories$2 = (lines, columnMode = null) => {
2031
2044
  const guessScriptingMemoryColumnMode = lines => {
@@ -2139,7 +2152,7 @@ const calculateWer$2 = (str, pattern) => {
2139
2152
  errCount += err.filter(err => err === true).length;
2140
2153
  allCount += err.length;
2141
2154
  }
2142
- debug$l(`Word Error Rate Asserter - Compared Bot Message '${botMessage}' / '${utt}': ${(errCount / allCount).toFixed(2)}`);
2155
+ debug$m(`Word Error Rate Asserter - Compared Bot Message '${botMessage}' / '${utt}': ${(errCount / allCount).toFixed(2)}`);
2143
2156
  return (errCount / allCount).toFixed(2);
2144
2157
  };
2145
2158
  const toPercent$1 = s => `${(s * 100).toFixed(0)}%`;
@@ -2247,6 +2260,44 @@ const BotiumError$4 = class BotiumError extends Error {
2247
2260
  return null;
2248
2261
  }
2249
2262
  }
2263
+ hasError({
2264
+ type,
2265
+ source
2266
+ }) {
2267
+ if (this.context) {
2268
+ const errArr = lodash__default["default"].isArray(this.context) ? this.context : [this.context];
2269
+ for (const err of errArr) {
2270
+ if (err.type === 'list') {
2271
+ for (const internal of err.errors) {
2272
+ if ((!type || internal.type === type) && (!source || internal.source === source)) {
2273
+ return true;
2274
+ }
2275
+ }
2276
+ }
2277
+ if ((!type || err.type === type) && (!source || err.source === source)) {
2278
+ return true;
2279
+ }
2280
+ }
2281
+ } else {
2282
+ return false;
2283
+ }
2284
+ }
2285
+ toArray() {
2286
+ if (this.context) {
2287
+ let result = [];
2288
+ const errArr = lodash__default["default"].isArray(this.context) ? this.context : [this.context];
2289
+ for (const err of errArr) {
2290
+ if (err.type === 'list') {
2291
+ result = result.concat(err.errors);
2292
+ } else {
2293
+ result.push(err);
2294
+ }
2295
+ }
2296
+ return result;
2297
+ } else {
2298
+ return [];
2299
+ }
2300
+ }
2250
2301
  };
2251
2302
  const _getChildErrorsFromContext = context => {
2252
2303
  if (context && context.errors && lodash__default["default"].isArray(context.errors)) {
@@ -2254,12 +2305,16 @@ const _getChildErrorsFromContext = context => {
2254
2305
  }
2255
2306
  return false;
2256
2307
  };
2257
- const botiumErrorFromErr$2 = (message, err) => {
2308
+ const botiumErrorFromErr$2 = (message, err, context = {}) => {
2258
2309
  if (err instanceof BotiumError$4) {
2259
- return new BotiumError$4(message, err.context, true);
2310
+ return new BotiumError$4(message, {
2311
+ ...err.context,
2312
+ ...context
2313
+ }, true);
2260
2314
  } else {
2261
2315
  return new BotiumError$4(message, {
2262
- err
2316
+ err,
2317
+ ...context
2263
2318
  }, true);
2264
2319
  }
2265
2320
  };
@@ -2295,7 +2350,7 @@ var BotiumError_1 = {
2295
2350
  botiumErrorFromList: botiumErrorFromList$2
2296
2351
  };
2297
2352
 
2298
- const debug$k = debug__default["default"]('botium-core-ScriptingMemory');
2353
+ const debug$l = debug__default["default"]('botium-core-ScriptingMemory');
2299
2354
  const {
2300
2355
  v1: uuidv1
2301
2356
  } = uuid__default["default"];
@@ -2534,6 +2589,13 @@ const _apply = (scriptingMemory, str, caps, mockMsg) => {
2534
2589
  return arg;
2535
2590
  }
2536
2591
  });
2592
+ args = args.map(arg => {
2593
+ const argStr = `${arg}`;
2594
+ if (argStr.startsWith('$')) {
2595
+ return scriptingMemory[argStr.substring(1)] || arg;
2596
+ }
2597
+ return arg;
2598
+ });
2537
2599
  str = str.replace(match, SCRIPTING_FUNCTIONS$1[key].handler(caps, ...args, mockMsg));
2538
2600
  } else {
2539
2601
  str = str.replace(match, SCRIPTING_FUNCTIONS$1[key].handler(caps));
@@ -2548,7 +2610,7 @@ const extractVarNames = text => {
2548
2610
  return (lodash__default["default"].isString(text) ? text.match(/\$[A-Za-z]\w+/g) : false) || [];
2549
2611
  };
2550
2612
  const fill = (container, scriptingMemory, result, utterance, scriptingEvents) => {
2551
- debug$k(`fill start: ${util__default["default"].inspect(scriptingMemory)}`);
2613
+ debug$l(`fill start: ${util__default["default"].inspect(scriptingMemory)}`);
2552
2614
  let varRegex;
2553
2615
  switch (container.caps[Capabilities.SCRIPTING_MEMORY_MATCHING_MODE]) {
2554
2616
  case 'word':
@@ -2582,14 +2644,14 @@ const fill = (container, scriptingMemory, result, utterance, scriptingEvents) =>
2582
2644
  if (i <= varMatches.length) {
2583
2645
  const varName = varMatches[i - 1];
2584
2646
  if (RESERVED_WORDS.indexOf(varName) >= 0) {
2585
- debug$k(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2647
+ debug$l(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2586
2648
  } else {
2587
2649
  scriptingMemory[varName] = resultMatches[i];
2588
2650
  }
2589
2651
  }
2590
2652
  }
2591
2653
  });
2592
- debug$k(`fill end: ${util__default["default"].inspect(scriptingMemory)}`);
2654
+ debug$l(`fill end: ${util__default["default"].inspect(scriptingMemory)}`);
2593
2655
  }
2594
2656
  };
2595
2657
  var ScriptingMemory = {
@@ -2607,7 +2669,7 @@ ScriptingMemory.extractVarNames;
2607
2669
  ScriptingMemory.RESERVED_WORDS;
2608
2670
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2609
2671
 
2610
- const debug$j = debug__default["default"]('botium-core-Convo');
2672
+ const debug$k = debug__default["default"]('botium-core-Convo');
2611
2673
  const {
2612
2674
  BotiumError: BotiumError$2,
2613
2675
  botiumErrorFromErr: botiumErrorFromErr$1,
@@ -2761,10 +2823,10 @@ class TranscriptError extends Error {
2761
2823
  class Convo$6 {
2762
2824
  constructor(context, fromJson = {}) {
2763
2825
  if (fromJson instanceof Convo$6) {
2764
- debug$j('Illegal state!!! Parameter should be a JSON, but it is a Convo');
2826
+ debug$k('Illegal state!!! Parameter should be a JSON, but it is a Convo');
2765
2827
  } else if (fromJson.beginAsserter) {
2766
2828
  // beginAsserter is one of the fields which are lost
2767
- debug$j('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
2829
+ debug$k('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
2768
2830
  }
2769
2831
  this.scriptingEvents = context.scriptingEvents;
2770
2832
  this.context = context;
@@ -2913,8 +2975,52 @@ class Convo$6 {
2913
2975
  let skipTranscriptStep = false;
2914
2976
  let conditionalGroupId = null;
2915
2977
  let conditionMetInGroup = false;
2916
- for (let i = 0; i < this.conversation.length; i++) {
2978
+ let globalConvoStepParameters = container.caps[Capabilities.SCRIPTING_CONVO_STEP_PARAMETERS] || {};
2979
+ let retryBotMessageTimeoutEnd = null;
2980
+ let retryBotMessageConvoId = null;
2981
+ let retryBotMessageDropBotResponse = false;
2982
+ for (let i = 0; i < this.conversation.length; i = retryBotMessageDropBotResponse ? i : i + 1) {
2983
+ retryBotMessageDropBotResponse = false;
2917
2984
  const convoStep = this.conversation[i];
2985
+ const rawConvoStepParameters = convoStep.logicHooks.find(lh => lh.name === 'CONVO_STEP_PARAMETERS')?.args;
2986
+ let convoStepParameters = {};
2987
+ if (rawConvoStepParameters && rawConvoStepParameters.length) {
2988
+ let params;
2989
+ if (rawConvoStepParameters[0].trim().startsWith('{')) {
2990
+ try {
2991
+ params = JSON.parse(rawConvoStepParameters[0]);
2992
+ } catch (e) {
2993
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Failed to parse convo step parameters from JSON ${rawConvoStepParameters[0]}`);
2994
+ }
2995
+ }
2996
+ if (!params || !Object.keys(params).length) {
2997
+ params = {};
2998
+ for (const param of rawConvoStepParameters) {
2999
+ const semicolon = param.indexOf(':');
3000
+ if (semicolon) {
3001
+ try {
3002
+ const name = param.substring(0, semicolon);
3003
+ const value = param.substring(semicolon + 1);
3004
+ params[name] = value;
3005
+ } catch (e) {
3006
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Failed to parse convo step parameter from arg ${param}`);
3007
+ }
3008
+ }
3009
+ }
3010
+ }
3011
+ if (convoStep.sender === 'begin') {
3012
+ globalConvoStepParameters = Object.assign({}, globalConvoStepParameters || {}, params);
3013
+ } else {
3014
+ convoStepParameters = Object.assign({}, globalConvoStepParameters || {}, params);
3015
+ }
3016
+ } else {
3017
+ if (convoStep.sender !== 'begin') {
3018
+ convoStepParameters = globalConvoStepParameters;
3019
+ }
3020
+ }
3021
+ if (Object.keys(convoStepParameters).length) {
3022
+ debug$k(`${this.header.name}: using convo step parameters ${JSON.stringify(convoStepParameters)}`);
3023
+ }
2918
3024
  const currentStepIndex = i;
2919
3025
  container.eventEmitter.emit(Events.CONVO_STEP_NEXT, container, convoStep, i);
2920
3026
  skipTranscriptStep = false;
@@ -2976,10 +3082,10 @@ class Convo$6 {
2976
3082
  });
2977
3083
  await this._checkBotRepliesConsumed(container);
2978
3084
  const coreMsg = lodash__default["default"].omit(removeBuffers(meMsg), ['sourceData']);
2979
- debug$j(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3085
+ debug$k(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
2980
3086
  await new Promise(resolve => {
2981
- if (container.caps.SIMULATE_WRITING_SPEED && meMsg.messageText && meMsg.messageText.length) {
2982
- setTimeout(() => resolve(), container.caps.SIMULATE_WRITING_SPEED * meMsg.messageText.length);
3087
+ if (container.caps[Capabilities.SIMULATE_WRITING_SPEED] && meMsg.messageText && meMsg.messageText.length) {
3088
+ setTimeout(() => resolve(), container.caps[Capabilities.SIMULATE_WRITING_SPEED] * meMsg.messageText.length);
2983
3089
  } else {
2984
3090
  resolve();
2985
3091
  }
@@ -3012,7 +3118,7 @@ class Convo$6 {
3012
3118
  });
3013
3119
  continue;
3014
3120
  } else {
3015
- debug$j(`${this.header.name}/${convoStep.stepTag}: message not found in #me section, message not sent to container ${util__default["default"].inspect(convoStep)}`);
3121
+ debug$k(`${this.header.name}/${convoStep.stepTag}: message not found in #me section, message not sent to container ${util__default["default"].inspect(convoStep)}`);
3016
3122
  transcriptStep.botEnd = new Date();
3017
3123
  await this.scriptingEvents.onMeEnd({
3018
3124
  convo: this,
@@ -3028,7 +3134,7 @@ class Convo$6 {
3028
3134
  } catch (err) {
3029
3135
  transcriptStep.botEnd = new Date();
3030
3136
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error sending to bot - ${err.message || err}`, err);
3031
- debug$j(failErr);
3137
+ debug$k(failErr);
3032
3138
  try {
3033
3139
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3034
3140
  } catch (failErr) {}
@@ -3041,7 +3147,7 @@ class Convo$6 {
3041
3147
  waitForBotSays = true;
3042
3148
  }
3043
3149
  try {
3044
- debug$j(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3150
+ debug$k(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3045
3151
  await this.scriptingEvents.onBotStart({
3046
3152
  convo: this,
3047
3153
  convoStep,
@@ -3057,11 +3163,11 @@ class Convo$6 {
3057
3163
  transcriptStep.botEnd = new Date();
3058
3164
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3059
3165
  const coreMsg = lodash__default["default"].omit(removeBuffers(botMsg), ['sourceData']);
3060
- debug$j(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3166
+ debug$k(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3061
3167
  } catch (err) {
3062
3168
  transcriptStep.botEnd = new Date();
3063
3169
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error waiting for bot - ${err.message}`, err);
3064
- debug$j(failErr);
3170
+ debug$k(failErr);
3065
3171
  try {
3066
3172
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3067
3173
  } catch (failErr) {}
@@ -3080,11 +3186,11 @@ class Convo$6 {
3080
3186
  if (prepared) {
3081
3187
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3082
3188
  const coreMsg = lodash__default["default"].omit(removeBuffers(botMsg), ['sourceData']);
3083
- debug$j(`${this.header.name}: onBotPrepare (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3189
+ debug$k(`${this.header.name}: onBotPrepare (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3084
3190
  }
3085
3191
  } catch (err) {
3086
3192
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: onBotPrepare error - ${err.message || err}`, err);
3087
- debug$j(failErr);
3193
+ debug$k(failErr);
3088
3194
  try {
3089
3195
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3090
3196
  } catch (failErr) {}
@@ -3105,7 +3211,7 @@ class Convo$6 {
3105
3211
  skipTranscriptStep = true;
3106
3212
  if (endOfConditionalGroup && !conditionMetInGroup && !convoStep.optional) {
3107
3213
  const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: Non of the conditions are met in ${conditionalGroupId ? `'${conditionalGroupId}' ` : ''}condition group`);
3108
- debug$j(failErr);
3214
+ debug$k(failErr);
3109
3215
  throw failErr;
3110
3216
  }
3111
3217
  if (endOfConditionalGroup) {
@@ -3125,7 +3231,7 @@ class Convo$6 {
3125
3231
  }
3126
3232
  if (!botMsg || !botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp) {
3127
3233
  const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3128
- debug$j(failErr);
3234
+ debug$k(failErr);
3129
3235
  try {
3130
3236
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3131
3237
  } catch (failErr) {}
@@ -3133,10 +3239,29 @@ class Convo$6 {
3133
3239
  }
3134
3240
  const isErrorHandledWithOptionConvoStep = err => {
3135
3241
  const nextConvoStep = this.conversation[i + 1];
3242
+ const retryConfig = convoStepParameters?.ignoreNotMatchedBotResponses;
3243
+ const retryOn = convoStep.sender === 'bot' && retryConfig && retryConfig.timeout && retryConfig.mainAsserter;
3136
3244
  if (convoStep.optional && nextConvoStep && nextConvoStep.sender === 'bot') {
3245
+ if (retryOn) {
3246
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Retry failed asserter is ignored on optional convo`);
3247
+ }
3137
3248
  waitForBotSays = false;
3138
3249
  skipTranscriptStep = true;
3139
3250
  return true;
3251
+ } else if (retryOn) {
3252
+ if (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag) {
3253
+ retryBotMessageTimeoutEnd = transcriptStep.stepBegin.getTime() + +retryConfig.timeout;
3254
+ retryBotMessageConvoId = convoStep.stepTag;
3255
+ }
3256
+ const now = new Date().getTime();
3257
+ const timeoutRemaining = retryBotMessageTimeoutEnd - now;
3258
+ if (timeoutRemaining > 0) {
3259
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, timeout remaining: ${timeoutRemaining}, error: "${err.message}"`);
3260
+ retryBotMessageDropBotResponse = true;
3261
+ return false;
3262
+ } else {
3263
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, but timeout is over. error: "${err.message}"`);
3264
+ }
3140
3265
  }
3141
3266
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
3142
3267
  assertErrors.push(err);
@@ -3154,7 +3279,7 @@ class Convo$6 {
3154
3279
  const tomatch = this._resolveUtterancesToMatch(container, Object.assign({}, scriptingMemoryUpdate, scriptingMemory), messageText, botMsg);
3155
3280
  if (convoStep.not) {
3156
3281
  try {
3157
- this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep);
3282
+ this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters);
3158
3283
  } catch (err) {
3159
3284
  if (isErrorHandledWithOptionConvoStep(err)) {
3160
3285
  continue;
@@ -3162,7 +3287,7 @@ class Convo$6 {
3162
3287
  }
3163
3288
  } else {
3164
3289
  try {
3165
- this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep);
3290
+ this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters);
3166
3291
  } catch (err) {
3167
3292
  if (isErrorHandledWithOptionConvoStep(err)) {
3168
3293
  continue;
@@ -3171,7 +3296,7 @@ class Convo$6 {
3171
3296
  }
3172
3297
  } else if (convoStep.sourceData) {
3173
3298
  try {
3174
- this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg);
3299
+ this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg, convoStepParameters);
3175
3300
  } catch (err) {
3176
3301
  if (isErrorHandledWithOptionConvoStep(err)) {
3177
3302
  continue;
@@ -3205,19 +3330,42 @@ class Convo$6 {
3205
3330
  skipTranscriptStep = true;
3206
3331
  continue;
3207
3332
  }
3208
- const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err);
3209
- debug$j(failErr);
3210
- try {
3211
- this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3212
- } catch (failErr) {}
3213
- if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$2) {
3214
- assertErrors.push(err);
3333
+ const errors = err.toArray ? err.toArray() : [];
3334
+ const retryConfig = convoStepParameters?.ignoreNotMatchedBotResponses;
3335
+ const retryOn = convoStep.sender === 'bot' && retryConfig && retryConfig.timeout && errors.length && errors.filter(({
3336
+ type,
3337
+ source,
3338
+ asserter
3339
+ }) => type === 'asserter' && (retryConfig.allAsserters || retryConfig.asserters && retryConfig.asserters.includes(asserter))).length;
3340
+ if (retryOn && (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag)) {
3341
+ retryBotMessageTimeoutEnd = transcriptStep.stepBegin.getTime() + +retryConfig.timeout;
3342
+ retryBotMessageConvoId = convoStep.stepTag;
3343
+ }
3344
+ const now = new Date().getTime();
3345
+ const timeoutRemaining = retryOn && retryBotMessageTimeoutEnd - now;
3346
+ if (retryOn && timeoutRemaining > 0) {
3347
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, timeout remaining: ${timeoutRemaining}, error: "${err.message}"`);
3348
+ retryBotMessageDropBotResponse = true;
3215
3349
  } else {
3216
- throw failErr;
3350
+ if (retryOn && timeoutRemaining <= 0) {
3351
+ debug$k(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, but timeout is over. error: "${err.message}"`);
3352
+ }
3353
+ const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err);
3354
+ debug$k(failErr);
3355
+ try {
3356
+ this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3357
+ } catch (failErr) {}
3358
+ if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$2) {
3359
+ assertErrors.push(err);
3360
+ } else {
3361
+ throw failErr;
3362
+ }
3217
3363
  }
3218
3364
  }
3219
3365
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
3220
3366
  if (assertErrors.length > 0) {
3367
+ // this has no effect, but logically it has to be false
3368
+ retryBotMessageDropBotResponse = false;
3221
3369
  throw botiumErrorFromList$1(assertErrors, {});
3222
3370
  }
3223
3371
  } else {
@@ -3227,7 +3375,7 @@ class Convo$6 {
3227
3375
  }
3228
3376
  } else {
3229
3377
  const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util__default["default"].inspect(convoStep.sender)}`);
3230
- debug$j(failErr);
3378
+ debug$k(failErr);
3231
3379
  try {
3232
3380
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3233
3381
  } catch (failErr) {}
@@ -3277,7 +3425,7 @@ class Convo$6 {
3277
3425
  }
3278
3426
  }
3279
3427
  }
3280
- _compareObject(container, scriptingMemory, convoStep, result, expected, botMsg) {
3428
+ _compareObject(container, scriptingMemory, convoStep, result, expected, botMsg, convoStepParameters) {
3281
3429
  if (expected === null || expected === undefined) return;
3282
3430
  if (lodash__default["default"].isArray(expected)) {
3283
3431
  if (!lodash__default["default"].isArray(result)) {
@@ -3287,12 +3435,12 @@ class Convo$6 {
3287
3435
  throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response expected array length ${expected.length}, got ${result.length}`);
3288
3436
  }
3289
3437
  for (let i = 0; i < expected.length; i++) {
3290
- this._compareObject(container, scriptingMemory, convoStep, result[i], expected[i]);
3438
+ this._compareObject(container, scriptingMemory, convoStep, result[i], expected[i], null, convoStepParameters);
3291
3439
  }
3292
3440
  } else if (lodash__default["default"].isObject(expected)) {
3293
3441
  lodash__default["default"].forOwn(expected, (value, key) => {
3294
3442
  if (Object.prototype.hasOwnProperty.call(result, key)) {
3295
- this._compareObject(container, scriptingMemory, convoStep, result[key], expected[key]);
3443
+ this._compareObject(container, scriptingMemory, convoStep, result[key], expected[key], null, convoStepParameters);
3296
3444
  } else {
3297
3445
  throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response "${result}" missing expected property: ${key}`);
3298
3446
  }
@@ -3301,7 +3449,7 @@ class Convo$6 {
3301
3449
  ScriptingMemory.fill(container, scriptingMemory, result, expected, this.scriptingEvents);
3302
3450
  const response = this._checkNormalizeText(container, result);
3303
3451
  const tomatch = this._resolveUtterancesToMatch(container, scriptingMemory, expected, botMsg);
3304
- this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`);
3452
+ this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, null, convoStepParameters);
3305
3453
  }
3306
3454
  }
3307
3455
  GetScriptingMemoryAllVariables(container) {
@@ -3361,7 +3509,7 @@ class Convo$6 {
3361
3509
  }, []);
3362
3510
  }
3363
3511
  _checkBotRepliesConsumed(container) {
3364
- if (container.caps.SCRIPTING_FORCE_BOT_CONSUMED) {
3512
+ if (container.caps[Capabilities.SCRIPTING_FORCE_BOT_CONSUMED]) {
3365
3513
  const queueLength = container._QueueLength();
3366
3514
  if (queueLength === 1) {
3367
3515
  throw new Error('There is an unread bot reply in queue');
@@ -3433,7 +3581,7 @@ class Convo$6 {
3433
3581
  throw new BotiumError$2(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3434
3582
  }
3435
3583
  _getEffectiveConversationRecursive(partialConvo.conversation, [...parentPConvos, includeLogicHook], result, true);
3436
- debug$j(`Partial convo ${includeLogicHook} included`);
3584
+ debug$k(`Partial convo ${includeLogicHook} included`);
3437
3585
  });
3438
3586
  });
3439
3587
  return result;
@@ -3454,7 +3602,7 @@ var Convo_1 = {
3454
3602
  TranscriptError
3455
3603
  };
3456
3604
 
3457
- const debug$i = debug__default["default"]('botium-core-RetryHelper');
3605
+ const debug$j = debug__default["default"]('botium-core-RetryHelper');
3458
3606
  var RetryHelper_1 = class RetryHelper {
3459
3607
  constructor(caps, section, options = {}) {
3460
3608
  this.retryErrorPatterns = [];
@@ -3478,7 +3626,7 @@ var RetryHelper_1 = class RetryHelper {
3478
3626
  minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash__default["default"].isNil(options.minTimeout) ? 1000 : options.minTimeout)
3479
3627
  };
3480
3628
  if (this.retrySettings.retries > 0) {
3481
- debug$i(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
3629
+ debug$j(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
3482
3630
  }
3483
3631
  }
3484
3632
  shouldRetry(err) {
@@ -3492,26 +3640,36 @@ var RetryHelper_1 = class RetryHelper {
3492
3640
  }
3493
3641
  };
3494
3642
 
3643
+ const debug$i = debug__default["default"]('botium-core-MatchFunctions');
3495
3644
  const {
3496
3645
  toString,
3497
3646
  quoteRegexpString,
3498
3647
  calculateWer: calculateWer$1
3499
3648
  } = helper;
3500
- const _normalize = botresponse => {
3649
+ const _normalize = (botresponse, args, convoStepParameters) => {
3650
+ if (!convoStepParameters) {
3651
+ debug$i('Convo step parameters might be missing!');
3652
+ }
3501
3653
  if (lodash__default["default"].isUndefined(botresponse) || lodash__default["default"].isNil(botresponse)) return '';
3502
3654
  if (lodash__default["default"].isObject(botresponse) && lodash__default["default"].has(botresponse, 'messageText')) {
3503
3655
  return toString(botresponse.messageText) || '';
3504
3656
  }
3505
3657
  return toString(botresponse);
3506
3658
  };
3507
- const regexp = ignoreCase => (botresponse, utterance) => {
3659
+ const regexp = ignoreCase => (botresponse, utterance, args, convoStepParameters) => {
3660
+ if (!convoStepParameters) {
3661
+ debug$i('Convo step parameters might be missing!');
3662
+ }
3508
3663
  if (lodash__default["default"].isUndefined(botresponse)) return false;
3509
3664
  utterance = toString(utterance);
3510
3665
  botresponse = _normalize(botresponse);
3511
3666
  const regexp = ignoreCase ? new RegExp(utterance, 'i') : new RegExp(utterance, '');
3512
3667
  return regexp.test(botresponse);
3513
3668
  };
3514
- const wildcard = ignoreCase => (botresponse, utterance) => {
3669
+ const wildcard = ignoreCase => (botresponse, utterance, args, convoStepParameters) => {
3670
+ if (!convoStepParameters) {
3671
+ debug$i('Convo step parameters might be missing!');
3672
+ }
3515
3673
  if (lodash__default["default"].isUndefined(botresponse)) {
3516
3674
  if (utterance.trim() === '*') return true;else return false;
3517
3675
  }
@@ -3525,7 +3683,10 @@ const wildcard = ignoreCase => (botresponse, utterance) => {
3525
3683
  const regexp = ignoreCase ? new RegExp(utteranceRe, 'i') : new RegExp(utteranceRe, '');
3526
3684
  return regexp.test(botresponse);
3527
3685
  };
3528
- const wildcardExact = ignoreCase => (botresponse, utterance) => {
3686
+ const wildcardExact = ignoreCase => (botresponse, utterance, args, convoStepParameters) => {
3687
+ if (!convoStepParameters) {
3688
+ debug$i('Convo step parameters might be missing!');
3689
+ }
3529
3690
  if (lodash__default["default"].isUndefined(botresponse)) {
3530
3691
  if (utterance.trim() === '*') return true;else return false;
3531
3692
  }
@@ -3539,7 +3700,10 @@ const wildcardExact = ignoreCase => (botresponse, utterance) => {
3539
3700
  const regexp = ignoreCase ? new RegExp(utteranceRe, 'i') : new RegExp(utteranceRe, '');
3540
3701
  return regexp.test(botresponse);
3541
3702
  };
3542
- const include = ignoreCase => (botresponse, utterance) => {
3703
+ const include = ignoreCase => (botresponse, utterance, args, convoStepParameters) => {
3704
+ if (!convoStepParameters) {
3705
+ debug$i('Convo step parameters might be missing!');
3706
+ }
3543
3707
  if (lodash__default["default"].isUndefined(botresponse)) return false;
3544
3708
  utterance = toString(utterance);
3545
3709
  botresponse = _normalize(botresponse);
@@ -3549,7 +3713,10 @@ const include = ignoreCase => (botresponse, utterance) => {
3549
3713
  }
3550
3714
  return botresponse.indexOf(utterance) >= 0;
3551
3715
  };
3552
- const equals = ignoreCase => (botresponse, utterance) => {
3716
+ const equals = ignoreCase => (botresponse, utterance, args, convoStepParameters) => {
3717
+ if (!convoStepParameters) {
3718
+ debug$i('Convo step parameters might be missing!');
3719
+ }
3553
3720
  if (lodash__default["default"].isUndefined(botresponse)) return false;
3554
3721
  utterance = toString(utterance);
3555
3722
  botresponse = _normalize(botresponse);
@@ -3559,10 +3726,13 @@ const equals = ignoreCase => (botresponse, utterance) => {
3559
3726
  }
3560
3727
  return botresponse === utterance;
3561
3728
  };
3562
- const wer = () => (botresponse, utterance, args) => {
3729
+ const wer = () => (botresponse, utterance, args, convoStepParameters) => {
3730
+ if (!convoStepParameters) {
3731
+ debug$i('Convo step parameters might be missing!');
3732
+ }
3563
3733
  botresponse = _normalize(botresponse || '');
3564
3734
  utterance = toString(utterance || '');
3565
- const threshold = [',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100;
3735
+ const threshold = !lodash__default["default"].isNil(convoStepParameters?.matchingModeWer) ? convoStepParameters?.matchingModeWer / 100 : [',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100;
3566
3736
  return calculateWer$1(botresponse, utterance) <= threshold;
3567
3737
  };
3568
3738
  const getMatchFunction$1 = matchingMode => {
@@ -4721,7 +4891,7 @@ var CompilerTxt_1 = class CompilerTxt extends CompilerBase_1 {
4721
4891
  Compile(scriptBuffer, scriptType = Constants.SCRIPTING_TYPE_CONVO) {
4722
4892
  let scriptData = scriptBuffer;
4723
4893
  if (Buffer.isBuffer(scriptBuffer)) scriptData = scriptData.toString();
4724
- const lines = lodash__default["default"].map(scriptData.split(this.eol), line => line.trim());
4894
+ const lines = scriptData.split(this.eol);
4725
4895
  if (scriptType === Constants.SCRIPTING_TYPE_CONVO) {
4726
4896
  return this._compileConvo(lines, false);
4727
4897
  } else if (scriptType === Constants.SCRIPTING_TYPE_PCONVO) {
@@ -4771,7 +4941,6 @@ var CompilerTxt_1 = class CompilerTxt extends CompilerBase_1 {
4771
4941
  };
4772
4942
  lines.forEach(line => {
4773
4943
  currentLineIndex++;
4774
- line = line.trim();
4775
4944
  if (isValidTagLine(line)) {
4776
4945
  pushPrev();
4777
4946
  convoStepSender = line.substr(1).trim();
@@ -5283,7 +5452,7 @@ var CompilerMarkdown_1 = class CompilerMarkdown extends CompilerBase_1 {
5283
5452
  conversation.push(Object.assign({
5284
5453
  sender,
5285
5454
  stepTag: 'Line ' + (step.map[0] + 1)
5286
- }, linesToConvoStep(step.children.map(child => child.content + (child.children ? ' ' + child.children.map(child => child.content).join('|') : '')), sender, this.context, this.eol)));
5455
+ }, linesToConvoStep(step.children.map(child => child.content + (child.children && child.children.length > 0 ? ' ' + child.children.map(child => child.content).join('|') : '')), sender, this.context, this.eol)));
5287
5456
  } else {
5288
5457
  debug$a(`Expected sender ${validSenders.map(s => `'${s}'`).join(' or ')} but found ${sender}`);
5289
5458
  }
@@ -5405,7 +5574,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5405
5574
  }) => {
5406
5575
  return this._createLogicHookPromises({
5407
5576
  hookType: 'onConvoBegin',
5408
- logicHooks: convo.beginLogicHook || [],
5577
+ logicHooks: convo?.beginLogicHook || [],
5409
5578
  convo,
5410
5579
  convoStep,
5411
5580
  scriptingMemory,
@@ -5420,7 +5589,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5420
5589
  }) => {
5421
5590
  return this._createLogicHookPromises({
5422
5591
  hookType: 'onConvoEnd',
5423
- logicHooks: convo.endLogicHook || [],
5592
+ logicHooks: convo?.endLogicHook || [],
5424
5593
  convo,
5425
5594
  convoStep,
5426
5595
  scriptingMemory,
@@ -5435,7 +5604,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5435
5604
  }) => {
5436
5605
  return this._createLogicHookPromises({
5437
5606
  hookType: 'onMeStart',
5438
- logicHooks: convoStep.logicHooks || [],
5607
+ logicHooks: convoStep?.logicHooks || [],
5439
5608
  convo,
5440
5609
  convoStep,
5441
5610
  scriptingMemory,
@@ -5450,7 +5619,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5450
5619
  }) => {
5451
5620
  return this._createLogicHookPromises({
5452
5621
  hookType: 'onMePrepare',
5453
- logicHooks: convoStep.logicHooks || [],
5622
+ logicHooks: convoStep?.logicHooks || [],
5454
5623
  convo,
5455
5624
  convoStep,
5456
5625
  scriptingMemory,
@@ -5465,7 +5634,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5465
5634
  }) => {
5466
5635
  return this._createLogicHookPromises({
5467
5636
  hookType: 'onMeEnd',
5468
- logicHooks: convoStep.logicHooks || [],
5637
+ logicHooks: convoStep?.logicHooks || [],
5469
5638
  convo,
5470
5639
  convoStep,
5471
5640
  scriptingMemory,
@@ -5480,7 +5649,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5480
5649
  }) => {
5481
5650
  return this._createLogicHookPromises({
5482
5651
  hookType: 'onBotStart',
5483
- logicHooks: convoStep.logicHooks || [],
5652
+ logicHooks: convoStep?.logicHooks || [],
5484
5653
  convo,
5485
5654
  convoStep,
5486
5655
  scriptingMemory,
@@ -5495,7 +5664,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5495
5664
  }) => {
5496
5665
  return this._createLogicHookPromises({
5497
5666
  hookType: 'onBotPrepare',
5498
- logicHooks: convoStep.logicHooks || [],
5667
+ logicHooks: convoStep?.logicHooks || [],
5499
5668
  convo,
5500
5669
  convoStep,
5501
5670
  scriptingMemory,
@@ -5510,7 +5679,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5510
5679
  }) => {
5511
5680
  return this._createLogicHookPromises({
5512
5681
  hookType: 'onBotEnd',
5513
- logicHooks: convoStep.logicHooks || [],
5682
+ logicHooks: convoStep?.logicHooks || [],
5514
5683
  convo,
5515
5684
  convoStep,
5516
5685
  scriptingMemory,
@@ -5525,7 +5694,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5525
5694
  }) => {
5526
5695
  return this._createAsserterPromises({
5527
5696
  asserterType: 'assertConvoBegin',
5528
- asserters: convo.beginAsserter || [],
5697
+ asserters: convo?.beginAsserter || [],
5529
5698
  convo,
5530
5699
  convoStep,
5531
5700
  scriptingMemory,
@@ -5540,7 +5709,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5540
5709
  }) => {
5541
5710
  return this._createAsserterPromises({
5542
5711
  asserterType: 'assertConvoStep',
5543
- asserters: convoStep.asserters || [],
5712
+ asserters: convoStep?.asserters || [],
5544
5713
  convo,
5545
5714
  convoStep,
5546
5715
  scriptingMemory,
@@ -5555,7 +5724,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5555
5724
  }) => {
5556
5725
  return this._createAsserterPromises({
5557
5726
  asserterType: 'assertConvoEnd',
5558
- asserters: convo.endAsserter || [],
5727
+ asserters: convo?.endAsserter || [],
5559
5728
  convo,
5560
5729
  convoStep,
5561
5730
  scriptingMemory,
@@ -5584,24 +5753,26 @@ var ScriptingProvider_1 = class ScriptingProvider {
5584
5753
  resolveEmptyIfUnknown
5585
5754
  });
5586
5755
  },
5587
- assertBotResponse: (botresponse, tomatch, stepTag, meMsg) => {
5756
+ assertBotResponse: (botresponse, tomatch, stepTag, meMsg, convoStepParameters = {}) => {
5588
5757
  if (!lodash__default["default"].isArray(tomatch)) {
5589
5758
  tomatch = [tomatch];
5590
5759
  }
5591
5760
  debug$9(`assertBotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} = ${tomatch} ...`);
5592
- const found = lodash__default["default"].find(tomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5761
+ const matchFn = convoStepParameters.matchingMode ? getMatchFunction(convoStepParameters.matchingMode) || this.matchFn : this.matchFn;
5762
+ const found = lodash__default["default"].find(tomatch, utt => matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS], convoStepParameters));
5593
5763
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5594
5764
  if (lodash__default["default"].isNil(found)) {
5595
- if (this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer') {
5765
+ const matchingMode = convoStepParameters.matchingMode || this.caps[Capabilities.SCRIPTING_MATCHING_MODE];
5766
+ if (matchingMode === 'wer') {
5596
5767
  const wer = calculateWer(botresponse, tomatch[0]);
5597
5768
  const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5598
- const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5769
+ const threshold = !lodash__default["default"].isNil(convoStepParameters.matchingModeWer) ? convoStepParameters.matchingModeWer / 100 : [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5599
5770
  const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) higher than accepted (${toPercent(threshold)})`;
5600
5771
  throw new BotiumError$1(message, {
5601
5772
  type: 'asserter',
5602
5773
  source: asserterType,
5603
5774
  params: {
5604
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5775
+ matchingMode,
5605
5776
  args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5606
5777
  },
5607
5778
  context: {
@@ -5639,24 +5810,26 @@ var ScriptingProvider_1 = class ScriptingProvider {
5639
5810
  }
5640
5811
  }
5641
5812
  },
5642
- assertBotNotResponse: (botresponse, nottomatch, stepTag, meMsg) => {
5813
+ assertBotNotResponse: (botresponse, nottomatch, stepTag, meMsg, convoStepParameters = {}) => {
5643
5814
  if (!lodash__default["default"].isArray(nottomatch)) {
5644
5815
  nottomatch = [nottomatch];
5645
5816
  }
5646
5817
  debug$9(`assertBotNotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} != ${nottomatch} ...`);
5647
- const found = lodash__default["default"].find(nottomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5818
+ const matchFn = convoStepParameters.matchingMode ? getMatchFunction(convoStepParameters.matchingMode) || this.matchFn : this.matchFn;
5819
+ const found = lodash__default["default"].find(nottomatch, utt => matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS], convoStepParameters));
5648
5820
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5649
5821
  if (!lodash__default["default"].isNil(found)) {
5650
- if (this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer') {
5822
+ const matchingMode = convoStepParameters.matchingMode || this.caps[Capabilities.SCRIPTING_MATCHING_MODE];
5823
+ if (matchingMode === 'wer') {
5651
5824
  const wer = calculateWer(botresponse, nottomatch[0]);
5652
5825
  const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5653
- const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5826
+ const threshold = !lodash__default["default"].isNil(convoStepParameters.matchingModeWer) ? convoStepParameters.matchingModeWer / 100 : [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5654
5827
  const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) lower than accepted (${toPercent(threshold)})`;
5655
5828
  throw new BotiumError$1(message, {
5656
5829
  type: 'asserter',
5657
5830
  source: asserterType,
5658
5831
  params: {
5659
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5832
+ matchingMode,
5660
5833
  args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5661
5834
  },
5662
5835
  context: {
@@ -5718,6 +5891,22 @@ var ScriptingProvider_1 = class ScriptingProvider {
5718
5891
  assertConvoStep: 'assertNotConvoStep',
5719
5892
  assertConvoEnd: 'assertNotConvoEnd'
5720
5893
  };
5894
+ const updateExceptionContext = (promise, asserter) => {
5895
+ const updateError = err => {
5896
+ if (err instanceof BotiumError$1) {
5897
+ if (!err.context) {
5898
+ err.context = {};
5899
+ }
5900
+ err.context.asserter = asserter.name;
5901
+ throw err;
5902
+ } else {
5903
+ throw botiumErrorFromErr(lodash__default["default"].isString(err) ? err : err.message, err, {
5904
+ asserter: asserter.name
5905
+ });
5906
+ }
5907
+ };
5908
+ return promise.catch(err => updateError(err));
5909
+ };
5721
5910
  const callAsserter = (asserterSpec, asserter, params) => {
5722
5911
  if (asserterSpec.not) {
5723
5912
  const notAsserterType = mapNot[asserterType];
@@ -5741,24 +5930,36 @@ var ScriptingProvider_1 = class ScriptingProvider {
5741
5930
  return p(this.retryHelperAsserter, () => asserter[asserterType](params));
5742
5931
  }
5743
5932
  };
5744
- const convoAsserter = asserters.filter(a => this.asserters[a.name][asserterType]).map(a => callAsserter(a, this.asserters[a.name], {
5745
- convo,
5746
- convoStep,
5747
- scriptingMemory,
5748
- container,
5749
- args: ScriptingMemory.applyToArgs(a.args, scriptingMemory, container.caps, rest.botMsg),
5750
- isGlobal: false,
5751
- ...rest
5752
- }));
5753
- const globalAsserter = Object.values(this.globalAsserter).filter(a => a[asserterType]).map(a => p(this.retryHelperAsserter, () => a[asserterType]({
5754
- convo,
5755
- convoStep,
5756
- scriptingMemory,
5757
- container,
5758
- args: [],
5759
- isGlobal: true,
5760
- ...rest
5761
- })));
5933
+ const convoAsserter = asserters.filter(a => this.asserters[a.name][asserterType]).map(a => ({
5934
+ asserter: a,
5935
+ promise: callAsserter(a, this.asserters[a.name], {
5936
+ convo,
5937
+ convoStep,
5938
+ scriptingMemory,
5939
+ container,
5940
+ args: ScriptingMemory.applyToArgs(a.args, scriptingMemory, container.caps, rest.botMsg),
5941
+ isGlobal: false,
5942
+ ...rest
5943
+ })
5944
+ })).map(({
5945
+ promise,
5946
+ asserter
5947
+ }) => updateExceptionContext(promise, asserter));
5948
+ const globalAsserter = Object.values(this.globalAsserter).filter(a => a[asserterType]).map(a => ({
5949
+ asserter: a,
5950
+ promise: p(this.retryHelperAsserter, () => a[asserterType]({
5951
+ convo,
5952
+ convoStep,
5953
+ scriptingMemory,
5954
+ container,
5955
+ args: [],
5956
+ isGlobal: true,
5957
+ ...rest
5958
+ }))
5959
+ })).map(({
5960
+ promise,
5961
+ asserter
5962
+ }) => updateExceptionContext(promise, asserter));
5762
5963
  const allPromises = [...convoAsserter, ...globalAsserter];
5763
5964
  if (this.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
5764
5965
  return Promise.allSettled(allPromises).then(results => {
@@ -5784,7 +5985,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
5784
5985
  if (hookType !== 'onMeStart' && hookType !== 'onMePrepare' && hookType !== 'onMeEnd' && hookType !== 'onBotStart' && hookType !== 'onBotPrepare' && hookType !== 'onBotEnd' && hookType !== 'onConvoBegin' && hookType !== 'onConvoEnd') {
5785
5986
  throw Error(`Unknown hookType ${hookType}`);
5786
5987
  }
5787
- const convoStepPromises = (logicHooks || []).filter(l => this.logicHooks[l.name][hookType]).map(l => p(this.retryHelperLogicHook, () => this.logicHooks[l.name][hookType]({
5988
+ const localHooks = (logicHooks || []).filter(l => this.logicHooks[l.name][hookType]);
5989
+ const convoStepPromises = localHooks.map(l => p(this.retryHelperLogicHook, () => this.logicHooks[l.name][hookType]({
5788
5990
  convo,
5789
5991
  convoStep,
5790
5992
  scriptingMemory,
@@ -5793,7 +5995,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
5793
5995
  isGlobal: false,
5794
5996
  ...rest
5795
5997
  })));
5796
- const globalPromises = Object.values(this.globalLogicHook).filter(l => l[hookType]).map(l => p(this.retryHelperLogicHook, () => l[hookType]({
5998
+ const globalHooks = Object.values(this.globalLogicHook).filter(l => l[hookType]);
5999
+ const globalPromises = globalHooks.map(l => p(this.retryHelperLogicHook, () => l[hookType]({
5797
6000
  convo,
5798
6001
  convoStep,
5799
6002
  scriptingMemory,
@@ -5803,7 +6006,14 @@ var ScriptingProvider_1 = class ScriptingProvider {
5803
6006
  ...rest
5804
6007
  })));
5805
6008
  const allPromises = [...convoStepPromises, ...globalPromises];
5806
- if (allPromises.length > 0) return Promise.all(allPromises).then(() => true);
6009
+ if (allPromises.length > 0) {
6010
+ return Promise.all(allPromises).then(() => {
6011
+ return {
6012
+ // just returning some humanreadable
6013
+ hooks: [...localHooks, ...globalHooks].map(h => h.name || h.context?.ref || JSON.stringify(h))
6014
+ };
6015
+ });
6016
+ }
5807
6017
  return Promise.resolve(false);
5808
6018
  }
5809
6019
  _createUserInputPromises({
@@ -5813,7 +6023,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5813
6023
  container,
5814
6024
  ...rest
5815
6025
  }) {
5816
- const convoStepPromises = (convoStep.userInputs || []).filter(ui => this.userInputs[ui.name]).map(ui => p(this.retryHelperUserInput, () => this.userInputs[ui.name].setUserInput({
6026
+ const convoStepPromises = (convoStep?.userInputs || []).filter(ui => this.userInputs[ui.name]).map(ui => p(this.retryHelperUserInput, () => this.userInputs[ui.name].setUserInput({
5817
6027
  convo,
5818
6028
  convoStep,
5819
6029
  scriptingMemory,
@@ -5875,6 +6085,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
5875
6085
  }
5876
6086
  };
5877
6087
  }
6088
+
6089
+ // Livechat, and crawler using logichooks too. So they need script context
6090
+ BuildScriptContext() {
6091
+ return this._buildScriptContext();
6092
+ }
5878
6093
  Build() {
5879
6094
  const CompilerXlsx = CompilerXlsx_1;
5880
6095
  this.compilers[Constants.SCRIPTING_FORMAT_XSLX] = new CompilerXlsx(this._buildScriptContext(), this.caps);