botium-core 1.12.6 → 1.13.2

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.
@@ -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$l = require('debug');
17
+ var debug$m = require('debug');
18
18
  var vm2 = require('vm2');
19
19
  var isClass = require('is-class');
20
20
  var crypto = require('crypto');
@@ -53,7 +53,7 @@ var randomatic__default = /*#__PURE__*/_interopDefaultLegacy(randomatic);
53
53
  var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
54
54
  var boolean__default = /*#__PURE__*/_interopDefaultLegacy(boolean$1);
55
55
  var events__default = /*#__PURE__*/_interopDefaultLegacy(events);
56
- var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$l);
56
+ var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$m);
57
57
  var vm2__default = /*#__PURE__*/_interopDefaultLegacy(vm2);
58
58
  var isClass__default = /*#__PURE__*/_interopDefaultLegacy(isClass);
59
59
  var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
@@ -79,7 +79,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
79
79
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
80
80
 
81
81
  var name = "botium-core";
82
- var version$1 = "1.12.6";
82
+ var version$1 = "1.13.2";
83
83
  var description = "The Selenium for Chatbots";
84
84
  var main = "index.js";
85
85
  var module$1 = "dist/botium-es.js";
@@ -111,25 +111,25 @@ var bugs = {
111
111
  };
112
112
  var homepage = "https://www.botium.ai";
