@tiledesk/tiledesk-tybot-connector 0.2.601-rc1 → 0.3.0

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 (71) hide show
  1. package/CHANGELOG.md +378 -1
  2. package/ExtApi.js +6 -6
  3. package/TdCache copy.js +242 -0
  4. package/TdCache.js +81 -176
  5. package/TdCache_v3.js +261 -0
  6. package/TiledeskExpression.js +7 -3
  7. package/index.js +290 -43
  8. package/logs/app.log +279 -0
  9. package/models/IntentsMachineFactory.js +5 -2
  10. package/models/MockBotsDataSource.js +19 -11
  11. package/models/TiledeskChatbot.js +97 -79
  12. package/models/TiledeskChatbotConst.js +12 -17
  13. package/models/TiledeskChatbotUtil.js +353 -109
  14. package/models/TiledeskIntentsMachine.js +1 -1
  15. package/models/faqKbService.js +1 -1
  16. package/package.json +7 -6
  17. package/tiledeskChatbotPlugs/DirectivesChatbotPlug.js +172 -106
  18. package/tiledeskChatbotPlugs/Filler.js +13 -2
  19. package/tiledeskChatbotPlugs/TildeskContextForCodeOrchestrator.js +8 -0
  20. package/tiledeskChatbotPlugs/WebhookChatbotPlug.js +13 -7
  21. package/tiledeskChatbotPlugs/directives/DirAddTags.js +374 -0
  22. package/tiledeskChatbotPlugs/directives/DirAiPrompt.js +476 -0
  23. package/tiledeskChatbotPlugs/directives/DirAskGPT.js +16 -19
  24. package/tiledeskChatbotPlugs/directives/DirAskGPTV2.js +221 -34
  25. package/tiledeskChatbotPlugs/directives/DirAssign.js +0 -11
  26. package/tiledeskChatbotPlugs/directives/DirAssignFromFunction.js +11 -21
  27. package/tiledeskChatbotPlugs/directives/DirAssistant.js +728 -0
  28. package/tiledeskChatbotPlugs/directives/DirBrevo.js +353 -0
  29. package/tiledeskChatbotPlugs/directives/DirCaptureUserReply.js +3 -30
  30. package/tiledeskChatbotPlugs/directives/DirClearTranscript.js +22 -0
  31. package/tiledeskChatbotPlugs/directives/DirClose.js +16 -3
  32. package/tiledeskChatbotPlugs/directives/DirCode.js +1 -1
  33. package/tiledeskChatbotPlugs/directives/DirCondition.js +0 -26
  34. package/tiledeskChatbotPlugs/directives/DirConnectBlock.js +183 -0
  35. package/tiledeskChatbotPlugs/directives/DirContactUpdate.js +121 -0
  36. package/tiledeskChatbotPlugs/directives/DirCustomerio.js +5 -8
  37. package/tiledeskChatbotPlugs/directives/DirDeflectToHelpCenter.js +11 -1
  38. package/tiledeskChatbotPlugs/directives/DirDepartment.js +15 -6
  39. package/tiledeskChatbotPlugs/directives/DirFireTiledeskEvent.js +17 -6
  40. package/tiledeskChatbotPlugs/directives/DirForm.js +12 -2
  41. package/tiledeskChatbotPlugs/directives/DirGptTask.js +83 -38
  42. package/tiledeskChatbotPlugs/directives/DirGptTask_OLD.js +4 -7
  43. package/tiledeskChatbotPlugs/directives/DirHubspot.js +5 -8
  44. package/tiledeskChatbotPlugs/directives/DirIfOnlineAgents.js +14 -27
  45. package/tiledeskChatbotPlugs/directives/DirIfOnlineAgentsV2.js +278 -0
  46. package/tiledeskChatbotPlugs/directives/DirIfOpenHours.js +147 -51
  47. package/tiledeskChatbotPlugs/directives/DirIfOpenHours_OLD.js +125 -0
  48. package/tiledeskChatbotPlugs/directives/DirIntent.js +8 -36
  49. package/tiledeskChatbotPlugs/directives/DirJSONCondition.js +5 -26
  50. package/tiledeskChatbotPlugs/directives/DirMessage.js +19 -17
  51. package/tiledeskChatbotPlugs/directives/DirMessageToBot.js +136 -0
  52. package/tiledeskChatbotPlugs/directives/DirMoveToAgent.js +20 -87
  53. package/tiledeskChatbotPlugs/directives/DirMoveToUnassigned.js +59 -0
  54. package/tiledeskChatbotPlugs/directives/DirQapla.js +6 -9
  55. package/tiledeskChatbotPlugs/directives/DirRandomReply.js +17 -7
  56. package/tiledeskChatbotPlugs/directives/DirRemoveCurrentBot.js +17 -7
  57. package/tiledeskChatbotPlugs/directives/DirReplaceBot.js +11 -2
  58. package/tiledeskChatbotPlugs/directives/DirReplaceBotV2.js +135 -21
  59. package/tiledeskChatbotPlugs/directives/DirReplaceBotV3.js +163 -0
  60. package/tiledeskChatbotPlugs/directives/DirReply.js +42 -9
  61. package/tiledeskChatbotPlugs/directives/DirReplyV2.js +347 -0
  62. package/tiledeskChatbotPlugs/directives/DirSendEmail.js +13 -23
  63. package/tiledeskChatbotPlugs/directives/DirSendWhatsapp.js +247 -0
  64. package/tiledeskChatbotPlugs/directives/DirSetAttributeV2.js +202 -15
  65. package/tiledeskChatbotPlugs/directives/DirSetConversationTags.js +13 -4
  66. package/tiledeskChatbotPlugs/directives/DirWait.js +21 -4
  67. package/tiledeskChatbotPlugs/directives/DirWebRequest.js +1 -2
  68. package/tiledeskChatbotPlugs/directives/DirWebRequestV2.js +166 -103
  69. package/tiledeskChatbotPlugs/directives/DirWhatsappByAttribute.js +2 -60
  70. package/tiledeskChatbotPlugs/directives/Directives.js +16 -1
  71. /package/tiledeskChatbotPlugs/directives/{DirOfflineHours.js → DEPRECATED_DirOfflineHours.js} +0 -0
