@tiledesk/tiledesk-tybot-connector 0.2.63 → 0.2.65

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
@@ -6,6 +6,14 @@ available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
8
 
9
+ # v0.2.65
10
+ - fix OPENAI_APIKEY: removed Bearer prefix
11
+
12
+ # v0.2.64
13
+ - removed system parameters from /reserved/parameters
14
+ - Web Request Action: added multipart form-data support with files binary from URL source
15
+ - Added DirAssistant Action
16
+
9
17
  # v0.2.63
10
18
  - BUG fix on /ext/parameters/requests/:requestid
11
19
  - Moved getChatbotParameters function in TiledeskChatbotUtil
package/index.js CHANGED
@@ -395,7 +395,12 @@ router.get('/ext/reserved/parameters/requests/:requestid', async (req, res) => {
395
395
  "lastUserImageType", // image
396
396
  "lastUserDocumentURL", // file
397
397
  "lastUserDocumentName", // file
398
- "lastUserDocumentType" // file
398
+ "lastUserDocumentType", // file
399
+ "ticketId",
400
+ TiledeskChatbotConst.REQ_CHAT_CHANNEL,
401
+ "user_lead_id",
402
+ "lastUserText",
403
+ TiledeskChatbotConst.REQ_REQUESTER_IS_AUTHENTICATED_KEY
399
404
  ]
400
405
  let userParams = {};
401
406
  if (parameters) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "0.2.63",
3
+ "version": "0.2.65",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -46,6 +46,7 @@ const { DirHubspot } = require('./directives/DirHubspot');
46
46
  const { DirCustomerio } = require('./directives/DirCustomerio');
47
47
  const { DirBrevo } = require('./directives/DirBrevo');
48
48
  const { DirAskGPTV2 } = require('./directives/DirAskGPTV2');
49
+ const { DirAssistant } = require('./directives/DirAssistant');
49
50
 
50
51
  class DirectivesChatbotPlug {
51
52
 
@@ -727,6 +728,20 @@ class DirectivesChatbotPlug {
727
728
  this.process(next_dir);
728
729
  })
729
730
  }
