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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botium-core",
3
- "version": "1.14.1",
3
+ "version": "1.14.4",
4
4
  "description": "The Selenium for Chatbots",
5
5
  "main": "index.js",
6
6
  "module": "dist/botium-es.js",
@@ -31,12 +31,12 @@
31
31
  },
32
32
  "homepage": "https://www.botium.ai",
33
33
  "dependencies": {
34
- "@babel/runtime": "^7.23.2",
34
+ "@babel/runtime": "^7.23.5",
35
35
  "async": "^3.2.5",
36
36
  "body-parser": "^1.20.2",
37
37
  "boolean": "^3.2.0",
38
38
  "bottleneck": "^2.19.5",
39
- "csv-parse": "^5.5.2",
39
+ "csv-parse": "^5.5.3",
40
40
  "debug": "^4.3.4",
41
41
  "express": "^4.18.2",
42
42
  "globby": "11.0.4",
@@ -45,7 +45,7 @@
45
45
  "is-json": "^2.0.1",
46
46
  "jsonpath": "^1.1.1",
47
47
  "lodash": "^4.17.21",
48
- "markdown-it": "^13.0.2",
48
+ "markdown-it": "^14.0.0",
49
49
  "mime-types": "^2.1.35",
50
50
  "mkdirp": "^3.0.1",
51
51
  "moment": "^2.29.4",
@@ -71,23 +71,23 @@
71
71
  "yaml": "^2.3.4"
72
72
  },
73
73
  "devDependencies": {
74
- "@babel/core": "^7.23.3",
74
+ "@babel/core": "^7.23.5",
75
75
  "@babel/node": "^7.22.19",
76
- "@babel/plugin-transform-runtime": "^7.23.3",
77
- "@babel/preset-env": "^7.23.3",
76
+ "@babel/plugin-transform-runtime": "^7.23.4",
77
+ "@babel/preset-env": "^7.23.5",
78
78
  "chai": "^4.3.10",
79
79
  "chai-as-promised": "^7.1.1",
80
80
  "cross-env": "^7.0.3",
81
- "eslint": "^8.53.0",
81
+ "eslint": "^8.55.0",
82
82
  "eslint-config-standard": "^17.1.0",
83
83
  "eslint-plugin-import": "^2.29.0",
84
84
  "eslint-plugin-mocha": "^10.2.0",
85
- "eslint-plugin-n": "^16.3.1",
85
+ "eslint-plugin-n": "^16.4.0",
86
86
  "eslint-plugin-promise": "^6.1.1",
87
87
  "eslint-plugin-standard": "^4.1.0",
88
88
  "mocha": "^10.2.0",
89
- "nock": "^13.3.8",
90
- "npm-check-updates": "^16.14.6",
89
+ "nock": "^13.4.0",
90
+ "npm-check-updates": "^16.14.11",
91
91
  "nyc": "^15.1.0",
92
92
  "rollup": "2.79.1",
93
93
  "rollup-plugin-babel": "^4.4.0",
@@ -157,6 +157,8 @@ module.exports = {
157
157
  // varnames, testcasenames
158
158
  SCRIPTING_MEMORY_COLUMN_MODE: 'SCRIPTING_MEMORY_COLUMN_MODE',
159
159
  // Botium Lifecycle Hooks
160
+ SCRIPTING_CONVO_STEP_PARAMETERS: 'SCRIPTING_CONVO_STEP_PARAMETERS',
161
+ // Botium Lifecycle Hooks
160
162
  CUSTOMHOOK_ONBUILD: 'CUSTOMHOOK_ONBUILD',
161
163
  CUSTOMHOOK_ONSTART: 'CUSTOMHOOK_ONSTART',
162
164
  CUSTOMHOOK_ONUSERSAYS: 'CUSTOMHOOK_ONUSERSAYS',
@@ -90,6 +90,43 @@ const BotiumError = class BotiumError extends Error {
90
90
  return null
91
91
  }
92
92
  }
93
+
94
+ hasError ({ type, source }) {
95
+ if (this.context) {
96
+ const errArr = _.isArray(this.context) ? this.context : [this.context]
97
+ for (const err of errArr) {
98
+ if (err.type === 'list') {
99
+ for (const internal of err.errors) {
100
+ if ((!type || internal.type === type) && (!source || internal.source === source)) {
101
+ return true
102
+ }
103
+ }
104
+ }
105
+ if ((!type || err.type === type) && (!source || err.source === source)) {
106
+ return true
107
+ }
108
+ }
109
+ } else {
110
+ return false
111
+ }
112
+ }
113
+
114
+ toArray () {
115
+ if (this.context) {
116
+ let result = []
117
+ const errArr = _.isArray(this.context) ? this.context : [this.context]
118
+ for (const err of errArr) {
119
+ if (err.type === 'list') {
120
+ result = result.concat(err.errors)
121
+ } else {
122
+ result.push(err)
123
+ }
124
+ }
125
+ return result
126
+ } else {
127
+ return []
128
+ }
129
+ }
93
130
  }