@@ -12,7 +12,8 @@ const { DirUnlockIntent } = require('../tiledeskChatbotPlugs/directives/DirUnloc
12
12
 
13
13
  class TiledeskChatbot {
14
14
 
15
- static MAX_STEPS = 200;
15
+ // static MAX_STEPS = process.env.CHATBOT_MAX_STEPS || 1000; // prod 1000;
16
+ // static MAX_EXECUTION_TIME = process.env.CHATBOT_MAX_EXECUTION_TIME || 1000 * 3600 * 8;// test // prod1000 * 3600 * 4; // 4 hours
16
17
 
17
18
  constructor(config) {
18
19
  if (!config.botsDataSource) {
@@ -38,31 +39,29 @@ class TiledeskChatbot {
38
39
  this.APIKEY = config.APIKEY;
39
40
  this.requestId = config.requestId;
40
41
  this.projectId = config.projectId;
42
+ this.MAX_STEPS = config.MAX_STEPS;
43
+ this.MAX_EXECUTION_TIME = config.MAX_EXECUTION_TIME;
41
44
  this.log = config.log;
42
45
  }
43
46
 
44
47
  async replyToMessage(message, callback) {
45
48
  return new Promise( async (resolve, reject) => {
46
- // get bot info
47
- // if (this.log) {
48
- // console.log("replyToMessage():", JSON.stringify(message));
49
- // }
50
49
  let lead = null;
51
50
  if (message.request) {
52
51
  this.request = message.request;
53
- lead = message.request.lead;
54
- if (lead && lead.fullname) {
55
- if (this.log) {console.log("lead.fullname => params.userFullname:", lead.fullname)}
56
- await this.addParameter(this.requestId, "userFullname", lead.fullname);
57
- }
58
- if (lead && lead.email) {
59
- if (this.log) {console.log("lead.email => params.userEmail:", lead.email)}
60
- await this.addParameter(this.requestId, "userEmail", lead.email);
61
- }
62
- }
63
- if (this.log) {
64
- console.log("replyToMessage() > lead found:", JSON.stringify(lead));
52
+ // lead = message.request.lead;
53
+ // if (lead && lead.fullname) {
54
+ // if (this.log) {console.log("lead.fullname => params.userFullname:", lead.fullname)}
55
+ // await this.addParameter("userFullname", lead.fullname);
56
+ // }
57
+ // if (lead && lead.email) {
58
+ // if (this.log) {console.log("lead.email => params.userEmail:", lead.email)}
59
+ // await this.addParameter("userEmail", lead.email);
60
+ // }
65
61
  }
62
+ // if (this.log) {
63
+ // console.log("replyToMessage() > lead found:", JSON.stringify(lead));
64
+ // }
66
65
 
67
66
  // reset lockedIntent on direct user invocation ( /intent or action => this only?)
68
67
  if (message.sender != "_tdinternal") {
@@ -88,6 +87,18 @@ class TiledeskChatbot {
88
87
  }
89
88
  }
90
89
 
90
+ // resetting any noInput timeout setting userInput = true
91
+ // if (message.sender != "_tdinternal") {
92
+ // if (this.log) {console.log("resetting any noInput timeout setting userInput = (false?)", await this.getParameter(TiledeskChatbotConst.USER_INPUT) );}
93
+ // try {
94
+ // // await this.addParameter(TiledeskChatbotConst.USER_INPUT, true); // set userInput
95
+ // await this.deleteParameter(TiledeskChatbotConst.USER_INPUT); // reset userInput
96
+ // if (this.log) {console.log("userInput?", await this.getParameter(TiledeskChatbotConst.USER_INPUT) );}
97
+ // } catch(error) {
98
+ // console.error("Error resetting userInput:", error);
99
+ // }
100
+ // }
101
+
91
102
  // any external invocation restarts the steps counter
92
103
  try {
93
104
  if (message.sender != "_tdinternal") {
@@ -95,6 +106,7 @@ class TiledeskChatbot {
95
106
  console.log("Resetting current step by request message:", message.text);
96
107
  }
97
108
  await TiledeskChatbot.resetStep(this.tdcache, this.requestId);
109
+ await TiledeskChatbot.resetStarted(this.tdcache, this.requestId);
98
110
  if (this.log) {
99
111
  if (this.tdcache) {
100
112
  let currentStep =
@@ -132,17 +144,21 @@ class TiledeskChatbot {
132
144
  let reply;
133
145
  if (faq) {
134
146
  reply = await this.execIntent(faq, message, lead);//, bot);
135
- // if (!reply.attributes) {
136
- // reply.attributes = {}
137
- // }
138
- // // used by the Clients to get some info about the intent that generated this reply
139
- // reply.attributes.intent_display_name = faq.intent_display_name;
140
- // reply.attributes.intent_id = faq.intent_id;
147
+ // resolve(reply);
148
+ // return;
141
149
  }
142
150
  else {
143
151
  reply = {
144
- "text": "An error occurred while getting locked intent:'" + locked_intent + "'"
152
+ "text": "An error occurred while getting locked intent:'" + locked_intent + "'",
153
+ "attributes": {
154
+ "subtype": "info"
155
+ }
145
156
  }
157
+ // because of some race condition, during a mixed ReplyV2 Action button + Replace bot an
158
+ // intent can be found locked outside of the original chatbot scope.
159
+ // The temp solution is to immediatly unlock the intent and let the flow continue.
160
+ await this.unlockIntent(this.requestId);
161
+ await this.unlockAction(this.requestId);
146
162
  }
147
163
  resolve(reply);
148
164
  return;
@@ -187,9 +203,7 @@ class TiledeskChatbot {
187
203
  let reply;
188
204
  if (!intent || (intent && !intent.name)) {
189
205
  if (this.log) {console.log("Invalid intent:", explicit_intent_name);}
190
- reply = {
191
- "text": "Invalid intent: *" + explicit_intent_name + "*"
192
- }
206
+ resolve();
193
207
  }
194
208
  else {
195
209
  if (this.log) {console.log("processing intent:", explicit_intent_name);}
@@ -217,21 +231,12 @@ class TiledeskChatbot {
217
231
  }
218
232
  for (const [key, value] of Object.entries(intent.parameters)) {
219
233
  if (this.log) {console.log(`Adding attribute from intent invocation /intentName{} => ${key}: ${value}`);}
220
- // const parameter_typeof_key = "_tdTypeOf:" + key;
221
- // console.log("intent[parameter_typeof_key]",parameter_typeof_key, intent.parameters[parameter_typeof_key]);
222
- // if (intent.parameters[parameter_typeof_key] === "object") {
223
- // const parameter_value_string = JSON.stringify(value)
224
- // console.log("Adding parameter as string:", parameter_value_string)
225
234
  this.addParameter(key, value);
226
- //this.addParameter(parameter_typeof_key, intent[parameter_typeof_key]);
227
- // }
228
- // else { // TODO: support the other data types
229
- // this.addParameter(key, value);
230
- // }
231
-
232
235
  }
233
236
  }
234
237
  reply = await this.execIntent(faq, message, lead);
238
+ resolve(reply);
239
+ return;
235
240
  }
236
241
  catch(error) {
237
242
  console.error("error");
@@ -240,22 +245,19 @@ class TiledeskChatbot {
240
245
  }
241
246
  else {
242
247
  if (this.log) {console.log("Intent not found:", explicit_intent_name);}
243
- reply = {
244
- "text": "Intent not found: " + explicit_intent_name
245
- }
248
+ resolve()
246
249
  }
247
250
  }
248
- resolve(reply);
249
- return;
250
251
  }
251
252
 
252
253
  // SEARCH INTENTS
253
254
  let faqs;
254
255
  try {
255
256
  faqs = await this.botsDataSource.getByExactMatch(this.botId, message.text);
257
+ if (this.log) {console.log("got faq by EXACT MATCH", faqs);}
256
258
  }
257
259
  catch (error) {
258
- console.error("An error occurred during exact match:", error);
260
+ console.error("(TiledeskChatbot) An error occurred during exact match:", JSON.stringify(error));
259
261
  }
260
262
  if (faqs && faqs.length > 0 && faqs[0].answer) {
261
263
  if (this.log) {console.log("EXACT MATCH OR ACTION FAQ:", faqs[0]);}
@@ -370,8 +372,8 @@ class TiledeskChatbot {
370
372
  // ON THE MAIN SERVER. OTHERWISE WE USE TYBOT_ROUTE TO SPECIFY
371
373
  // THE ALTERNATIVE ROUTE.
372
374
  // let extEndpoint = `${this.APIURL}/modules/tilebot/`;
373
- // if (process.env.TYBOT_ENDPOINT) {
374
- // extEndpoint = `${process.env.TYBOT_ENDPOINT}`;
375
+ // if (process.env.TILEBOT_ENDPOINT) {
376
+ // extEndpoint = `${process.env.TILEBOT_ENDPOINT}`;
375
377
  // }
376
378
  // const apiext = new ExtApi({
377
379
  // ENDPOINT: extEndpoint,
@@ -606,8 +608,17 @@ class TiledeskChatbot {
606
608
  }
607
609
 
608
610
  static async addParameterStatic(_tdcache, requestId, parameter_name, parameter_value) {
611
+ if (parameter_name === null || parameter_name === undefined) {
612
+ // console.error("Error saving key:", parameter_name, "value:", parameter_value);
613
+ return;
614
+ }
609
615
  const parameter_key = TiledeskChatbot.requestCacheKey(requestId) + ":parameters";
610
616
  const parameter_value_s = JSON.stringify(parameter_value);
617
+ // console.log("saving key:", parameter_name, "value:", parameter_value);
618
+ if (parameter_value_s?.length > 20000000) {
619
+ // console.log("Error. Attribute size too big (> 20mb):", parameter_value_s);
620
+ return;
621
+ }
611
622
  await _tdcache.hset(parameter_key, parameter_name, parameter_value_s);
612
623
  }
613
624
 
@@ -661,44 +672,50 @@ class TiledeskChatbot {
661
672
  TiledeskChatbot.requestCacheKey(requestId) + ":parameters", paramName);
662
673
  }
663
674
 
664
- static async checkStep(_tdcache, requestId, max_steps, log) {
675
+ static async checkStep(_tdcache, requestId, max_steps, max_execution_time, log) {
665
676
  if (log) {console.log("CHECKING ON MAX_STEPS:", max_steps);}
666
- let go_on = true; // continue
677
+ // let go_on = true; // continue
667
678
  const parameter_key = TiledeskChatbot.requestCacheKey(requestId) + ":step";
668
679
  if (log) {console.log("__parameter_key:", parameter_key);}
669
680
  await _tdcache.incr(parameter_key);
670
681
  // console.log("incr-ed");
671
682
  let _current_step = await _tdcache.get(parameter_key);
672
- // if (!_current_step) { // this shouldn't be happening
673
- // _current_step = 0;
674
- // }
675
683
  let current_step = Number(_current_step);
676
- // current_step += 1;
677
- // await _tdcache.set(parameter_key, current_step); // increment step
678
- // console.log("CURRENT-STEP:", current_step);
679
684
  if (current_step > max_steps) {
680
685
  if (log) {console.log("max_steps limit just violated");}
681
686
  if (log) {console.log("CURRENT-STEP > MAX_STEPS!", current_step);}
682
- // await TiledeskChatbot.resetStep(_tdcache, requestId);
683
- // go_on = 1; // stop execution, send error message
684
- go_on = false
685
- }
686
- // else if (current_step > max_steps + 1) { // max_steps limit already violated
687
- // console.log("CURRENT-STEP > MAX_STEPS!", current_step);
688
- // // await TiledeskChatbot.resetStep(_tdcache, requestId);
689
- // go_on = 2; // stop execution, don't send error message (already sent with go_on = 1)
690
- // }
691
- else {
692
- // go_on = 0;
693
- go_on = true;
687
+ // go_on = false
688
+ return {
689
+ error: "Anomaly detection. MAX ACTIONS (" + max_steps + ") exeeded."
690
+ };
694
691
  }
695
692
  // else {
696
- // console.log("CURRENT-STEP UNDER MAX_STEPS THRESHOLD:)", current_step);
697
- // current_step += 1;
698
- // await _tdcache.set(parameter_key, current_step); // increment step
699
- // console.log("current_step from cache:", await _tdcache.get(parameter_key));
693
+ // go_on = true;
700
694
  // }
701
- return go_on;
695
+
696
+ // check execution_time
697
+ // const TOTAL_ALLOWED_EXECUTION_TIME = 1000 * 60 // * 60 * 12 // 12 hours
698
+ let start_time_key = TiledeskChatbot.requestCacheKey(requestId) + ":started";
699
+ let start_time = await _tdcache.get(start_time_key);
700
+ // console.log("cached start_time is:", start_time, typeof start_time);
701
+ const now = Date.now();
702
+ if (start_time === null || Number(start_time) === 0) {
703
+ // console.log("start_time is null");
704
+ await _tdcache.set(start_time_key, now);
705
+ return {};
706
+ }
707
+ else {
708
+ // console.log("start_time:", start_time);
709
+ const execution_time = now - Number(start_time);
710
+ // console.log("execution_time:", execution_time);
711
+ if (execution_time > max_execution_time) {
712
+ if (log) {console.log("execution_time > TOTAL_ALLOWED_EXECUTION_TIME. Stopping flow");}
713
+ return {
714
+ error: "Anomaly detection. MAX EXECUTION TIME (" + max_execution_time + " ms) exeeded."
715
+ };
716
+ }
717
+ }
718
+ return {};
702
719
  }
703
720
 
704
721
  static async resetStep(_tdcache, requestId) {
@@ -709,6 +726,14 @@ class TiledeskChatbot {
709
726
  }
710
727
  }
711
728
 
729
+ static async resetStarted(_tdcache, requestId) {
730
+ const parameter_key = TiledeskChatbot.requestCacheKey(requestId) + ":started";
731
+ // console.log("resetStarted() parameter_key:", parameter_key);
732
+ if (_tdcache) {
733
+ await _tdcache.set(parameter_key, 0);
734
+ }
735
+ }
736
+
712
737
  static async currentStep(_tdcache, requestId) {
713
738
  const parameter_key = TiledeskChatbot.requestCacheKey(requestId) + ":step";
714
739
  // console.log("currentStep() parameter_key:", parameter_key);
@@ -777,15 +802,8 @@ class TiledeskChatbot {
777
802
  fullname: all_parameters['userFullname'],
778
803
  phone: all_parameters['userPhone']
779
804
  }
780
- // tdclient.updateLeadData(leadId, all_parameters['userEmail'], all_parameters['userFullname'], null, () => {
781
- tdclient.updateLead(leadId, nativeAttributes, null, null, () => {
805
+ tdclient.updateLead(leadId, nativeAttributes, null, null, () => {
782
806
  if (this.log) {console.log("Lead updated.")}
783
- // tdclient.updateRequestAttributes(requestId, {
784
- // preChatForm: all_parameters,
785
- // updated: Date.now
786
- // }, () => {
787
- // if (this.log) {console.log("Prechat updated.");}
788
- // });
789
807
  });
790
808
  };
791
809
  }
@@ -4,6 +4,7 @@ class TiledeskChatbotConst {
4
4
  static REQ_PROJECT_ID_KEY = "project_id";
5
5
  static REQ_REQUEST_ID_KEY = "conversation_id";
6
6
  static REQ_CHATBOT_NAME_KEY = "chatbot_name";
7
+ static REQ_CHATBOT_ID_KEY = "chatbot_id";
7
8
  static REQ_LAST_USER_TEXT_KEY = "last_user_text";
8
9
  static REQ_LAST_USER_TEXT_v2_KEY = "lastUserText";
9
10
  static REQ_LAST_MESSAGE_ID_KEY = "last_message_id";
@@ -22,23 +23,17 @@ class TiledeskChatbotConst {
22
23
  static REQ_CHAT_CHANNEL = "chatChannel";
23
24
  static REQ_DECODED_JWT_KEY = "decodedCustomJWT";
24
25
  static REQ_REQUESTER_IS_AUTHENTICATED_KEY = "strongAuthenticated";
25
-
26
- // static REQ_DEPARTMENT_ID_KEY = "tdDepartmentId";
27
- // static REQ_PROJECT_ID_KEY = "projectId";
28
- // static REQ_REQUEST_ID_KEY = "tdRequestId";
29
- // static REQ_CHATBOT_NAME_KEY = "tdChatbotName";
30
- // static REQ_LAST_USER_TEXT_KEY = "tdLastUserText";
31
- // static REQ_LAST_MESSAGE_ID_KEY = "tdLastMessageId";
32
- // static REQ_COUNTRY_KEY = "tdCountry";
33
- // static REQ_CITY_KEY = "tdCity";
34
- // static REQ_USER_SOURCE_PAGE_KEY = "tdUserSourcePage";
35
- // static REQ_USER_LANGUAGE_KEY = "tdUserLanguage";
36
- // static REQ_USER_AGENT_KEY = "tdUserAgent";
37
- // static REQ_DEPARTMENT_NAME_KEY = "tdDepartmentName";
38
- // static REQ_END_USER_ID_KEY = "tdEndUserId";
39
- // static REQ_END_USER_IP_ADDRESS_KEY = "tdEndUserIpAddress";
40
- // static REQ_CHAT_URL = "chat_url";
41
-
26
+ static USER_INPUT = "_userInput";
27
+ static REQ_LEAD_USERFULLNAME_KEY = "userFullname";
28
+ static REQ_LEAD_EMAIL_KEY = "userEmail";
29
+ static REQ_USER_PHONE_KEY = "userPhone";
30
+ static REQ_CURRENT_PHONE_NUMBER_KEY = "currentPhoneNumber";
31
+ static REQ_USER_LEAD_ID_KEY = "userLeadId";
32
+ static REQ_USER_COMPANY_KEY = "userCompany";
33
+ static REQ_TICKET_ID_KEY = "ticketId";
34
+ static REQ_CHATBOT_TOKEN = "chatbotToken";
35
+ static REQ_CHATBOT_TOKEN_v2 = "chatbot_jwt_token";
36
+ static API_BASE_URL = "api_base_url";
42
37
  }
43
38
 
44
39
  module.exports = { TiledeskChatbotConst };