@tiledesk/tiledesk-tybot-connector 0.2.69 → 0.2.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@
5
5
  available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
+ # v0.2.70
9
+ - added DirIfOnlineAgentsV2
10
+ - Fix. TiledeskChatbot: WRONG: await chatbot.addParameter("userInput", true); ====> FIXED: this.addParameter("userInput", true)
11
+ - Fix. Fixed WRONG addParameter(key, value) invocation in TiledeskChatbot with 3 (instead of key, value) parameters
12
+
8
13
  # v0.2.69
9
14
  - added flow attributes in reply action (original)
10
15
 
@@ -53,11 +53,13 @@ class TiledeskChatbot {
53
53
  lead = message.request.lead;
54
54
  if (lead && lead.fullname) {
55
55
  if (this.log) {console.log("lead.fullname => params.userFullname:", lead.fullname)}
56
- await this.addParameter(this.requestId, "userFullname", lead.fullname);
56
+ // await this.addParameter(this.requestId, "userFullname", lead.fullname);
57
+ await this.addParameter("userFullname", lead.fullname);
57
58
  }
58
59
  if (lead && lead.email) {
59
60
  if (this.log) {console.log("lead.email => params.userEmail:", lead.email)}
60
- await this.addParameter(this.requestId, "userEmail", lead.email);
61
+ // await this.addParameter(this.requestId, "userEmail", lead.email);
62
+ await this.addParameter("userEmail", lead.email);
61
63
  }
62
64
  }
63
65
  if (this.log) {
@@ -81,7 +83,7 @@ class TiledeskChatbot {
81
83
  await this.unlockIntent(this.requestId);
82
84
  await this.unlockAction(this.requestId);
83
85
  // console.log("RESET LOCKED INTENT.");
84
- await chatbot.addParameter("userInput", true); // set userInput
86
+ await this.addParameter("userInput", true); // set userInput
85
87
  if (this.log) {console.log("RESET LOCKED INTENT. Intent was explicitly invoked with an action:", message.attributes.action);}
86
88
  }
87
89
  } catch(error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "0.2.69",
3
+ "version": "0.2.70",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -48,6 +48,7 @@ const { DirBrevo } = require('./directives/DirBrevo');
48
48
  const { DirAskGPTV2 } = require('./directives/DirAskGPTV2');
49
49
  const { DirAssistant } = require('./directives/DirAssistant');
50
50
  const { DirReplyV2 } = require('./directives/DirReplyV2');
51
+ const { DirIfOnlineAgentsV2 } = require('./directives/DirIfOnlineAgentsV2');
51
52
 
52
53
  class DirectivesChatbotPlug {
53
54
 
@@ -378,6 +379,19 @@ class DirectivesChatbotPlug {
378
379
  // this.process(next_dir);
379
380
  });
380
381
  }