113
113
  var dependencies = {
114
- "@babel/runtime": "^7.17.9",
115
- async: "^3.2.3",
114
+ "@babel/runtime": "^7.18.6",
115
+ async: "^3.2.4",
116
116
  "body-parser": "^1.20.0",
117
117
  boolean: "^3.2.0",
118
118
  bottleneck: "^2.19.5",
119
- "csv-parse": "^5.0.4",
119
+ "csv-parse": "^5.3.0",
120
120
  debug: "^4.3.4",
121
121
  esprima: "^4.0.1",
122
- express: "^4.17.3",
122
+ express: "^4.18.1",
123
123
  globby: "11.0.4",
124
- ioredis: "^5.0.4",
124
+ ioredis: "^5.1.0",
125
125
  "is-class": "^0.0.9",
126
126
  "is-json": "^2.0.1",
127
127
  jsonpath: "^1.1.1",
128
128
  lodash: "^4.17.21",
129
- "markdown-it": "^12.3.2",
129
+ "markdown-it": "^13.0.1",
130
130
  "mime-types": "^2.1.35",
131
131
  mkdirp: "^1.0.4",
132
- moment: "^2.29.3",
132
+ moment: "^2.29.4",
133
133
  mustache: "^4.2.0",
134
134
  "promise-retry": "^2.0.1",
135
135
  "promise.allsettled": "^1.0.5",
@@ -138,39 +138,39 @@ var dependencies = {
138
138
  rimraf: "^3.0.2",
139
139
  "sanitize-filename": "^1.6.3",
140
140
  slugify: "^1.6.5",
141
- "socket.io": "^4.4.1",
142
- "socket.io-client": "^4.4.1",
141
+ "socket.io": "^4.5.1",
142
+ "socket.io-client": "^4.5.1",
143
143
  "socketio-auth": "^0.1.1",
144
144
  "swagger-jsdoc": "^6.2.1",
145
- "swagger-ui-express": "^4.3.0",
145
+ "swagger-ui-express": "^4.4.0",
146
146
  uuid: "^8.3.2",
147
- vm2: "^3.9.9",
147
+ vm2: "^3.9.10",
148
148
  "write-yaml": "^1.0.0",
149
149
  xlsx: "^0.18.5",
150
- xregexp: "^5.1.0",
151
- yaml: "^2.0.1"
150
+ xregexp: "^5.1.1",
151
+ yaml: "^2.1.1"
152
152
  };
153
153
  var devDependencies = {
154
- "@babel/core": "^7.17.9",
155
- "@babel/node": "^7.16.8",
156
- "@babel/plugin-transform-runtime": "^7.17.0",
157
- "@babel/preset-env": "^7.16.11",
154
+ "@babel/core": "^7.18.6",
155
+ "@babel/node": "^7.18.6",
156
+ "@babel/plugin-transform-runtime": "^7.18.6",
157
+ "@babel/preset-env": "^7.18.6",
158
158
  chai: "^4.3.6",
159
159
  "chai-as-promised": "^7.1.1",
160
160
  "cross-env": "^7.0.3",
161
- eslint: "^8.13.0",
161
+ eslint: "^8.19.0",
162
162
  "eslint-config-standard": "^17.0.0",
163
163
  "eslint-plugin-import": "^2.26.0",
164
- "eslint-plugin-n": "^15.1.0",
164
+ "eslint-plugin-n": "^15.2.4",
165
165
  "eslint-plugin-promise": "^6.0.0",
166
166
  "eslint-plugin-standard": "^4.1.0",
167
167
  "license-checker": "^25.0.1",
168
168
  "license-compatibility-checker": "^0.3.5",
169
- mocha: "^9.2.2",
170
- nock: "^13.2.4",
171
- "npm-check-updates": "^12.5.9",
169
+ mocha: "^10.0.0",
170
+ nock: "^13.2.8",
171
+ "npm-check-updates": "^15.2.6",
172
172
  nyc: "^15.1.0",
173
- rollup: "^2.70.2",
173
+ rollup: "^2.76.0",
174
174
  "rollup-plugin-babel": "^4.4.0",
175
175
  "rollup-plugin-commonjs": "^10.1.0",
176
176
  "rollup-plugin-json": "^4.0.0",
@@ -319,6 +319,10 @@ var Capabilities = {
319
319
  SCRIPTING_XLSX_SHEETNAMES_PCONVOS: 'SCRIPTING_XLSX_SHEETNAMES_PCONVOS',
320
320
  SCRIPTING_XLSX_SHEETNAMES_UTTERANCES: 'SCRIPTING_XLSX_SHEETNAMES_UTTERANCES',
321
321
  SCRIPTING_XLSX_SHEETNAMES_SCRIPTING_MEMORY: 'SCRIPTING_XLSX_SHEETNAMES_SCRIPTING_MEMORY',
322
+ // hidden capability. All newly in Box created testsets will have this as true. CsvCompiler
323
+ // - throws less error (Box reads csv files as utterances, and convo. Compiler cant throw exception if a file is correct, but box tries to load it with incorrect script type)
324
+ // 4 or more colums are compiled just as utterances.
325
+ SCRIPTING_CSV_LEGACY_MODE_OFF: 'SCRIPTING_CSV_LEGACY_MODE_OFF',
322
326
  SCRIPTING_CSV_DELIMITER: 'SCRIPTING_CSV_DELIMITER',
323
327
  SCRIPTING_CSV_SKIP_HEADER: 'SCRIPTING_CSV_SKIP_HEADER',
324
328
  SCRIPTING_CSV_QUOTE: 'SCRIPTING_CSV_QUOTE',
@@ -328,6 +332,9 @@ var Capabilities = {
328
332
  SCRIPTING_CSV_MULTIROW_COLUMN_TEXT: 'SCRIPTING_CSV_MULTIROW_COLUMN_TEXT',
329
333
  SCRIPTING_CSV_QA_COLUMN_QUESTION: 'SCRIPTING_CSV_QA_COLUMN_QUESTION',
330
334
  SCRIPTING_CSV_QA_COLUMN_ANSWER: 'SCRIPTING_CSV_QA_COLUMN_ANSWER',
335
+ SCRIPTING_CSV_UTTERANCE_STARTROW: 'SCRIPTING_CSV_UTTERANCE_STARTROW',
336
+ SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER: 'SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER',
337
+ SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY: 'SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY',
331
338
  SCRIPTING_NORMALIZE_TEXT: 'SCRIPTING_NORMALIZE_TEXT',
332
339
  SCRIPTING_ENABLE_MEMORY: 'SCRIPTING_ENABLE_MEMORY',
333
340
  SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS: 'SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS',
@@ -469,6 +476,7 @@ Capabilities.SCRIPTING_XLSX_SHEETNAMES;
469
476
  Capabilities.SCRIPTING_XLSX_SHEETNAMES_PCONVOS;
470
477
  Capabilities.SCRIPTING_XLSX_SHEETNAMES_UTTERANCES;
471
478
  Capabilities.SCRIPTING_XLSX_SHEETNAMES_SCRIPTING_MEMORY;
479
+ Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF;
472
480
  Capabilities.SCRIPTING_CSV_DELIMITER;
473
481
  Capabilities.SCRIPTING_CSV_SKIP_HEADER;
474
482
  Capabilities.SCRIPTING_CSV_QUOTE;
@@ -478,6 +486,9 @@ Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_SENDER;
478
486
  Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_TEXT;
479
487
  Capabilities.SCRIPTING_CSV_QA_COLUMN_QUESTION;
480
488
  Capabilities.SCRIPTING_CSV_QA_COLUMN_ANSWER;
489
+ Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW;
490
+ Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER;
491
+ Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY;
481
492
  Capabilities.SCRIPTING_NORMALIZE_TEXT;
482
493
  Capabilities.SCRIPTING_ENABLE_MEMORY;
483
494
  Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS;
@@ -1220,7 +1231,7 @@ LogicHookConsts.DEFAULT_USER_INPUTS;
1220
1231
  const {
1221
1232
  NodeVM: NodeVM$2
1222
1233
  } = vm2__default["default"];
1223
- const debug$k = debug__default["default"]('botium-core-asserterUtils');
1234
+ const debug$l = debug__default["default"]('botium-core-asserterUtils');
1224
1235
  const {
1225
1236
  BotiumError: BotiumError$6
1226
1237
  } = BotiumError_1;
@@ -1285,7 +1296,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1285
1296
  _fetchAsserters() {
1286
1297
  this.caps[Capabilities.ASSERTERS].forEach(asserter => {
1287
1298
  if (this.asserters[asserter.ref]) {
1288
- debug$k(`${asserter.ref} asserter already exists, overwriting.`);
1299
+ debug$l(`${asserter.ref} asserter already exists, overwriting.`);
1289
1300
  }
1290
1301
 
1291
1302
  this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
@@ -1299,7 +1310,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1299
1310
  _fetchLogicHooks() {
1300
1311
  this.caps[Capabilities.LOGIC_HOOKS].forEach(logicHook => {
1301
1312
  if (this.logicHooks[logicHook.ref]) {
1302
- debug$k(`${logicHook.ref} logic hook already exists, overwriting.`);
1313
+ debug$l(`${logicHook.ref} logic hook already exists, overwriting.`);
1303
1314
  }
1304
1315
 
1305
1316
  this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook');
@@ -1313,7 +1324,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1313
1324
  _fetchUserInputs() {
1314
1325
  this.caps[Capabilities.USER_INPUTS].forEach(userInput => {
1315
1326
  if (this.userInputs[userInput.ref]) {
1316
- debug$k(`${userInput.ref} userinput already exists, overwriting.`);
1327
+ debug$l(`${userInput.ref} userinput already exists, overwriting.`);
1317
1328
  }
1318
1329
 
1319
1330
  this.userInputs[userInput.ref] = this._loadClass(userInput, 'userinput');
@@ -1456,7 +1467,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1456
1467
  });
1457
1468
  return vm.run(script);
1458
1469
  } catch (err) {
1459
- throw new Error(`${err.message || err}`);
1470
+ throw new Error(`Script ${key} is not valid - ${err.message || err}`);
1460
1471
  }
1461
1472
  } else {
1462
1473
  throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`);
@@ -1547,7 +1558,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1547
1558
  }
1548
1559
  }
1549
1560
 
1550
- loadErr.forEach(debug$k);
1561
+ loadErr.forEach(debug$l);
1551
1562
  }
1552
1563
 
1553
1564
  throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`);
@@ -2406,7 +2417,7 @@ var helper = {
2406
2417
  linesToScriptingMemories: linesToScriptingMemories$2
2407
2418
  };
2408
2419
 
2409
- const debug$j = debug__default["default"]('botium-core-ScriptingMemory');
2420
+ const debug$k = debug__default["default"]('botium-core-ScriptingMemory');
2410
2421
  const {
2411
2422
  v1: uuidv1
2412
2423
  } = uuid__default["default"];
@@ -2664,7 +2675,7 @@ const extractVarNames = text => {
2664
2675
  };
2665
2676
 
2666
2677
  const fill = (container, scriptingMemory, result, utterance, scriptingEvents) => {
2667
- debug$j(`fill start: ${util__default["default"].inspect(scriptingMemory)}`);
2678
+ debug$k(`fill start: ${util__default["default"].inspect(scriptingMemory)}`);
2668
2679
  let varRegex;
2669
2680
 
2670
2681
  switch (container.caps[Capabilities.SCRIPTING_MEMORY_MATCHING_MODE]) {
@@ -2708,14 +2719,14 @@ const fill = (container, scriptingMemory, result, utterance, scriptingEvents) =>
2708
2719
  const varName = varMatches[i - 1];
2709
2720
 
2710
2721
  if (RESERVED_WORDS.indexOf(varName) >= 0) {
2711
- debug$j(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2722
+ debug$k(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2712
2723
  } else {
2713
2724
  scriptingMemory[varName] = resultMatches[i];
2714
2725
  }
2715
2726
  }
2716
2727
  }
2717
2728
  });
2718
- debug$j(`fill end: ${util__default["default"].inspect(scriptingMemory)}`);
2729
+ debug$k(`fill end: ${util__default["default"].inspect(scriptingMemory)}`);
2719
2730
  }
2720
2731
  };
2721
2732
 
@@ -2734,6 +2745,47 @@ ScriptingMemory.extractVarNames;
2734
2745
  ScriptingMemory.RESERVED_WORDS;
2735
2746
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2736
2747
 
2748
+ const debug$j = debug__default["default"]('botium-core-RetryHelper');
2749
+ var RetryHelper_1 = class RetryHelper {
2750
+ constructor(caps, section, options = {}) {
2751
+ this.retryErrorPatterns = [];
2752
+ const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
2753
+
2754
+ if (onErrorRegexp) {
2755
+ if (lodash__default["default"].isArray(onErrorRegexp)) {
2756
+ onErrorRegexp.forEach(r => {
2757
+ if (lodash__default["default"].isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
2758
+ });
2759
+ } else if (lodash__default["default"].isString(onErrorRegexp)) {
2760
+ this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
2761
+ } else {
2762
+ this.retryErrorPatterns.push(onErrorRegexp);
2763
+ }
2764
+ } // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
2765
+
2766
+
2767
+ this.retrySettings = {
2768
+ retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash__default["default"].isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
2769
+ factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash__default["default"].isNil(options.factor) ? 1 : options.factor),
2770
+ minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash__default["default"].isNil(options.minTimeout) ? 1000 : options.minTimeout)
2771
+ };
2772
+ debug$j(`Retry for ${section} is ${this.retrySettings.retries > 0 ? 'enabled' : 'disabled'}. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
2773
+ }
2774
+
2775
+ shouldRetry(err) {
2776
+ if (!err) return false;
2777
+ if (this.retryErrorPatterns.length === 0) return true;
2778
+ const errString = util__default["default"].inspect(err);
2779
+
2780
+ for (const re of this.retryErrorPatterns) {
2781
+ if (errString.match(re)) return true;
2782
+ }
2783
+
2784
+ return false;
2785
+ }
2786
+
2787
+ };
2788
+
2737
2789
  const debug$i = debug__default["default"]('botium-core-Convo');
2738
2790
  const {
2739
2791
  BotiumError: BotiumError$4,
@@ -2959,6 +3011,26 @@ class Convo$6 {
2959
3011
  }
2960
3012
 
2961
3013
  async Run(container) {
3014
+ const retryHelper = new RetryHelper_1(container.caps, 'CONVO');
3015
+ return promiseRetry__default["default"](async (retry, number) => {
3016
+ return this.RunImpl(container).catch(err => {
3017
+ const retryRemaining = retryHelper.retrySettings.retries - number + 1;
3018
+
3019
+ if (retryHelper.shouldRetry(err)) {
3020
+ debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry ${retryRemaining > 0 ? 'enabled' : 'disabled'} (remaining #${retryRemaining}/${retryHelper.retrySettings.retries}, criterion matches)`);
3021
+ retry(err);
3022
+ } else {
3023
+ if (retryHelper.retryErrorPatterns.length > 0) {
3024
+ debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry 'disabled' (remaining (#${retryRemaining}/${retryHelper.retrySettings.retries}), criterion does not match)`);
3025
+ }
3026
+
3027
+ throw err;
3028
+ }
3029
+ });
3030
+ }, retryHelper.retrySettings);
3031
+ }
3032
+
3033
+ async RunImpl(container) {
2962
3034
  const transcript = new Transcript({
2963
3035
  steps: [],
2964
3036
  attachments: [],
@@ -3630,42 +3702,6 @@ var Convo_1 = {
3630
3702
  ConvoStep: ConvoStep$1
3631
3703
  };
3632
3704
 
3633
- var RetryHelper_1 = class RetryHelper {
3634
- constructor(caps, section) {
3635
- this.retrySettings = {
3636
- retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || 1,
3637
- factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || 1,
3638
- minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || 1000
3639
- };
3640
- this.retryErrorPatterns = [];
3641
- const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
3642
-
3643
- if (onErrorRegexp) {
3644
- if (lodash__default["default"].isArray(onErrorRegexp)) {
3645
- onErrorRegexp.forEach(r => {
3646
- if (lodash__default["default"].isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
3647
- });
3648
- } else if (lodash__default["default"].isString(onErrorRegexp)) {
3649
- this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
3650
- } else {
3651
- this.retryErrorPatterns.push(onErrorRegexp);
3652
- }
3653
- }
3654
- }
3655
-
3656
- shouldRetry(err) {
3657
- if (!err || this.retryErrorPatterns.length === 0) return false;
3658
- const errString = util__default["default"].inspect(err);
3659
-
3660
- for (const re of this.retryErrorPatterns) {
3661
- if (errString.match(re)) return true;
3662
- }
3663
-
3664
- return false;
3665
- }
3666
-
3667
- };
3668
-
3669
3705
  const {
3670
3706
  toString,
3671
3707
  quoteRegexpString
@@ -5338,6 +5374,8 @@ var CompilerCsv_1 = class CompilerCsv extends CompilerBase_1 {
5338
5374
  return [];
5339
5375
  }
5340
5376
 
5377
+ const legacyModeOn = !this._GetOptionalCapability(Capabilities.SCRIPTING_CSV_LEGACY_MODE_OFF, false);
5378
+
5341
5379
  let delimiter = this._GetOptionalCapability(Capabilities.SCRIPTING_CSV_DELIMITER);
5342
5380
 
5343
5381
  if (!delimiter) {
@@ -5365,7 +5403,8 @@ var CompilerCsv_1 = class CompilerCsv extends CompilerBase_1 {
5365
5403
  delimiter,
5366
5404
  escape: this.caps[Capabilities.SCRIPTING_CSV_ESCAPE],
5367
5405
  quote: this.caps[Capabilities.SCRIPTING_CSV_QUOTE],
5368
- columns: false
5406
+ columns: false,
5407
+ relax_column_count: true
5369
5408
  });
5370
5409
  } catch (err) {
5371
5410
  throw new Error(`Invalid CSV: ${err.message || err}`);
@@ -5375,120 +5414,175 @@ var CompilerCsv_1 = class CompilerCsv extends CompilerBase_1 {
5375
5414
  return [];
5376
5415
  }
5377
5416
 
5378
- if (rows[0].length === 1) {
5379
- debug$c('Found 1-column CSV file, treating it as utterance file');
5417
+ const columnCount = rows[0].length;
5418
+ debug$c(`Legacy mode ${legacyModeOn ? 'on' : 'off'} rows ${rows.length} columns ${columnCount}`);
5380
5419
 
5381
- if (scriptType === Constants.SCRIPTING_TYPE_UTTERANCES) {
5382
- const result = [{
5383
- name: rows[0][0],
5384
- utterances: rows.slice(1).map(r => r[0])
5385
- }];
5386
- this.context.AddUtterances(result);
5387
- return result;
5388
- } else {
5420
+ if (scriptType === Constants.SCRIPTING_TYPE_CONVO || scriptType === Constants.SCRIPTING_TYPE_PCONVO) {
5421
+ if (columnCount === 1 || !legacyModeOn && columnCount > 3) {
5422
+ debug$c(`Invalid column count '${columnCount}' in convo mode`);
5389
5423
  return [];
5390
5424
  }
5391
- }
5392
5425
 
5393
- if (scriptType !== Constants.SCRIPTING_TYPE_CONVO && scriptType !== Constants.SCRIPTING_TYPE_PCONVO) {
5394
- return [];
5395
- }
5426
+ let header = null;
5396
5427
 
5397
- let header = null;
5428
+ if (rows.length > 0 && this.caps[Capabilities.SCRIPTING_CSV_SKIP_HEADER]) {
5429
+ header = rows[0];
5430
+ rows = rows.slice(1);
5431
+ }
5398
5432
 
5399
- if (rows.length > 0 && this.caps[Capabilities.SCRIPTING_CSV_SKIP_HEADER]) {
5400
- header = rows[0];
5401
- rows = rows.slice(1);
5402
- }
5433
+ if (rows.length === 0) {
5434
+ debug$c('Datarows not found in convo mode');
5435
+ return [];
5436
+ }
5403
5437
 
5404
- if (rows.length === 0) {
5405
- return [];
5406
- }
5438
+ const lineNumberBase = this.caps[Capabilities.SCRIPTING_CSV_SKIP_HEADER] ? 2 : 1;
5407
5439
 
5408
- const lineNumberBase = this.caps[Capabilities.SCRIPTING_CSV_SKIP_HEADER] ? 2 : 1;
5440
+ if (columnCount === 2) {
5441
+ let colQuestion = DEFAULT_QA_COLUMN_QUESTION;
5442
+ let colAnswer = DEFAULT_QA_COLUMN_ANSWER;
5409
5443
 
5410
- if (rows[0].length === 2) {
5411
- debug$c('Found 2-column CSV file, treating it as question/answer file');
5412
- let colQuestion = DEFAULT_QA_COLUMN_QUESTION;
5413
- let colAnswer = DEFAULT_QA_COLUMN_ANSWER;
5444
+ if (header) {
5445
+ if (this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_QUESTION] !== undefined) {
5446
+ colQuestion = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_QUESTION]);
5447
+ }
5414
5448
 
5415
- if (header) {
5416
- if (this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_QUESTION] !== undefined) {
5417
- colQuestion = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_QUESTION]);
5449
+ if (this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_ANSWER] !== undefined) {
5450
+ colAnswer = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_ANSWER]);
5451
+ }
5418
5452
  }
5419
5453
 
5420
- if (this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_ANSWER] !== undefined) {
5421
- colAnswer = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_QA_COLUMN_ANSWER]);
5422
- }
5423
- }
5454
+ const convos = rows.map((row, i) => new Convo$3(this.context, {
5455
+ header: {
5456
+ name: `L${i + lineNumberBase}`
5457
+ },
5458
+ conversation: [Object.assign({}, linesToConvoStep$2([row[colQuestion]], 'me', this.context, undefined, true), {
5459
+ stepTag: `L${i + lineNumberBase}-Question`
5460
+ }), Object.assign({}, linesToConvoStep$2([row[colAnswer]], 'bot', this.context, undefined, true), {
5461
+ stepTag: `L${i + lineNumberBase}-Answer`
5462
+ })]
5463
+ }));
5424
5464
 
5425
- const convos = rows.map((row, i) => new Convo$3(this.context, {
5426
- header: {
5427
- name: `L${i + lineNumberBase}`
5428
- },
5429
- conversation: [Object.assign({}, linesToConvoStep$2([row[colQuestion]], 'me', this.context, undefined, true), {
5430
- stepTag: `L${i + lineNumberBase}-Question`
5431
- }), Object.assign({}, linesToConvoStep$2([row[colAnswer]], 'bot', this.context, undefined, true), {
5432
- stepTag: `L${i + lineNumberBase}-Answer`
5433
- })]
5434
- }));
5465
+ if (scriptType === Constants.SCRIPTING_TYPE_CONVO) {
5466
+ this.context.AddConvos(convos);
5467
+ } else if (scriptType === Constants.SCRIPTING_TYPE_PCONVO) {
5468
+ this.context.AddPartialConvos(convos);
5469
+ }
5435
5470
 
5436
- if (scriptType === Constants.SCRIPTING_TYPE_CONVO) {
5437
- this.context.AddConvos(convos);
5438
- } else if (scriptType === Constants.SCRIPTING_TYPE_PCONVO) {
5439
- this.context.AddPartialConvos(convos);
5471
+ debug$c(`Found 2-column CSV file, treating it as question/answer file, extracted ${convos.length} convos`);
5472
+ return convos;
5440
5473
  }
5441
5474
 
5442
- return convos;
5443
- }
5475
+ if (columnCount >= 3) {
5476
+ let colConversationId = DEFAULT_MULTIROW_COLUMN_CONVERSATION;
5477
+ let colSender = DEFAULT_MULTIROW_COLUMN_SENDER;
5478
+ let colText = DEFAULT_MULTIROW_COLUMN_TEXT;
5479
+
5480
+ if (header) {
5481
+ if (this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_CONVERSATION_ID] !== undefined) {
5482
+ colConversationId = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_CONVERSATION_ID]);
5483
+ }
5444
5484
 