94
131
 
95
132
  const _getChildErrorsFromContext = (context) => {
@@ -99,11 +136,11 @@ const _getChildErrorsFromContext = (context) => {
99
136
  return false
100
137
  }
101
138
 
102
- const botiumErrorFromErr = (message, err) => {
139
+ const botiumErrorFromErr = (message, err, context = {}) => {
103
140
  if (err instanceof BotiumError) {
104
- return new BotiumError(message, err.context, true)
141
+ return new BotiumError(message, { ...err.context, ...context }, true)
105
142
  } else {
106
- return new BotiumError(message, { err }, true)
143
+ return new BotiumError(message, { err, ...context }, true)
107
144
  }
108
145
  }
109
146
 
@@ -89,7 +89,8 @@ module.exports = class CompilerMarkdown extends CompilerBase {
89
89
  stepTag: 'Line ' + (step.map[0] + 1)
90
90
  },
91
91
  linesToConvoStep(step.children.map(child => child.content +
92
- (child.children ? ' ' + child.children.map(child => child.content).join('|') : '')), sender, this.context, this.eol)
92
+ (child.children && child.children.length > 0 ? ' ' + child.children.map(child => child.content).join('|') : '')
93
+ ), sender, this.context, this.eol)
93
94
  ))
94
95
  } else {
95
96
  debug(`Expected sender ${validSenders.map(s => `'${s}'`).join(' or ')} but found ${sender}`)
@@ -1,5 +1,3 @@
1
- const _ = require('lodash')
2
-
3
1
  const Capabilities = require('../Capabilities')
4
2
  const Constants = require('./Constants')
5
3
  const CompilerBase = require('./CompilerBase')
@@ -37,7 +35,7 @@ module.exports = class CompilerTxt extends CompilerBase {
37
35
  let scriptData = scriptBuffer
38
36
  if (Buffer.isBuffer(scriptBuffer)) scriptData = scriptData.toString()
39
37
 
40
- const lines = _.map(scriptData.split(this.eol), (line) => line.trim())
38
+ const lines = scriptData.split(this.eol)
41
39
 
42
40
  if (scriptType === Constants.SCRIPTING_TYPE_CONVO) {
43
41
  return this._compileConvo(lines, false)
@@ -94,7 +92,6 @@ module.exports = class CompilerTxt extends CompilerBase {
94
92
 
95
93
  lines.forEach((line) => {
96
94
  currentLineIndex++
97
- line = line.trim()
98
95
  if (isValidTagLine(line)) {
99
96
  pushPrev()
100
97
 
@@ -277,8 +277,55 @@ class Convo {
277
277
  let skipTranscriptStep = false
278
278
  let conditionalGroupId = null
279
279
  let conditionMetInGroup = false
280
- for (let i = 0; i < this.conversation.length; i++) {
280
+ let globalConvoStepParameters = container.caps[Capabilities.SCRIPTING_CONVO_STEP_PARAMETERS] || {}
281
+ let retryBotMessageTimeoutEnd = null
282
+ let retryBotMessageConvoId = null
283
+ let retryBotMessageDropBotResponse = false
284
+ for (let i = 0; i < this.conversation.length; i = (retryBotMessageDropBotResponse ? i : i + 1)) {
285
+ retryBotMessageDropBotResponse = false
281
286
  const convoStep = this.conversation[i]
287
+ const rawConvoStepParameters = convoStep.logicHooks.find(lh => lh.name === 'CONVO_STEP_PARAMETERS')?.args
288
+ let convoStepParameters = {}
289
+ if (rawConvoStepParameters && rawConvoStepParameters.length) {
290
+ let params
291
+ if (rawConvoStepParameters[0].trim().startsWith('{')) {
292
+ try {
293
+ params = JSON.parse(rawConvoStepParameters[0])
294
+ } catch (e) {
295
+ debug(`${this.header.name}/${convoStep.stepTag}: Failed to parse convo step parameters from JSON ${rawConvoStepParameters[0]}`)
296
+ }
297
+ }
298
+ if (!params || !Object.keys(params).length) {
299
+ params = {}
300
+ for (const param of rawConvoStepParameters) {
301
+ const semicolon = param.indexOf(':')
302
+ if (semicolon) {
303
+ try {
304
+ const name = param.substring(0, semicolon)
305
+ const value = param.substring(semicolon + 1)
306
+ params[name] = value
307
+ } catch (e) {
308
+ debug(`${this.header.name}/${convoStep.stepTag}: Failed to parse convo step parameter from arg ${param}`)
309
+ }
310
+ }
311
+ }
312
+ }
313
+
314
+ if (convoStep.sender === 'begin') {
315
+ globalConvoStepParameters = Object.assign({}, globalConvoStepParameters || {}, params)
316
+ } else {
317
+ convoStepParameters = Object.assign({}, globalConvoStepParameters || {}, params)
318
+ }
319
+ } else {
320
+ if (convoStep.sender !== 'begin') {
321
+ convoStepParameters = globalConvoStepParameters
322
+ }
323
+ }
324
+
325
+ if (Object.keys(convoStepParameters).length) {
326
+ debug(`${this.header.name}: using convo step parameters ${JSON.stringify(convoStepParameters)}`)
327
+ }
328
+
282
329
  const currentStepIndex = i
283
330
  container.eventEmitter.emit(Events.CONVO_STEP_NEXT, container, convoStep, i)
284
331
  skipTranscriptStep = false
@@ -319,8 +366,8 @@ class Convo {
319
366
  const coreMsg = _.omit(removeBuffers(meMsg), ['sourceData'])
320
367
  debug(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`)
321
368
  await new Promise(resolve => {
322
- if (container.caps.SIMULATE_WRITING_SPEED && meMsg.messageText && meMsg.messageText.length) {
323
- setTimeout(() => resolve(), container.caps.SIMULATE_WRITING_SPEED * meMsg.messageText.length)
369
+ if (container.caps[Capabilities.SIMULATE_WRITING_SPEED] && meMsg.messageText && meMsg.messageText.length) {
370
+ setTimeout(() => resolve(), container.caps[Capabilities.SIMULATE_WRITING_SPEED] * meMsg.messageText.length)
324
371
  } else {
325
372
  resolve()
326
373
  }
@@ -453,11 +500,32 @@ class Convo {
453
500
  }
454
501
  const isErrorHandledWithOptionConvoStep = (err) => {
455
502
  const nextConvoStep = this.conversation[i + 1]
503
+ const retryConfig = convoStepParameters?.ignoreNotMatchedBotResponses
504
+ const retryOn = convoStep.sender === 'bot' && retryConfig && retryConfig.timeout && retryConfig.mainAsserter
456
505
  if (convoStep.optional && nextConvoStep && nextConvoStep.sender === 'bot') {
506
+ if (retryOn) {
507
+ debug(`${this.header.name}/${convoStep.stepTag}: Retry failed asserter is ignored on optional convo`)
508
+ }
457
509
  waitForBotSays = false
458
510
  skipTranscriptStep = true
459
511
  return true
512
+ } else if (retryOn) {
513
+ if (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag) {
514
+ retryBotMessageTimeoutEnd = transcriptStep.stepBegin.getTime() + +retryConfig.timeout
515
+ retryBotMessageConvoId = convoStep.stepTag
516
+ }
517
+
518
+ const now = new Date().getTime()
519
+ const timeoutRemaining = retryBotMessageTimeoutEnd - now
520
+ if (timeoutRemaining > 0) {
521
+ debug(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, timeout remaining: ${timeoutRemaining}, error: "${err.message}"`)
522
+ retryBotMessageDropBotResponse = true
523
+ return false
524
+ } else {
525
+ debug(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, but timeout is over. error: "${err.message}"`)
526
+ }
460
527
  }
528
+
461
529
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
462
530
  assertErrors.push(err)
463
531
  return false
@@ -474,7 +542,7 @@ class Convo {
474
542
  const tomatch = this._resolveUtterancesToMatch(container, Object.assign({}, scriptingMemoryUpdate, scriptingMemory), messageText, botMsg)
475
543
  if (convoStep.not) {
476
544
  try {
477
- this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep)
545
+ this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters)
478
546
  } catch (err) {
479
547
  if (isErrorHandledWithOptionConvoStep(err)) {
480
548
  continue
@@ -482,7 +550,7 @@ class Convo {
482
550
  }
483
551
  } else {
484
552
  try {
485
- this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep)
553
+ this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters)
486
554
  } catch (err) {
487
555
  if (isErrorHandledWithOptionConvoStep(err)) {
488
556
  continue
@@ -491,7 +559,7 @@ class Convo {
491
559
  }
492
560
  } else if (convoStep.sourceData) {
493
561
  try {
494
- this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg)
562
+ this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg, convoStepParameters)
495
563
  } catch (err) {
496
564
  if (isErrorHandledWithOptionConvoStep(err)) {
497
565
  continue
@@ -509,20 +577,46 @@ class Convo {
509
577
  skipTranscriptStep = true
510
578
  continue
511
579
  }
512
- const failErr = botiumErrorFromErr(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err)
513
- debug(failErr)
514
- try {
515
- this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep)
516
- } catch (failErr) {
580
+
581
+ const errors = err.toArray ? err.toArray() : []
582
+ const retryConfig = convoStepParameters?.ignoreNotMatchedBotResponses
583
+ const retryOn =
584
+ convoStep.sender === 'bot' &&
585
+ retryConfig &&
586
+ retryConfig.timeout &&
587
+ errors.length &&
588
+ errors.filter(({ type, source, asserter }) => type === 'asserter' && (retryConfig.allAsserters || (retryConfig.asserters && retryConfig.asserters.includes(asserter)))).length
589
+ if (retryOn && (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag)) {
590
+ retryBotMessageTimeoutEnd = transcriptStep.stepBegin.getTime() + +retryConfig.timeout
591
+ retryBotMessageConvoId = convoStep.stepTag
517
592
  }
518
- if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError) {
519
- assertErrors.push(err)
593
+
594
+ const now = new Date().getTime()
595
+ const timeoutRemaining = retryOn && (retryBotMessageTimeoutEnd - now)
596
+ if (retryOn && timeoutRemaining > 0) {
597
+ debug(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, timeout remaining: ${timeoutRemaining}, error: "${err.message}"`)
598
+ retryBotMessageDropBotResponse = true
520
599
  } else {
521
- throw failErr
600
+ if (retryOn && timeoutRemaining <= 0) {
601
+ debug(`${this.header.name}/${convoStep.stepTag}: Convo step retry on, but timeout is over. error: "${err.message}"`)
602
+ }
603
+ const failErr = botiumErrorFromErr(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err)
604
+ debug(failErr)
605
+ try {
606
+ this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep)
607
+ } catch (failErr) {
608
+ }
609
+ if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError) {
610
+ assertErrors.push(err)
611
+ } else {
612
+ throw failErr
613
+ }
522
614
  }
523
615
  }
524
616
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
525
617
  if (assertErrors.length > 0) {
618
+ // this has no effect, but logically it has to be false
619
+ retryBotMessageDropBotResponse = false
526
620
  throw botiumErrorFromList(assertErrors, {})
527
621
  }
528
622
  } else {
@@ -580,7 +674,7 @@ class Convo {
580
674
  }
581
675
  }
582
676
 
583
- _compareObject (container, scriptingMemory, convoStep, result, expected, botMsg) {
677
+ _compareObject (container, scriptingMemory, convoStep, result, expected, botMsg, convoStepParameters) {
584
678
  if (expected === null || expected === undefined) return
585
679
 
586
680
  if (_.isArray(expected)) {
@@ -591,12 +685,12 @@ class Convo {
591
685
  throw new BotiumError(`${this.header.name}/${convoStep.stepTag}: bot response expected array length ${expected.length}, got ${result.length}`)
592
686
  }
593
687
  for (let i = 0; i < expected.length; i++) {
594
- this._compareObject(container, scriptingMemory, convoStep, result[i], expected[i])
688
+ this._compareObject(container, scriptingMemory, convoStep, result[i], expected[i], null, convoStepParameters)
595
689
  }
596
690
  } else if (_.isObject(expected)) {
597
691
  _.forOwn(expected, (value, key) => {
598
692
  if (Object.prototype.hasOwnProperty.call(result, key)) {
599
- this._compareObject(container, scriptingMemory, convoStep, result[key], expected[key])
693
+ this._compareObject(container, scriptingMemory, convoStep, result[key], expected[key], null, convoStepParameters)
600
694
  } else {
601
695
  throw new BotiumError(`${this.header.name}/${convoStep.stepTag}: bot response "${result}" missing expected property: ${key}`)
602
696
  }
@@ -605,7 +699,7 @@ class Convo {
605
699
  ScriptingMemory.fill(container, scriptingMemory, result, expected, this.scriptingEvents)
606
700
  const response = this._checkNormalizeText(container, result)
607
701
  const tomatch = this._resolveUtterancesToMatch(container, scriptingMemory, expected, botMsg)
608
- this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`)
702
+ this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, null, convoStepParameters)
609
703
  }
610
704
  }
611
705
 
@@ -673,7 +767,7 @@ class Convo {
673
767
  }
674
768
 
675
769
  _checkBotRepliesConsumed (container) {
676
- if (container.caps.SCRIPTING_FORCE_BOT_CONSUMED) {
770
+ if (container.caps[Capabilities.SCRIPTING_FORCE_BOT_CONSUMED]) {
677
771
  const queueLength = container._QueueLength()
678
772
  if (queueLength === 1) {
679
773
  throw new Error('There is an unread bot reply in queue')
@@ -1,8 +1,12 @@
1
1
  const _ = require('lodash')
2
+ const debug = require('debug')('botium-core-MatchFunctions')
2
3
 
3
4
  const { toString, quoteRegexpString, calculateWer } = require('./helper')
4
5
 
5
- const _normalize = (botresponse) => {
6
+ const _normalize = (botresponse, args, convoStepParameters) => {
7
+ if (!convoStepParameters) {
8
+ debug('Convo step parameters might be missing!')
9
+ }
6
10
  if (_.isUndefined(botresponse) || _.isNil(botresponse)) return ''
7
11
  if (_.isObject(botresponse) && _.has(botresponse, 'messageText')) {
8
12
  return toString(botresponse.messageText) || ''
@@ -10,7 +14,10 @@ const _normalize = (botresponse) => {
10
14
  return toString(botresponse)
11
15
  }
12
16
 
13
- const regexp = (ignoreCase) => (botresponse, utterance) => {
17
+ const regexp = (ignoreCase) => (botresponse, utterance, args, convoStepParameters) => {
18
+ if (!convoStepParameters) {
19
+ debug('Convo step parameters might be missing!')
20
+ }
14
21
  if (_.isUndefined(botresponse)) return false
15
22
  utterance = toString(utterance)
16
23
  botresponse = _normalize(botresponse)
@@ -19,7 +26,10 @@ const regexp = (ignoreCase) => (botresponse, utterance) => {
19
26
  return regexp.test(botresponse)
20
27
  }
21
28
 
22
- const wildcard = (ignoreCase) => (botresponse, utterance) => {
29
+ const wildcard = (ignoreCase) => (botresponse, utterance, args, convoStepParameters) => {
30
+ if (!convoStepParameters) {
31
+ debug('Convo step parameters might be missing!')
32
+ }
23
33
  if (_.isUndefined(botresponse)) {
24
34
  if (utterance.trim() === '*') return true
25
35
  else return false
@@ -37,7 +47,10 @@ const wildcard = (ignoreCase) => (botresponse, utterance) => {
37
47
  return regexp.test(botresponse)
38
48
  }
39
49
 
40
- const wildcardExact = (ignoreCase) => (botresponse, utterance) => {
50
+ const wildcardExact = (ignoreCase) => (botresponse, utterance, args, convoStepParameters) => {
51
+ if (!convoStepParameters) {
52
+ debug('Convo step parameters might be missing!')
53
+ }
41
54
  if (_.isUndefined(botresponse)) {
42
55
  if (utterance.trim() === '*') return true
43
56
  else return false
@@ -55,7 +68,10 @@ const wildcardExact = (ignoreCase) => (botresponse, utterance) => {
55
68
  return regexp.test(botresponse)
56
69
  }
57
70
 
58
- const include = (ignoreCase) => (botresponse, utterance) => {
71
+ const include = (ignoreCase) => (botresponse, utterance, args, convoStepParameters) => {
72
+ if (!convoStepParameters) {
73
+ debug('Convo step parameters might be missing!')
74
+ }
59
75
  if (_.isUndefined(botresponse)) return false
60
76
  utterance = toString(utterance)
61
77
  botresponse = _normalize(botresponse)
@@ -67,7 +83,10 @@ const include = (ignoreCase) => (botresponse, utterance) => {
67
83
  return botresponse.indexOf(utterance) >= 0
68
84
  }
69
85
 
70
- const equals = (ignoreCase) => (botresponse, utterance) => {
86
+ const equals = (ignoreCase) => (botresponse, utterance, args, convoStepParameters) => {
87
+ if (!convoStepParameters) {
88
+ debug('Convo step parameters might be missing!')
89
+ }
71
90
  if (_.isUndefined(botresponse)) return false
72
91
  utterance = toString(utterance)
73
92
  botresponse = _normalize(botresponse)
@@ -79,11 +98,14 @@ const equals = (ignoreCase) => (botresponse, utterance) => {
79
98
  return botresponse === utterance
80
99
  }
81
100
 
82
- const wer = () => (botresponse, utterance, args) => {
101
+ const wer = () => (botresponse, utterance, args, convoStepParameters) => {
102
+ if (!convoStepParameters) {
103
+ debug('Convo step parameters might be missing!')
104
+ }
83
105
  botresponse = _normalize(botresponse || '')
84
106
  utterance = toString(utterance || '')
85
107
 
86
- const threshold = ([',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100)
108
+ const threshold = !_.isNil(convoStepParameters?.matchingModeWer) ? (convoStepParameters?.matchingModeWer / 100) : ([',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100)
87
109
  return calculateWer(botresponse, utterance) <= threshold
88
110
  }
89
111
 
@@ -261,6 +261,13 @@ const _apply = (scriptingMemory, str, caps, mockMsg) => {
261
261
  return arg
262
262
  }
263
263
  })
264
+ args = args.map(arg => {
265
+ const argStr = `${arg}`
266
+ if (argStr.startsWith('$')) {
267
+ return scriptingMemory[argStr.substring(1)] || arg
268
+ }
269
+ return arg
270
+ })
264
271
  str = str.replace(match, SCRIPTING_FUNCTIONS[key].handler(caps, ...args, mockMsg))
265
272
  } else {
266
273
  str = str.replace(match, SCRIPTING_FUNCTIONS[key].handler(caps))