382
+ else if (directive_name === Directives.IF_ONLINE_AGENTS_V2) {
383
+ // console.log("...DirIfOnlineAgents")
384
+ new DirIfOnlineAgentsV2(context).execute(directive, async (stop) => {
385
+ if (stop) {
386
+ if (context.log) { console.log("Stopping Actions on:", JSON.stringify(directive));}
387
+ this.theend();
388
+ }
389
+ else {
390
+ let next_dir = await this.nextDirective(this.directives);
391
+ this.process(next_dir);
392
+ }
393
+ });
394
+ }
381
395
  else if (directive_name === Directives.FUNCTION_VALUE) {
382
396
  // console.log("...DirAssignFromFunction")
383
397
  new DirAssignFromFunction(context).execute(directive, async () => {
@@ -0,0 +1,399 @@
1
+ // const { TiledeskClient } = require('@tiledesk/tiledesk-client');
2
+ const { rejects } = require('assert');
3
+ const { DirIntent } = require('./DirIntent');
4
+ const axios = require("axios").default;
5
+ let https = require("https");
6
+
7
+ class DirIfOnlineAgentsV2 {
8
+
9
+ constructor(context) {
10
+ if (!context) {
11
+ throw new Error('context object is mandatory.');
12
+ }
13
+ this.context = context;
14
+ this.chatbot = context.chatbot;
15
+ this.tdclient = context.tdclient;
16
+ this.intentDir = new DirIntent(context);
17
+ this.log = context.log;
18
+ }
19
+
20
+ execute(directive, callback) {
21
+ let action;
22
+ if (directive.action) {
23
+ action = directive.action
24
+ }
25
+ else {
26
+ callback();
27
+ return;
28
+ }
29
+ this.go(action, (stop) => {
30
+ callback(stop);
31
+ });
32
+ }
33
+
34
+ async go(action, callback) {
35
+ console.log("(DirIfOnlineAgents) action:", action);
36
+ if (!action.trueIntent && !action.falseIntent) {
37
+ if (this.log) {
38
+ console.log("Error DirIfOnlineAgents: missing both action.trueIntent & action.falseIntent");
39
+ }
40
+ callback();
41
+ return;
42
+ }
43
+ const trueIntent = action.trueIntent;
44
+ const falseIntent = action.falseIntent;
45
+ if (this.log) {
46
+ console.log("(DirIfOnlineAgents) IfOnlineAgents:trueIntent:", trueIntent);
47
+ console.log("(DirIfOnlineAgents) IfOnlineAgents:falseIntent:", falseIntent);
48
+ }
49
+ const trueIntentAttributes = action.trueIntentAttributes;
50
+ const falseIntentAttributes = action.falseIntentAttributes;
51
+ let stopOnConditionMet = true; //action.stopOnConditionMet;
52
+
53
+ try {
54
+ const result = await this.openNow();
55
+ if (result && result.isopen) {
56
+ const selectedOption = action.selectedOption;
57
+
58
+ let agents;
59
+ if (selectedOption === "currentDep") {
60
+ console.log("(DirIfOnlineAgents) selectedOption === currentDep");
61
+ agents = await this.getDepartmentAvailableAgents(this.context.departmentId);
62
+ console.log("(DirIfOnlineAgents) agents:", agents);
63
+ }
64
+ else if (selectedOption === "selectedDep") {
65
+ console.log("(DirIfOnlineAgents) selectedOption === selectedDep", action.selectedDepartmentId);
66
+ agents = await this.getDepartmentAvailableAgents(action.selectedDepartmentId);
67
+ console.log("(DirIfOnlineAgents) agents:", agents);
68
+ }
69
+ else { // if (checkAll) => go project-wide
70
+ console.log("(DirIfOnlineAgents) selectedOption === all");
71
+ agents = await this.getProjectAvailableAgents();
72
+ console.log("(DirIfOnlineAgents) agents:", agents);
73
+ }
74
+
75
+ if (agents && agents.length > 0) {
76
+ if (trueIntent) {
77
+ let intentDirective = DirIntent.intentDirectiveFor(trueIntent, trueIntentAttributes);
78
+ if (this.log) {console.log("agents (openHours) => trueIntent");}
79
+ this.intentDir.execute(intentDirective, () => {
80
+ callback(stopOnConditionMet);
81
+ });
82
+ }
83
+ else {
84
+ console.log("(DirIfOnlineAgents) No IfOnlineAgents trueIntent defined. callback()") // prod
85
+ this.chatbot.addParameter("flowError", "(If online Agents) No IfOnlineAgents success path defined.");
86
+ callback();
87
+ return;
88
+ }
89
+ }
90
+ else if (falseIntent) { // no agents available
91
+ let intentDirective = DirIntent.intentDirectiveFor(falseIntent, falseIntentAttributes);
92
+ if (this.log) {console.log("(DirIfOnlineAgents) !agents (openHours) => falseIntent", intentDirective);}
93
+ this.intentDir.execute(intentDirective, () => {
94
+ callback(stopOnConditionMet);
95
+ });
96
+ }
97
+ else {
98
+ if (this.log) {console.log("(DirIfOnlineAgents) Error: No falseIntent defined", intentDirective);}
99
+ this.chatbot.addParameter("flowError", "(If online Agents) No path for 'no available agents' defined.");
100
+ callback();
101
+ }
102
+ }
103
+ }
104
+ catch(err) {
105
+ console.error("(DirIfOnlineAgents) An error occurred:", err);
106
+ this.chatbot.addParameter("flowError", "(If online Agents) An error occurred: " + err);
107
+ callback();
108
+ }
109
+ }
110
+
111
+ async openNow() {
112
+ return new Promise( (resolve, reject) => {
113
+ this.tdclient.openNow(async (err, result) => {
114
+ if (this.log) {console.log("(DirIfOnlineAgents) openNow():", result);}
115
+ if (err) {
116
+ reject(err);
117
+ }
118
+ else {
119
+ resolve(result);
120
+ }
121
+ });
122
+ });
123
+ }
124
+
125
+ async getProjectAvailableAgents() {
126
+ return new Promise( (resolve, reject) => {
127
+ this.tdclient.getProjectAvailableAgents((err, agents) => {
128
+ if (err) {
129
+ reject(err);
130
+ }
131
+ else {
132
+ resolve(agents);
133
+ }
134
+ });
135
+ })
136
+ }
137
+
138
+ async getDepartmentAvailableAgents(depId) {
139
+ return new Promise( (resolve, reject) => {
140
+ this.tdclient.getDepartment(depId, async (error, dep) => {
141
+ if (error) {
142
+ reject(error);
143
+ }
144
+ else {
145
+ console.log("(DirIfOnlineAgents) got department:", JSON.stringify(dep));
146
+ const groupId = dep.id_group;
147
+ console.log("(DirIfOnlineAgents) department.groupId:", groupId);
148
+ try {
149
+ if (groupId) {
150
+ const group = await this.getGroup(groupId);
151
+ console.log("(DirIfOnlineAgents) got group info:", group);
152
+ if (group) {
153
+ if (group.members) {
154
+ console.log("(DirIfOnlineAgents) group members ids:", group.members);
155
+ // let group_members = await getTeammates(group.members);
156
+ // console.log("group members details:", group_members);
157
+ let all_teammates = await this.getAllTeammates();
158
+ console.log("(DirIfOnlineAgents) all teammates:", all_teammates);
159
+ if (all_teammates && all_teammates.length > 0){
160
+ // [
161
+ // {
162
+ // "user_available": false,
163
+ // ...
164
+ // "id_user": {
165
+ // "status": 100,
166
+ // "email": "michele@tiledesk.com",
167
+ // "firstname": "Michele",
168
+ // "lastname": "Pomposo",
169
+ // ...
170
+ // },
171
+ // "role": "admin",
172
+ // "tags": [],
173
+ // "presence": {
174
+ // "status": "offline",
175
+ // "changedAt": "2023-11-16T12:37:31.990Z"
176
+ // },
177
+ // "isBusy": false
178
+ // }, ... ]
179
+ // filter on availability
180
+ console.log("(DirIfOnlineAgents) filtering available agents for group:", groupId);
181
+ let available_agents = [];
182
+ all_teammates.forEach((agent) => {
183
+ console.log("Checking teammate:", agent.id_user._id, "(", agent.id_user.email ,") Available:", agent.user_available, ") with members:",group.members );
184
+ if (agent.user_available === true && group.members.includes(agent.id_user._id)) {
185
+ console.log("Adding teammate:", agent.id_user._id);
186
+ available_agents.push(agent);
187
+ }
188
+ });
189
+ console.log("(DirIfOnlineAgents) available agents in group:", available_agents);
190
+ resolve(available_agents);
191
+ }
192
+ }
193
+ else {
194
+ this.chatbot.addParameter("flowError", "(If online Agents) Empty group:" + groupId);
195
+ resolve([]);
196
+ }
197
+ }
198
+ else {
199
+ this.chatbot.addParameter("flowError", "(If online Agents) Error: no group for groupId:" + groupId);
200
+ resolve([]);
201
+ }
202
+ }
203
+ else {
204
+ // no group => assigned to all teammates
205
+ const agents = await this.getProjectAvailableAgents();
206
+ resolve(agents);
207
+ }
208
+ }
209
+ catch(error) {
210
+ console.error("(DirIfOnlineAgents) Error:", error);
211
+ reject(error);
212
+ }
213
+ }
214
+ });
215
+ });
216
+ }
217
+
218
+ // async getGroup(groupId, callback) {
219
+ // return new Promise ( (resolve, reject) => {
220
+ // const URL = `${this.APIURL}/${this.projectId}/groups/${groupId}`
221
+ // const HTTPREQUEST = {
222
+ // url: URL,
223
+ // headers: {
224
+ // 'Content-Type' : 'application/json',
225
+ // 'Authorization': this.context.token
226
+ // },
227
+ // method: 'GET',
228
+ // httpsOptions: this.httpsOptions
229
+ // };
230
+ // TiledeskClient.myrequest(
231
+ // HTTPREQUEST,
232
+ // function(err, resbody) {
233
+ // if (err) {
234
+ // reject(err);
235
+ // if (callback) {
236
+ // callback(err);
237
+ // }
238
+ // }
239
+ // else {
240
+ // resolve(resbody);
241
+ // if (callback) {
242
+ // callback(null, resbody);
243
+ // }
244
+ // }
245
+ // }, this.log
246
+ // );
247
+ // });
248
+ // }
249
+
250
+ async getGroup(groupId, callback) {
251
+ return new Promise ( (resolve, reject) => {
252
+ const URL = `${this.context.TILEDESK_APIURL}/${this.context.projectId}/groups/${groupId}`
253
+ const HTTPREQUEST = {
254
+ url: URL,
255
+ headers: {
256
+ 'Content-Type' : 'application/json',
257
+ 'Authorization': this.fixToken(this.context.token)
258
+ },
259
+ method: 'GET',
260
+ httpsOptions: this.httpsOptions
261
+ };
262
+ this.#myrequest(
263
+ HTTPREQUEST,
264
+ function(err, resbody) {
265
+ if (err) {
266
+ reject(err);
267
+ if (callback) {
268
+ callback(err);
269
+ }
270
+ }
271
+ else {
272
+ // {
273
+ // "members": [
274
+ // "62b317986993970035f0697e",
275
+ // "5aaa99024c3b110014b478f0"
276
+ // ],
277
+ // "_id": "65ddec23fd8dc3003295cdd7",
278
+ // "name": "Sales",
279
+ // "trashed": false,
280
+ // "id_project": "65203e12f8c0cf002cf4110b",
281
+ // "createdBy": "5e09d16d4d36110017506d7f",
282
+ // "createdAt": "2024-02-27T14:05:23.373Z",
283
+ // "updatedAt": "2024-02-27T14:05:29.137Z",
284
+ // "__v": 0
285
+ // }
286
+ resolve(resbody);
287
+ if (callback) {
288
+ callback(null, resbody);
289
+ }
290
+ }
291
+ }, this.log
292
+ );
293
+ });
294
+ }
295
+
296
+ async getAllTeammates(members, callback) {
297
+ return new Promise ( (resolve, reject) => {
298
+ const URL = `${this.context.TILEDESK_APIURL}/${this.context.projectId}/project_users`
299
+ const HTTPREQUEST = {
300
+ url: URL,
301
+ headers: {
302
+ 'Content-Type' : 'application/json',
303
+ 'Authorization': this.fixToken(this.context.token)
304
+ },
305
+ method: 'GET',
306
+ httpsOptions: this.httpsOptions
307
+ };
308
+ this.#myrequest(
309
+ HTTPREQUEST,
310
+ function(err, resbody) {
311
+ if (err) {
312
+ reject(err);
313
+ if (callback) {
314
+ callback(err);
315
+ }
316
+ }
317
+ else {
318
+ // {
319
+ // "members": [
320
+ // "62b317986993970035f0697e",
321
+ // "5aaa99024c3b110014b478f0"
322
+ // ],
323
+ // "_id": "65ddec23fd8dc3003295cdd7",
324
+ // "name": "Sales",
325
+ // "trashed": false,
326
+ // "id_project": "65203e12f8c0cf002cf4110b",
327
+ // "createdBy": "5e09d16d4d36110017506d7f",
328
+ // "createdAt": "2024-02-27T14:05:23.373Z",
329
+ // "updatedAt": "2024-02-27T14:05:29.137Z",
330
+ // "__v": 0
331
+ // }
332
+ resolve(resbody);
333
+ if (callback) {
334
+ callback(null, resbody);
335
+ }
336
+ }
337
+ }, this.log
338
+ );
339
+ });
340
+ }
341
+
342
+ #myrequest(options, callback) {
343
+ if (this.log) {
344
+ console.log("API URL:", options.url);
345
+ console.log("** Options:", JSON.stringify(options));
346
+ }
347
+ let axios_options = {
348
+ url: options.url,
349
+ method: options.method,
350
+ params: options.params,
351
+ headers: options.headers
352
+ }
353
+ if (options.json !== null) {
354
+ axios_options.data = options.json
355
+ }
356
+ if (this.log) {
357
+ console.log("axios_options:", JSON.stringify(axios_options));
358
+ }
359
+ if (options.url.startsWith("https:")) {
360
+ const httpsAgent = new https.Agent({
361
+ rejectUnauthorized: false,
362
+ });
363
+ axios_options.httpsAgent = httpsAgent;
364
+ }
365
+ axios(axios_options)
366
+ .then((res) => {
367
+ if (this.log) {
368
+ console.log("Response for url:", options.url);
369
+ console.log("Response headers:\n", JSON.stringify(res.headers));
370
+ }
371
+ if (res && res.status == 200 && res.data) {
372
+ if (callback) {
373
+ callback(null, res.data);
374
+ }
375
+ }
376
+ else {
377
+ if (callback) {
378
+ callback(new Error("Response status is not 200"), null);
379
+ }
380
+ }
381
+ })
382
+ .catch((error) => {
383
+ if (callback) {
384
+ callback(error, null);
385
+ }
386
+ });
387
+ }
388
+
389
+ fixToken(token) {
390
+ if (token.startsWith('JWT ')) {
391
+ return token
392
+ }
393
+ else {
394
+ return 'JWT ' + token
395
+ }
396
+ }
397
+ }
398
+
399
+ module.exports = { DirIfOnlineAgentsV2 };
@@ -48,6 +48,7 @@ class Directives {
48
48
  static PLAY_PROMPT = 'play_prompt';
49
49
  static GPT_ASSISTANT = 'gpt_assistant';
50
50
  static REPLY_V2 = 'replyv2';
51
+ static IF_ONLINE_AGENTS_V2 = "ifonlineagentsv2";
51
52
 
52
53
  // static WHEN_ONLINE_MOVE_TO_AGENT = "whenonlinemovetoagent"; // DEPRECATED?
53
54
  // static WHEN_OFFLINE_HOURS = "whenofflinehours"; // DEPRECATED // adds a message on top of the original message when offline hours opts: --replace