5445
- if (rows[0].length >= 3) {
5446
- debug$c('Found 3-column CSV file, treating it as multi-row conversation file');
5447
- let colConversationId = DEFAULT_MULTIROW_COLUMN_CONVERSATION;
5448
- let colSender = DEFAULT_MULTIROW_COLUMN_SENDER;
5449
- let colText = DEFAULT_MULTIROW_COLUMN_TEXT;
5485
+ if (this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_SENDER] !== undefined) {
5486
+ colSender = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_SENDER]);
5487
+ }
5450
5488
 
5451
- if (header) {
5452
- if (this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_CONVERSATION_ID] !== undefined) {
5453
- colConversationId = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_CONVERSATION_ID]);
5489
+ if (this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_TEXT] !== undefined) {
5490
+ colText = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_TEXT]);
5491
+ }
5454
5492
  }
5455
5493
 
5456
- if (this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_SENDER] !== undefined) {
5457
- colSender = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_SENDER]);
5458
- }
5494
+ const conversationIds = lodash__default["default"].uniq(rows.map(r => r[colConversationId]));
5495
+
5496
+ const convos = conversationIds.map(conversationId => {
5497
+ const convoRows = rows.map((row, i) => {
5498
+ if (row[colConversationId] === conversationId) {
5499
+ return Object.assign({}, linesToConvoStep$2([row[colText]], row[colSender], this.context, undefined, true), {
5500
+ stepTag: `L${i + lineNumberBase}`
5501
+ });
5502
+ }
5503
+
5504
+ return null;
5505
+ }).filter(c => c);
5506
+ return new Convo$3(this.context, {
5507
+ header: {
5508
+ name: conversationId
5509
+ },
5510
+ conversation: convoRows
5511
+ });
5512
+ });
5459
5513
 