731
+ else if (directive_name === Directives.GPT_ASSISTANT) {
732
+ // console.log("...GPT_ASSISTANT");
733
+ new DirAssistant(context).execute(directive, async (stop) => {
734
+ if (context.log) { console.log("stop on condition?", stop);}
735
+ if (stop == true) {
736
+ if (context.log) { console.log("Stopping Actions on:", JSON.stringify(directive));}
737
+ this.theend();
738
+ }
739
+ else {
740
+ let next_dir = await this.nextDirective(this.directives);
741
+ this.process(next_dir);
742
+ }
743
+ });
744
+ }
730
745
  else {
731
746
  //console.log("Unhandled Post-message Directive:", directive_name);
732
747
  let next_dir = await this.nextDirective(this.directives);
@@ -0,0 +1,645 @@
1
+ let axios = require('axios');
2
+ let https = require("https");
3
+ const { Filler } = require('../Filler');
4
+ const { TiledeskChatbot } = require('../../models/TiledeskChatbot');
5
+ const { DirIntent } = require('./DirIntent');
6
+
7
+ class DirAssistant {
8
+ constructor(context) {
9
+ if (!context) {
10
+ throw new Error('context object is mandatory.');
11
+ }
12
+ this.context = context;
13
+ this.tdclient = context.tdclient;
14
+ this.tdcache = context.tdcache;
15
+ this.requestId = context.requestId;
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
+ console.error("Incorrect directive:", JSON.stringify(directive));
27
+ callback();
28
+ return;
29
+ }
30
+ this.go(action, (stop) => {
31
+ if (this.log) {console.log("(DirAssistant, stop?", stop); }
32
+ callback(stop);
33
+ });
34
+ }
35
+
36
+ async go(action, callback) {
37
+ if (this.log) {console.log("DirAssistant action:", JSON.stringify(action));}
38
+ let requestAttributes = null;
39
+ if (this.tdcache) {
40
+ requestAttributes =
41
+ await TiledeskChatbot.allParametersStatic(
42
+ this.tdcache, this.requestId
43
+ );
44
+ }
45
+
46
+ const filler = new Filler();
47
+ const url = filler.fill(action.url, requestAttributes);
48
+ // prompt => Mandatory
49
+ // assistantId => Mandatory
50
+ // threadIdAttribute => Optional // default "firstThread"
51
+ // assignResultTo => Optional // default "assistantReply"
52
+ // assignErrorTo => Optional // default "assistantError"
53
+ // action.settings.timeout => Optional
54
+
55
+ let assignResultTo = "assistantReply";
56
+ if (action.assignResultTo) {
57
+ assignResultTo = action.assignResultTo;
58
+ }
59
+
60
+ let assignErrorTo = "assistantError";
61
+ if (action.assignErrorTo) {
62
+ assignErrorTo = action.assignErrorTo;
63
+ }
64
+
65
+ let threadIdAttribute = "firstThread";
66
+ if (action.threadIdAttribute) {
67
+ threadIdAttribute = action.threadIdAttribute;
68
+ }
69
+
70
+ let _assistantId = null;
71
+ if (action.assistantId) { // mandatory
72
+ _assistantId = action.assistantId;
73
+ }
74
+ else {
75
+ // TODO: LOG SETTINGS ERROR
76
+ console.error("DirAssistant error: no assistantId.");
77
+ callback();
78
+ return;
79
+ }
80
+
81
+ let _prompt = null;
82
+ if (action.prompt) { // mandatory
83
+ _prompt = action.prompt;
84
+ }
85
+ else {
86
+ // TODO: LOG SETTINGS ERROR
87
+ console.error("DirAssistant error: no prompt.");
88
+ callback();
89
+ return;
90
+ }
91
+
92
+ let assistantId = _assistantId;
93
+ try {
94
+ assistantId = filler.fill(_assistantId, requestAttributes);
95
+ }
96
+ catch(error) {
97
+ console.error("Error while filling assistantId:", error);
98
+ }
99
+
100
+ let prompt = _prompt;
101
+ try {
102
+ prompt = filler.fill(_prompt, requestAttributes);
103
+ }
104
+ catch(error) {
105
+ console.error("Error while filling prompt:", error);
106
+ }
107
+
108
+ if (this.log) {
109
+ console.log("settings ok");
110
+ console.log("prompt:", prompt);
111
+ console.log("assistantId:", assistantId);
112
+ }
113
+ // Condition branches
114
+ let trueIntent = action.trueIntent;
115
+ let falseIntent = action.falseIntent;
116
+ if (trueIntent && trueIntent.trim() === "") {
117
+ trueIntent = null;
118
+ }
119
+ if (falseIntent && falseIntent.trim() === "") {
120
+ falseIntent = null;
121
+ }
122
+
123
+ this.timeout = this.#webrequest_timeout(action, 20000, 1, 300000);
124
+
125
+ let apikey = await this.getGPT_APIKEY();
126
+ if (this.log) {console.log("apikey:", apikey);}
127
+ if (!apikey) {
128
+ const reply = "DirAssistant gptkey is mandatory in Integrations";
129
+ if (this.log) { console.error(reply); };
130
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, assignErrorTo, reply);
131
+ if (falseIntent) {
132
+ await this.#executeCondition(false, trueIntent, null, falseIntent, null);
133
+ callback(true);
134
+ }
135
+ return;
136
+ }
137
+ else {
138
+ apikey = "Bearer " + apikey;
139
+ console.log("APIKEY::", apikey);
140
+ }
141
+ let threadId = null;
142
+ try {
143
+ threadId = requestAttributes[threadIdAttribute];
144
+ if (!threadId || (threadId && threadId.trim() === '') ) {
145
+ // create thread if it doesn't exist
146
+ if (this.log) {console.log("Creating thread");}
147
+ const thread = await this.createThread(apikey);
148
+ if (this.log) {console.log("Thread crated.");}
149
+ threadId = thread.id;
150
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, threadIdAttribute, threadId);
151
+ if (this.log) {
152
+ console.log("thread:", thread);
153
+ console.log("threadId:", threadId);
154
+ }
155
+ }
156
+ else {
157
+ if (this.log) { console.log("Reusing threadId (used flow attribute:" + threadIdAttribute + "):", threadId); }
158
+ }
159
+ await this.addMessage(prompt, threadId, apikey);
160
+ if (this.log) {console.log("Message added.");}
161
+ await this.runThreadOnAssistant(assistantId, threadId, apikey);
162
+ let messages = await this.threadMessages(threadId, apikey);
163
+ let lastMessage = null;
164
+ if (messages && messages.data && messages.data.length > 0 && messages.data[0]) {
165
+ if (messages.data[0].content.length > 0 && messages.data[0].content[0] && messages.data[0].content[0].text) {
166
+ lastMessage = messages.data[0].content[0].text.value;
167
+ }
168
+ }
169
+ console.log("lastMessage:", lastMessage);
170
+ // process.exit(0);
171
+ if (lastMessage !== null) {
172
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, assignResultTo, lastMessage);
173
+ if (trueIntent) {
174
+ await this.#executeCondition(true, trueIntent, null, falseIntent, null);
175
+ callback(true);
176
+ }
177
+ else {
178
+ callback(false);
179
+ return;
180
+ }
181
+ }
182
+ else {
183
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, assignResultTo, null);
184
+ if (falseIntent) {
185
+ await this.#executeCondition(false, trueIntent, null, falseIntent, null);
186
+ callback(true);
187
+ }
188
+ else {
189
+ callback(false);
190
+ return;
191
+ }
192
+ }
193
+ }
194
+ catch (error) {
195
+ if (this.log) { console.error("error:", error); }
196
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, assignErrorTo, error);
197
+ if (falseIntent) {
198
+ await this.#executeCondition(false, trueIntent, null, falseIntent, null);
199
+ }
200
+ callback(true);
201
+ return;
202
+ }
203
+
204
+ }
205
+
206
+ async #executeCondition(result, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, callback) {
207
+ let trueIntentDirective = null;
208
+ if (trueIntent) {
209
+ trueIntentDirective = DirIntent.intentDirectiveFor(trueIntent, trueIntentAttributes);
210
+ }
211
+ let falseIntentDirective = null;
212
+ if (falseIntent) {
213
+ falseIntentDirective = DirIntent.intentDirectiveFor(falseIntent, falseIntentAttributes);
214
+ }
215
+ if (result === true) {
216
+ if (trueIntentDirective) {
217
+ this.intentDir.execute(trueIntentDirective, () => {
218
+ if (callback) {
219
+ callback();
220
+ }
221
+ });
222
+ }
223
+ else {
224
+ if (this.log) {console.log("No trueIntentDirective specified");}
225
+ if (callback) {
226
+ callback();
227
+ }
228
+ }
229
+ }
230
+ else {
231
+ if (falseIntentDirective) {
232
+ this.intentDir.execute(falseIntentDirective, () => {
233
+ if (callback) {
234
+ callback();
235
+ }
236
+ });
237
+ }
238
+ else {
239
+ if (this.log) {console.log("No falseIntentDirective specified");}
240
+ if (callback) {
241
+ callback();
242
+ }
243
+ }
244
+ }
245
+ }
246
+
247
+ #webrequest_timeout(action, default_timeout, min, max) {
248
+ let timeout = default_timeout;
249
+ if (!action.settings) {
250
+ return timeout;
251
+ }
252
+
253
+ if (action.settings.timeout) {
254
+ if ((typeof action.settings.timeout === "number") && action.settings.timeout > min && action.settings.timeout < max) {
255
+ timeout = Math.round(action.settings.timeout)
256
+ // console.log("new timeout:", timeout);
257
+ }
258
+ }
259
+ return timeout
260
+ }
261
+
262
+ async getGPT_APIKEY() {
263
+ if (process.env.TEST_OPENAI_APIKEY) {
264
+ return process.env.TEST_OPENAI_APIKEY
265
+ }
266
+ else {
267
+ const server_base_url = process.env.API_ENDPOINT || process.env.API_URL;
268
+ return await this.getKeyFromIntegrations(server_base_url);
269
+ }
270
+ }
271
+
272
+ async createThread(apikey) {
273
+ if (this.log) { console.log("creating thread..."); }
274
+ return new Promise( async (resolve, reject) => {
275
+ const url = "https://api.openai.com/v1/threads";
276
+ const headers = {
277
+ "Authorization": apikey,
278
+ "OpenAI-Beta": "assistants=v2"
279
+ }
280
+ const HTTPREQUEST = {
281
+ url: url,
282
+ headers: headers,
283
+ json: '', // no old messages on creation
284
+ method: "POST",
285
+ timeout: this.timeout
286
+ };
287
+ if (this.log) {console.log("DirAssistant HTTPREQUEST", HTTPREQUEST);}
288
+ this.#myrequest(
289
+ HTTPREQUEST, async (err, res) => {
290
+ let status = res.status;
291
+ if (err) {
292
+ if (this.log) {console.error("DirAssistant error:", err);}
293
+ reject(err);
294
+ }
295
+ else if(res.status >= 200 && res.status <= 299) {
296
+ if (this.log) {console.log("got threadid res:", res);}
297
+ let thread = res.data;
298
+ resolve(thread)
299
+ }
300
+ else {
301
+ reject(new Error("Thread creation status != 200:", status));
302
+ }
303
+ }
304
+ );
305
+ });
306
+ }
307
+
308
+ async addMessage(prompt, threadId, apikey) {
309
+
310
+ // POST https://api.openai.com/v1/threads/{{threadID}}/messages
311
+
312
+ // JSON
313
+ /*
314
+ {
315
+ "role": "user",
316
+ "content": {{last_user_text | json}},
317
+ "attachments": [
318
+ {
319
+ "file_id": "file-9rf2OwoLy22Q6bePkO0Zmhlc",
320
+ "tools": [
321
+ {
322
+ "type": "code_interpreter"
323
+ }
324
+ ]
325
+ }
326
+ ]
327
+ }
328
+ */
329
+ const json_payload = {
330
+ "role": "user",
331
+ "content": prompt
332
+ }
333
+
334
+ return new Promise( async (resolve, reject) => {
335
+ const url = `https://api.openai.com/v1/threads/${threadId}/messages`;
336
+ const headers = {
337
+ "Authorization": apikey,
338
+ "OpenAI-Beta": "assistants=v2"
339
+ }
340
+ const HTTPREQUEST = {
341
+ url: url,
342
+ headers: headers,
343
+ json: json_payload,
344
+ method: "POST",
345
+ timeout: this.timeout
346
+ };
347
+ if (this.log) {console.log("DirAssistant HTTPREQUEST", HTTPREQUEST);}
348
+ this.#myrequest(
349
+ HTTPREQUEST, async (err, res) => {
350
+ let status = res.status;
351
+ if (err) {
352
+ if (this.log) {console.error("DirAssistant error:", err);}
353
+ reject(err);
354
+ }
355
+ else if(res.status >= 200 && res.status <= 299) {
356
+ if (this.log) {console.log("got response data:", res.data);}
357
+ // let return_body = res.data;
358
+ resolve();
359
+ }
360
+ else {
361
+ reject(new Error("Message add status != 200:", status));
362
+ }
363
+ }
364
+ );
365
+ });
366
+ }
367
+
368
+ async runThreadOnAssistant(assistantId, threadId, apikey) {
369
+ let _run = await this.createRun(threadId, assistantId, apikey);
370
+ if (this.log) {console.log("Got run:", _run);}
371
+ let runId = _run.id;
372
+ if (this.log) {console.log("runId:", runId);}
373
+ let status = null;
374
+ do {
375
+ if (this.log) {console.log("Getting run...");}
376
+ const wait_for = 2000;
377
+ if (this.log) {console.log("Waiting:", wait_for);}
378
+ await new Promise(resolve => setTimeout(resolve, wait_for));
379
+ let run = await this.getRun(threadId, runId, apikey);
380
+ status = run.status;
381
+ if (this.log) {console.log("Run status:", status);}
382
+ }
383
+ while (status === "queued" || status === "in_progress" || status === "requires_action" && status === "cancelling");
384
+ // while (status != "completed" && status != "cancelled" && status != "failed" && status != "expired");
385
+ // queued, in_progress, requires_action, cancelling
386
+ if (this.log) {console.log("Run end.");}
387
+ }
388
+
389
+ async createRun(threadId, assistantId, apikey) {
390
+ const json_payload = {
391
+ "assistant_id": assistantId
392
+ }
393
+
394
+ return new Promise( async (resolve, reject) => {
395
+ if (this.log) {console.log("adding message to thread...");}
396
+ const url = `https://api.openai.com/v1/threads/${threadId}/runs`;
397
+ const headers = {
398
+ "Authorization": apikey,
399
+ "OpenAI-Beta": "assistants=v2"
400
+ }
401
+ const HTTPREQUEST = {
402
+ url: url,
403
+ headers: headers,
404
+ json: json_payload,
405
+ method: "POST",
406
+ timeout: this.timeout
407
+ };
408
+ if (this.log) {console.log("DirAssistant HTTPREQUEST", HTTPREQUEST);}
409
+ this.#myrequest(
410
+ HTTPREQUEST, async (err, res) => {
411
+ let status = res.status;
412
+ if (err) {
413
+ if (this.log) {console.error("DirAssistant error:", err);}
414
+ reject(err);
415
+ }
416
+ else if(res.status >= 200 && res.status <= 299) {
417
+ if (this.log) {console.log("got response data:", res.data);}
418
+ // let return_body = res.data;
419
+ resolve(res.data);
420
+ }
421
+ else {
422
+ reject(new Error("Message add status != 200:", status));
423
+ }
424
+ }
425
+ );
426
+ });
427
+ }
428
+
429
+ async getRun(threadId, runId, apikey) {
430
+ return new Promise( async (resolve, reject) => {
431
+ const url = `https://api.openai.com/v1/threads/${threadId}/runs/${runId}`;
432
+ const headers = {
433
+ "Authorization": apikey,
434
+ "OpenAI-Beta": "assistants=v2"
435
+ }
436
+ const HTTPREQUEST = {
437
+ url: url,
438
+ headers: headers,
439
+ json: null,
440
+ method: "GET",
441
+ timeout: this.timeout
442
+ };
443
+ if (this.log) {console.log("DirAssistant HTTPREQUEST", HTTPREQUEST);}
444
+ this.#myrequest(
445
+ HTTPREQUEST, async (err, res) => {
446
+ let status = res.status;
447
+ if (err) {
448
+ if (this.log) {console.error("DirAssistant error:", err);}
449
+ reject(err);
450
+ }
451
+ else if(res.status >= 200 && res.status <= 299) {
452
+ if (this.log) {console.log("got response data:", res.data);}
453
+ // let return_body = res.data;
454
+ resolve(res.data);
455
+ }
456
+ else {
457
+ reject(new Error("Message add status != 200:", status));
458
+ }
459
+ }
460
+ );
461
+ });
462
+ }
463
+
464
+ async threadMessages(threadId, apikey) {
465
+ return new Promise( async (resolve, reject) => {
466
+ const url = `https://api.openai.com/v1/threads/${threadId}/messages`;
467
+ const headers = {
468
+ "Authorization": apikey,
469
+ "OpenAI-Beta": "assistants=v2"
470
+ }
471
+ const HTTPREQUEST = {
472
+ url: url,
473
+ headers: headers,
474
+ json: null,
475
+ method: "GET",
476
+ timeout: this.timeout
477
+ };
478
+ if (this.log) {console.log("DirAssistant HTTPREQUEST", HTTPREQUEST);}
479
+ this.#myrequest(
480
+ HTTPREQUEST, async (err, res) => {
481
+ let status = res.status;
482
+ if (err) {
483
+ if (this.log) {console.error("DirAssistant error:", err);}
484
+ reject(err);
485
+ }
486
+ else if(res.status >= 200 && res.status <= 299) {
487
+ if (this.log) {console.log("got response data:", res.data);}
488
+ // let return_body = res.data;
489
+ resolve(res.data);
490
+ }
491
+ else {
492
+ reject(new Error("Message add status != 200:", status));
493
+ }
494
+ }
495
+ );
496
+ });
497
+ }
498
+
499
+ async getKeyFromIntegrations(server_base_url) {
500
+ return new Promise((resolve) => {
501
+
502
+ const INTEGRATIONS_HTTPREQUEST = {
503
+ url: server_base_url + "/" + this.context.projectId + "/integration/name/openai",
504
+ headers: {
505
+ 'Content-Type': 'application/json',
506
+ 'Authorization': 'JWT ' + this.context.token
507
+ },
508
+ method: "GET"
509
+ }
510
+ if (this.log) { console.log("DirAssistant INTEGRATIONS_HTTPREQUEST ", INTEGRATIONS_HTTPREQUEST) }
511
+
512
+ this.#myrequest(
513
+ INTEGRATIONS_HTTPREQUEST, async (err, res) => {
514
+ if (err) {
515
+ resolve(null);
516
+ } else {
517
+ let integration = res.data;
518
+ if (integration &&
519
+ integration.value) {
520
+ resolve(integration.value.apikey)
521
+ }
522
+ else {
523
+ resolve(null)
524
+ }
525
+ }
526
+ })
527
+ })
528
+ }
529
+
530
+ #myrequest(options, callback) {
531
+ try {
532
+ if (this.log) {
533
+ console.log("API URL:", options.url);
534
+ //console.log("** Options:", JSON.stringify(options));
535
+ // Stringify "options". FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
536
+ let cache = [];
537
+ let str_Options = JSON.stringify(options, function(key, value) { // try to use a separate function
538
+ if (typeof value === 'object' && value != null) {
539
+ if (cache.indexOf(value) !== -1) {
540
+ return;
541
+ }
542
+ cache.push(value);
543
+ }
544
+ return value;
545
+ });
546
+ console.log("** Options:", str_Options);
547
+
548
+
549
+ }
550
+ let axios_options = {
551
+ url: options.url,
552
+ method: options.method,
553
+ params: options.params,
554
+ headers: options.headers,
555
+ timeout: options.timeout
556
+ }
557
+
558
+ if (options.json !== null) {
559
+ axios_options.data = options.json
560
+ }
561
+ // if (this.log) {
562
+ // console.log("axios_options:", JSON.stringify(axios_options));
563
+ // }
564
+ if (options.url.startsWith("https:")) {
565
+ const httpsAgent = new https.Agent({
566
+ rejectUnauthorized: false,
567
+ });
568
+ axios_options.httpsAgent = httpsAgent;
569
+ }
570
+
571
+ axios(axios_options)
572
+ .then((res) => {
573
+ if (this.log) {
574
+ // console.log("Success Response:", res);
575
+ console.log("Response for url:", options.url);
576
+ console.log("Response headers:\n", JSON.stringify(res.headers));
577
+ }
578
+ if (callback) {
579
+ callback(null, res);
580
+ }
581
+ })
582
+ .catch( (err) => {
583
+ if (this.log) {
584
+ if (err.response) {
585
+ console.log("Error Response data:", err.response.data);
586
+ }
587
+ // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
588
+ let cache = [];
589
+ let error_log = JSON.stringify(err, function(key, value) { // try to use a separate function
590
+ if (typeof value === 'object' && value != null) {
591
+ if (cache.indexOf(value) !== -1) {
592
+ return;
593
+ }
594
+ cache.push(value);
595
+ }
596
+ return value;
597
+ });
598
+ console.error("An error occurred: ", error_log);
599
+ // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - END
600
+ // console.error("An error occurred:", JSON.stringify(err));
601
+ }
602
+ if (callback) {
603
+ let status = 1000;
604
+ let cache = [];
605
+ let str_error = JSON.stringify(err, function(key, value) { // try to use a separate function
606
+ if (typeof value === 'object' && value != null) {
607
+ if (cache.indexOf(value) !== -1) {
608
+ return;
609
+ }
610
+ cache.push(value);
611
+ }
612
+ return value;
613
+ });
614
+ let error = JSON.parse(str_error) // "status" disappears without this trick
615
+ let errorMessage = JSON.stringify(error);
616
+ if (error.status) {
617
+ status = error.status;
618
+ }
619
+ if (error.message) {
620
+ errorMessage = error.message;
621
+ }
622
+ let data = null;
623
+ if (err.response) {
624
+ data = err.response.data;
625
+ }
626
+ callback(
627
+ null, {
628
+ status: status,
629
+ data: data,
630
+ error: errorMessage
631
+ }
632
+ );
633
+ }
634
+ });
635
+ }
636
+ catch(error) {
637
+ console.error("Error:", error);
638
+ }
639
+ }
640
+
641
+ }
642
+
643
+
644
+
645
+ module.exports = { DirAssistant };
@@ -35,36 +35,80 @@ class DirWebRequestV2 {
35
35
 
36
36
  async go(action, callback) {
37
37
  if (this.log) {console.log("webRequest action:", JSON.stringify(action));}
38
- let requestVariables = null;
38
+ let requestAttributes = null;
39
39
  if (this.tdcache) {
40
- requestVariables =
40
+ requestAttributes =
41
41
  await TiledeskChatbot.allParametersStatic(
42
42
  this.tdcache, this.requestId
43
43
  );
44
44
  }
45
45
  const filler = new Filler();
46
- const url = filler.fill(action.url, requestVariables);
46
+ const url = filler.fill(action.url, requestAttributes);
47
47
 
48
48
  let headers = {};
49
49
  if (action.headersString) {
50
50
  let headersDict = action.headersString
51
51
  for (const [key, value] of Object.entries(headersDict)) {
52
52
  if (this.log) {console.log("header:", key, "value:", value)}
53
- let filled_value = filler.fill(value, requestVariables);
53
+ let filled_value = filler.fill(value, requestAttributes);
54
54
  headers[key] = filled_value;
55
55
  }
56
56
  }
57
+
57
58
  let json = null;
58
- if (action.jsonBody && action.bodyType == "json") {
59
- if (this.log) {console.log("action.body is:", action.jsonBody);}
60
- let jsonBody = filler.fill(action.jsonBody, requestVariables);
61
- try {
62
- json = JSON.parse(jsonBody);
63
- if (this.log) {console.log("json is:", json);}
59
+ try {
60
+ if (action.jsonBody && action.bodyType == "json") {
61
+ if (this.log) {console.log("action.body is:", action.jsonBody);}
62
+ let jsonBody = filler.fill(action.jsonBody, requestAttributes);
63
+ try {
64
+ json = JSON.parse(jsonBody);
65
+ if (this.log) {console.log("json is:", json);}
66
+ }
67
+ catch(err) {
68
+ console.error("Error parsing webRequest jsonBody:", jsonBody);
69
+ }
70
+ }
71
+ else if (action.formData && action.bodyType == "form-data") {
72
+ let formData = filler.fill(action.formData, requestAttributes);
73
+ if (this.log) {console.log("action.body is form-data:", formData);}
74
+ // // fill
75
+ if (formData && formData.length > 0) {
76
+ for (let i = 0; i < formData.length; i++) {
77
+ let field = formData[i];
78
+ if (field.value) {
79
+ field.value = filler.fill(field.value, requestAttributes);
80
+ if (this.log) {console.log("field filled:", field.value);}
81
+ }
82
+ }
83
+ }
84
+ json = {};
85
+ for (let i = 0; i < formData.length; i++) {
86
+ let field = formData[i];
87
+ if (field.enabled && field.value && field.type === "URL") {
88
+ if (this.log) {console.log("Getting file:", field.value);}
89
+ let response = await axios.get(field.value,
90
+ {
91
+ responseType: 'stream'
92
+ }
93
+ );
94
+ let stream = response.data;
95
+ // if (this.log) {console.log("Stream data:", stream);}
96
+ json[field.name] = stream;
97
+ // process.exit(0);
98
+ }
99
+ else if (field.enabled && field.value && field.type === "Text") {
100
+ json[field.name] = field.value;
101
+ }
102
+ }
103
+ if (this.log) {console.log("final json:", json);}
64
104
  }
65
- catch(err) {
66
- console.error("Error parsing webRequest jsonBody:", jsonBody);
105
+ else {
106
+ if (this.log) {console.log("no action upload parts");}
67
107
  }
108
+
109
+ }
110
+ catch(error) {
111
+ console.error("Error", error);
68
112
  }
69
113
 
70
114
  // Condition branches
@@ -81,8 +125,9 @@ class DirWebRequestV2 {
81
125
  }
82
126
 
83
127
  let timeout = this.#webrequest_timeout(action, 20000, 1, 300000);
84
- console.log("final timeout", timeout);
128
+
85
129
  if (this.log) {console.log("webRequest URL", url);}
130
+
86
131
  const HTTPREQUEST = {
87
132
  url: url,
88
133
  headers: headers,
@@ -90,6 +135,7 @@ class DirWebRequestV2 {
90
135
  method: action.method,
91
136
  timeout: timeout
92
137
  };
138
+
93
139
  if (this.log) {console.log("webRequest HTTPREQUEST", HTTPREQUEST);}
94
140
  this.#myrequest(
95
141
  HTTPREQUEST, async (err, res) => {
@@ -203,63 +249,13 @@ class DirWebRequestV2 {
203
249
  }
204
250
 
205
251
  #myrequest(options, callback) {
206
- if (this.log) {
207
- console.log("API URL:", options.url);
208
- console.log("** Options:", JSON.stringify(options));
209
- }
210
- let axios_options = {
211
- url: options.url,
212
- method: options.method,
213
- params: options.params,
214
- headers: options.headers,
215
- timeout: options.timeout
216
- }
217
- if (options.json !== null) {
218
- axios_options.data = options.json
219
- }
220
- if (this.log) {
221
- console.log("axios_options:", JSON.stringify(axios_options));
222
- }
223
- if (options.url.startsWith("https:")) {
224
- const httpsAgent = new https.Agent({
225
- rejectUnauthorized: false,
226
- });
227
- axios_options.httpsAgent = httpsAgent;
228
- }
229
- axios(axios_options)
230
- .then((res) => {
252
+ try {
231
253
  if (this.log) {
232
- console.log("Success Response:", res);
233
- console.log("Response for url:", options.url);
234
- console.log("Response headers:\n", JSON.stringify(res.headers));
235
- }
236
- if (callback) {
237
- callback(null, res);
238
- }
239
- // if (callback) {
240
- // let data = null;
241
- // let status = 1000;
242
- // if (res) {
243
- // status = res.status;
244
- // data = res.data;
245
- // }
246
- // callback(
247
- // {
248
- // status: status,
249
- // data: data
250
- // }, null
251
- // );
252
- // }
253
-
254
- })
255
- .catch( (err) => {
256
- if (this.log) {
257
- if (err.response) {
258
- console.log("Error Response data:", err.response.data);
259
- }
260
- // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
254
+ console.log("API URL:", options.url);
255
+ //console.log("** Options:", JSON.stringify(options));
256
+ // Stringify "options". FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
261
257
  let cache = [];
262
- let error_log = JSON.stringify(err, function(key, value) { // try to use a separate function
258
+ let str_Options = JSON.stringify(options, function(key, value) { // try to use a separate function
263
259
  if (typeof value === 'object' && value != null) {
264
260
  if (cache.indexOf(value) !== -1) {
265
261
  return;
@@ -268,43 +264,99 @@ class DirWebRequestV2 {
268
264
  }
269
265
  return value;
270
266
  });
271
- console.error("An error occurred: ", error_log);
272
- // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - END
273
- // console.error("An error occurred:", JSON.stringify(err));
267
+ console.log("** Options:", str_Options);
268
+
269
+
274
270
  }
275
- if (callback) {
276
- let status = 1000;
277
- let cache = [];
278
- let str_error = JSON.stringify(err, function(key, value) { // try to use a separate function
279
- if (typeof value === 'object' && value != null) {
280
- if (cache.indexOf(value) !== -1) {
281
- return;
282
- }
283
- cache.push(value);
284
- }
285
- return value;
271
+ let axios_options = {
272
+ url: options.url,
273
+ method: options.method,
274
+ params: options.params,
275
+ headers: options.headers,
276
+ timeout: options.timeout
277
+ }
278
+
279
+ if (options.json !== null) {
280
+ axios_options.data = options.json
281
+ }
282
+ // if (this.log) {
283
+ // console.log("axios_options:", JSON.stringify(axios_options));
284
+ // }
285
+ if (options.url.startsWith("https:")) {
286
+ const httpsAgent = new https.Agent({
287
+ rejectUnauthorized: false,
286
288
  });
287
- let error = JSON.parse(str_error) // "status" disappears without this trick
288
- let errorMessage = JSON.stringify(error);
289
- if (error.status) {
290
- status = error.status;
289
+ axios_options.httpsAgent = httpsAgent;
290
+ }
291
+
292
+ axios(axios_options)
293
+ .then((res) => {
294
+ if (this.log) {
295
+ console.log("Success Response:", res);
296
+ console.log("Response for url:", options.url);
297
+ console.log("Response headers:\n", JSON.stringify(res.headers));
291
298
  }
292
- if (error.message) {
293
- errorMessage = error.message;
299
+ if (callback) {
300
+ callback(null, res);
294
301
  }
295
- let data = null;
296
- if (err.response) {
297
- data = err.response.data;
302
+ })
303
+ .catch( (err) => {
304
+ if (this.log) {
305
+ if (err.response) {
306
+ console.log("Error Response data:", err.response.data);
307
+ }
308
+ // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
309
+ let cache = [];
310
+ let error_log = JSON.stringify(err, function(key, value) { // try to use a separate function
311
+ if (typeof value === 'object' && value != null) {
312
+ if (cache.indexOf(value) !== -1) {
313
+ return;
314
+ }
315
+ cache.push(value);
316
+ }
317
+ return value;
318
+ });
319
+ console.error("An error occurred: ", error_log);
320
+ // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - END
321
+ // console.error("An error occurred:", JSON.stringify(err));
298
322
  }
299
- callback(
300
- null, {
301
- status: status,
302
- data: data,
303
- error: errorMessage
323
+ if (callback) {
324
+ let status = 1000;
325
+ let cache = [];
326
+ let str_error = JSON.stringify(err, function(key, value) { // try to use a separate function
327
+ if (typeof value === 'object' && value != null) {
328
+ if (cache.indexOf(value) !== -1) {
329
+ return;
330
+ }
331
+ cache.push(value);
332
+ }
333
+ return value;
334
+ });
335
+ let error = JSON.parse(str_error) // "status" disappears without this trick
336
+ let errorMessage = JSON.stringify(error);
337
+ if (error.status) {
338
+ status = error.status;
304
339
  }
305
- );
306
- }
307
- });
340
+ if (error.message) {
341
+ errorMessage = error.message;
342
+ }
343
+ let data = null;
344
+ if (err.response) {
345
+ data = err.response.data;
346
+ }
347
+ callback(
348
+ null, {
349
+ status: status,
350
+ data: data,
351
+ error: errorMessage
352
+ }
353
+ );
354
+ }
355
+ });
356
+ }
357
+ catch(error) {
358
+ console.error("Error:", error);
359
+ }
308
360
  }
309
361
 
310
362
  #webrequest_timeout(action, default_timeout, min, max) {
@@ -46,6 +46,7 @@ class Directives {
46
46
  static BLIND_TRANSFER = 'blind_transfer';
47
47
  static SPEECH_FORM = 'speech_form';
48
48
  static PLAY_PROMPT = 'play_prompt';
49
+ static GPT_ASSISTANT = 'gpt_assistant';
49
50
 
50
51
  // static WHEN_ONLINE_MOVE_TO_AGENT = "whenonlinemovetoagent"; // DEPRECATED?
51
52
  // static WHEN_OFFLINE_HOURS = "whenofflinehours"; // DEPRECATED // adds a message on top of the original message when offline hours opts: --replace