5460
- if (this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_TEXT] !== undefined) {
5461
- colText = _findColIndex(header, this.caps[Capabilities.SCRIPTING_CSV_MULTIROW_COLUMN_TEXT]);
5514
+ if (scriptType === Constants.SCRIPTING_TYPE_CONVO) {
5515
+ this.context.AddConvos(convos);
5516
+ } else if (scriptType === Constants.SCRIPTING_TYPE_PCONVO) {
5517
+ this.context.AddPartialConvos(convos);
5462
5518
  }
5519
+
5520
+ debug$c(`Found 3-column CSV file, treating it as multi-row conversation file, extracted ${convos.length} convos`);
5521
+ return convos;
5522
+ }
5523
+ } else if (scriptType === Constants.SCRIPTING_TYPE_UTTERANCES) {
5524
+ if (columnCount === 2 || columnCount === 3 || legacyModeOn && columnCount > 4) {
5525
+ debug$c(`Invalid column count '${columnCount}' in utterances mode`);
5526
+ return [];
5463
5527
  }
5464
5528
 
5465
- const conversationIds = lodash__default["default"].uniq(rows.map(r => r[colConversationId]));
5529
+ const result = [];
5530
+ const startRow = this._GetOptionalCapability(Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW, 2) - 1;
5466
5531
 
5467
- const convos = conversationIds.map(conversationId => {
5468
- const convoRows = rows.map((row, i) => {
5469
- if (row[colConversationId] === conversationId) {
5470
- return Object.assign({}, linesToConvoStep$2([row[colText]], row[colSender], this.context, undefined, true), {
5471
- stepTag: `L${i + lineNumberBase}`
5472
- });
5532
+ const startRowHeader = this._GetOptionalCapability(Capabilities.SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER);
5533
+
5534
+ const stopOnEmpty = this._GetOptionalCapability(Capabilities.SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY);
5535
+
5536
+ for (let col = 0; col < columnCount; col++) {
5537
+ const name = rows[0][col];
5538
+
5539
+ if (!name || name.trim().length === 0) {
5540
+ debug$c(`Column ${col + 1} has no header, skipping`);
5541
+ continue;
5542
+ }
5543
+
5544
+ const uttStruct = {
5545
+ name,
5546
+ utterances: []
5547
+ };
5548
+ let skip = !!startRowHeader;
5549
+
5550
+ const getData = row => {
5551
+ return rows[row][col] ? rows[row][col].trim() : false;
5552
+ }; //
5553
+
5554
+
5555
+ for (let row = startRow; row < rows.length && (skip || !stopOnEmpty || !!getData(row)); row++) {
5556
+ // eslint-disable-line no-unmodified-loop-condition
5557
+ const data = getData(row);
5558
+
5559
+ if (!data) {
5560
+ continue;
5473
5561
  }
5474
5562
 
5475
- return null;
5476
- }).filter(c => c);
5477
- return new Convo$3(this.context, {
5478
- header: {
5479
- name: conversationId
5480
- },
5481
- conversation: convoRows
5482
- });
5483
- });
5563
+ if (!skip) {
5564
+ uttStruct.utterances.push(data);
5565
+ } else {
5566
+ if (startRowHeader === rows[row][col]) {
5567
+ skip = false;
5568
+ }
5569
+ }
5570
+ }
5484
5571
 
5485
- if (scriptType === Constants.SCRIPTING_TYPE_CONVO) {
5486
- this.context.AddConvos(convos);
5487
- } else if (scriptType === Constants.SCRIPTING_TYPE_PCONVO) {
5488
- this.context.AddPartialConvos(convos);
5572
+ if (uttStruct.utterances.length === 0) {
5573
+ // liveperson, skipping meta intents
5574
+ debug$c(`Column ${col + 1} has no utterances, skipping`);
5575
+ continue;
5576
+ }
5577
+
5578
+ result.push(uttStruct);
5489
5579
  }
5490
5580
 
5491
- return convos;
5581
+ debug$c(`Multi-column utterance file, extracted ${result.length} utterances`);
5582
+ this.context.AddUtterances(result);
5583
+ return result;
5584
+ } else {
5585
+ return [];
5492
5586
  }
5493
5587
  }
5494
5588
 
@@ -5815,7 +5909,7 @@ const {
5815
5909
  const {
5816
5910
  getMatchFunction
5817
5911
  } = MatchFunctions;
5818
- const globPattern = '**/+(*.convo.txt|*.utterances.txt|*.pconvo.txt|*.scriptingmemory.txt|*.xlsx|*.xlsm|*.convo.csv|*.pconvo.csv|*.yaml|*.yml|*.json|*.md|*.markdown)';
5912
+ const globPattern = '**/+(*.convo.txt|*.utterances.txt|*.pconvo.txt|*.scriptingmemory.txt|*.xlsx|*.xlsm|*.convo.csv|*.pconvo.csv|*.utterances.csv|*.yaml|*.yml|*.json|*.md|*.markdown)';
5819
5913
  const skipPattern = /^skip[.\-_]/i;
5820
5914
 
5821
5915
  const p = (retryHelper, fn) => {
@@ -6510,6 +6604,10 @@ var ScriptingProvider_1 = class ScriptingProvider {
6510
6604
  result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_CONVO);
6511
6605
  } else if (filename.endsWith('.pconvo.csv')) {
6512
6606
  result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_PCONVO);
6607
+ } else if (filename.endsWith('.pconvo.csv')) {
6608
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_PCONVO);
6609
+ } else if (filename.endsWith('.utterance.csv')) {
6610
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_UTTERANCES);
6513
6611
  } else if (filename.endsWith('.yaml') || filename.endsWith('.yml')) {
6514
6612
  result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_YAML, [Constants.SCRIPTING_TYPE_UTTERANCES, Constants.SCRIPTING_TYPE_PCONVO, Constants.SCRIPTING_TYPE_CONVO, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY]);
6515
6613
  } else if (filename.endsWith('.json')) {
@@ -8690,6 +8788,10 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8690
8788
  try {
8691
8789
  requestOptions.body = this._getMustachedCap(Capabilities.SIMPLEREST_BODY_TEMPLATE, !bodyRaw);
8692
8790
  requestOptions.json = !bodyRaw;
8791
+
8792
+ if (requestOptions.json && (!requestOptions.body || Object.keys(requestOptions.body).length === 0)) {
8793
+ debug$4(`warning: requestOptions.body content seems to be empty - ${requestOptions.body} - capability: "${this.caps[Capabilities.SIMPLEREST_BODY_TEMPLATE]}"`);
8794
+ }
8693
8795
  } catch (err) {
8694
8796
  throw new Error(`composing body from SIMPLEREST_BODY_TEMPLATE failed (${err.message})`);
8695
8797
  }