@tiledesk/tiledesk-tybot-connector 2.0.32 → 2.0.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "2.0.32",
3
+ "version": "2.0.34",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -252,8 +252,10 @@ class DirAiPrompt {
252
252
  error = err.response.data.detail[0]?.msg;
253
253
  } else if (err.response?.data?.detail?.answer) {
254
254
  error = err.response.data.detail.answer;
255
- } else {
255
+ } else if (err.response?.data) {
256
256
  error = JSON.stringify(err.response.data);
257
+ } else {
258
+ error = err.message || "General error executing action" // String(err);
257
259
  }
258
260
  this.logger.error("[AI Prompt] error executing action: ", error);
259
261
  if (falseIntent) {
@@ -30,11 +30,6 @@ class DirAskGPTV2 {
30
30
 
31
31
  this.intentDir = new DirIntent(context);
32
32
  this.logger = new Logger({ request_id: this.requestId, dev: this.context.supportRequest?.draft, intent_id: this.context.reply?.attributes?.intent_info?.intent_id });
33
-
34
- this.rerankingOff = false;
35
- if (process.env.RERANKING_OFF && (process.env.RERANKING_OFF === "true" || process.env.RERANKING_OFF === true)) {
36
- this.rerankingOff = true;
37
- }
38
33
  }
39
34
 
40
35
  execute(directive, callback) {
@@ -63,7 +58,6 @@ class DirAskGPTV2 {
63
58
  return;
64
59
  }
65
60
 
66
- let publicKey = false;
67
61
  let trueIntent = action.trueIntent;
68
62
  let falseIntent = action.falseIntent;
69
63
  let trueIntentAttributes = action.trueIntentAttributes;
@@ -74,11 +68,11 @@ class DirAskGPTV2 {
74
68
  winston.debug("DirAskGPTV2 trueIntentAttributes", trueIntentAttributes)
75
69
  winston.debug("DirAskGPTV2 falseIntentAttributes", falseIntentAttributes)
76
70
 
77
-
78
71
  // default values
79
72
  let answer = "No answers";
80
73
  let namespace = this.context.projectId;
81
- let model = "gpt-3.5-turbo";
74
+ let llm;
75
+ let model;
82
76
  let temperature;
83
77
  let max_tokens;
84
78
  let top_k;
@@ -87,7 +81,8 @@ class DirAskGPTV2 {
87
81
  let citations = false;
88
82
  let chunks_only = false;
89
83
  let engine;
90
- //let default_context = "You are an helpful assistant for question-answering tasks.\nUse ONLY the following pieces of retrieved context to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf none of the retrieved context answer the question, add this word to the end <NOANS>\n\n{context}";
84
+ let reranking;
85
+ let skip_unanswered;
91
86
 
92
87
  let contexts = {
93
88
  "gpt-3.5-turbo": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say: \"I don't know<NOANS>\"\n\n####{context}####",
@@ -105,16 +100,18 @@ class DirAskGPTV2 {
105
100
 
106
101
  let source = null;
107
102
 
108
- if (!action.question || action.question === '') {
109
- this.logger.error("[Ask Knowledge Base] question attribute is mandatory");
110
- winston.error("DirAskGPTV2 Error: question attribute is mandatory. Executing condition false...");
103
+ await this.checkMandatoryParameters(action).catch( async (missing_param) => {
104
+ this.logger.error(`[Ask Knowledge Base] missing attribute '${missing_param}'`);
105
+ await this.chatbot.addParameter("flowError", `AskKnowledgeBase Error: '${missing_param}' attribute is undefined`);
111
106
  await this.#assignAttributes(action, answer, source);
112
107
  if (falseIntent) {
113
108
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
109
+ callback(true);
110
+ return Promise.reject();
114
111
  }
115
- callback(true);
116
- return;
117
- }
112
+ callback();
113
+ return Promise.reject();
114
+ })
118
115
 
119
116
  if (action.namespace) {
120
117
  namespace = action.namespace;
@@ -122,30 +119,27 @@ class DirAskGPTV2 {
122
119
  if (action.model) {
123
120
  model = action.model;
124
121
  }
125
-
126
122
  if (action.top_k) {
127
123
  top_k = action.top_k;
128
124
  }
129
-
130
125
  if (action.temperature) {
131
126
  temperature = action.temperature;
132
127
  }
133
-
134
128
  if (action.max_tokens) {
135
129
  max_tokens = action.max_tokens;
136
130
  }
137
-
138
131
  if (action.alpha) {
139
132
  alpha = action.alpha;
140
133
  }
141
-
142
134
  if (action.citations) {
143
135
  citations = action.citations;
144
136
  }
145
-
146
137
  if (action.chunks_only) {
147
138
  chunks_only = action.chunks_only;
148
139
  }
140
+ if (action.reranking) {
141
+ reranking = action.reranking;
142
+ }
149
143
 
150
144
  let requestVariables = null;
151
145
  requestVariables =
@@ -175,41 +169,67 @@ class DirAskGPTV2 {
175
169
  }
176
170
  }
177
171
 
178
- let key = await integrationService.getKeyFromIntegrations(this.projectId, 'openai', this.token);
179
- if (!key) {
180
- this.logger.native("[Ask Knowledge Base] OpenAI key not found in Integration. Using shared OpenAI key");
181
- winston.verbose("DirAskGPTV2 - Key not found in Integrations. Searching in kb settings...");
182
- key = await kbService.getKeyFromKbSettings(this.projectId, this.token);
183
- }
184
-
185
- if (!key) {
186
- winston.verbose("DirAskGPTV2 - Retrieve public gptkey")
187
- key = process.env.GPTKEY;
188
- publicKey = true;
172
+ let key;
173
+ let publicKey = false;
174
+ let ollama_integration;
175
+
176
+ if (action.llm === 'ollama') {
177
+ ollama_integration = await integrationService.getIntegration(this.projectId, action.llm, this.token).catch( async (err) => {
178
+ this.logger.error("[Ask Knowledge Base] Error getting ollama integration.");
179
+ await this.chatbot.addParameter("flowError", "Ollama integration not found");
180
+ if (falseIntent) {
181
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
182
+ callback(true);
183
+ return;
184
+ }
185
+ callback();
186
+ return;
187
+ })
189
188
  } else {
190
- this.logger.native("[Ask Knowledge Base] use your own OpenAI key")
191
- }
189
+ key = await integrationService.getKeyFromIntegrations(this.projectId, action.llm, this.token);
192
190
 
193
- if (!key) {
194
- winston.info("DirAskGPTV2 Error: gptkey is mandatory");
195
- await this.#assignAttributes(action, answer);
196
- if (falseIntent) {
197
- await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
198
- callback(true);
191
+ if (!key && action.llm === 'openai') {
192
+ this.logger.native("[Ask Knowledge Base] OpenAI key not found in Integration. Retrieve shared OpenAI key.");
193
+ key = process.env.GPTKEY;
194
+ publicKey = true;
195
+ }
196
+
197
+ if (!key) {
198
+ this.logger.error(`[Ask Knowledge Base] llm key for ${action.llm} not found in integrations`);
199
+ await this.chatbot.addParameter("flowError", `AskKnowledgeBase Error: missing key for llm ${action.llm}`);
200
+ if (falseIntent) {
201
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
202
+ callback(true);
203
+ return;
204
+ }
205
+ callback();
199
206
  return;
200
207
  }
201
- callback();
202
- return;
203
208
  }
204
209
 
205
210
  if (publicKey === true && !chunks_only) {
206
- let keep_going = await quotasService.checkQuoteAvailability(this.projectId, this.token);
207
- if (keep_going === false) {
208
- this.logger.warn("[Ask Knowledge Base] Tokens quota exceeded. Skip the action")
209
- winston.verbose("DirAskGPTV2 - Quota exceeded for tokens. Skip the action")
210
- await this.chatbot.addParameter("flowError", "AskGPT Error: tokens quota exceeded");
211
- await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
212
- callback(true);
211
+ try {
212
+ let keep_going = await quotasService.checkQuoteAvailability(this.projectId, this.token)
213
+ if (keep_going === false) {
214
+ this.logger.warn("[AI Prompt] OpenAI tokens quota exceeded");
215
+ await this.chatbot.addParameter("flowError", "GPT Error: tokens quota exceeded");
216
+ if (falseIntent) {
217
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
218
+ callback();
219
+ return;
220
+ }
221
+ callback();
222
+ return;
223
+ }
224
+ } catch (err) {
225
+ this.logger.error("An error occured on checking token quota availability");
226
+ await this.chatbot.addParameter("flowError", "An error occured on checking token quota availability");
227
+ if (falseIntent) {
228
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
229
+ callback();
230
+ return;
231
+ }
232
+ callback();
213
233
  return;
214
234
  }
215
235
  }
@@ -262,6 +282,7 @@ class DirAskGPTV2 {
262
282
  question: filled_question,
263
283
  gptkey: key,
264
284
  namespace: namespace,
285
+ llm: llm,
265
286
  model: model,
266
287
  citations: citations,
267
288
  engine: engine,
@@ -280,6 +301,16 @@ class DirAskGPTV2 {
280
301
  json.chunks_only = chunks_only;
281
302
  }
282
303
 
304
+ if (llm === 'ollama') {
305
+ json.gptkey = "";
306
+ json.model = {
307
+ name: action.model,
308
+ url: ollama_integration.value.url,
309
+ token: ollama_integration.value.token
310
+ }
311
+ json.stream = false;
312
+ }
313
+
283
314
 
284
315
  if (ns.hybrid === true) {
285
316
  json.search_type = 'hybrid';
@@ -287,10 +318,11 @@ class DirAskGPTV2 {
287
318
  }
288
319
 
289
320
  if (!action.advancedPrompt) {
321
+ const contextTemplate = contexts[model] || contexts["general"];
290
322
  if (filled_context) {
291
- json.system_context = filled_context + "\n" + contexts[model];
323
+ json.system_context = filled_context + "\n" + contextTemplate;
292
324
  } else {
293
- json.system_context = contexts[model];
325
+ json.system_context = contextTemplate;
294
326
  }
295
327
  } else {
296
328
  json.system_context = filled_context;
@@ -300,13 +332,12 @@ class DirAskGPTV2 {
300
332
  json.chat_history_dict = await this.transcriptToLLM(transcript);
301
333
  }
302
334
 
303
- if (!this.rerankingOff) {
335
+ if (reranking === true) {
304
336
  json.reranking = true;
305
337
  json.reranking_multiplier = 3;
306
338
  json.reranker_model = "cross-encoder/ms-marco-MiniLM-L-6-v2";
307
339
  }
308
340
 
309
-
310
341
  winston.debug("DirAskGPTV2 json:", json);
311
342
 
312
343
  let kb_endpoint = process.env.KB_ENDPOINT_QA;
@@ -330,7 +361,8 @@ class DirAskGPTV2 {
330
361
  HTTPREQUEST, async (err, resbody) => {
331
362
 
332
363
  if (err) {
333
- winston.error("DirAskGPTV2 error: ", err?.respose);
364
+ winston.error("DirAskGPTV2 error: ", err?.response);
365
+ this.logger.error(`[Ask Knowledge Base] Error getting answer`);
334
366
  await this.#assignAttributes(action, answer, source);
335
367
  if (callback) {
336
368
  if (falseIntent) {
@@ -356,7 +388,7 @@ class DirAskGPTV2 {
356
388
 
357
389
  } else {
358
390
  await this.#assignAttributes(action, resbody.answer, resbody.source, resbody.content_chunks);
359
- if (publicKey === true) {
391
+ if (publicKey === true && !chunks_only) {
360
392
  let tokens_usage = {
361
393
  tokens: resbody.prompt_token_size,
362
394
  model: json.model
@@ -376,10 +408,12 @@ class DirAskGPTV2 {
376
408
  }
377
409
  } else {
378
410
  await this.#assignAttributes(action, answer, source);
379
- kbService.addUnansweredQuestion(this.projectId, json.namespace, json.question, this.token).catch((err) => {
380
- winston.error("DirAskGPTV2 - Error adding unanswered question: ", err);
381
- this.logger.warn("[Ask Knowledge Base] Unable to add unanswered question", json.question, "to namespacae", json.namespace);
382
- })
411
+ if (!skip_unanswered) {
412
+ kbService.addUnansweredQuestion(this.projectId, json.namespace, json.question, this.token).catch((err) => {
413
+ winston.error("DirAskGPTV2 - Error adding unanswered question: ", err);
414
+ this.logger.warn("[Ask Knowledge Base] Unable to add unanswered question", json.question, "to namespacae", json.namespace);
415
+ })
416
+ }
383
417
  if (falseIntent) {
384
418
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
385
419
  callback(true);
@@ -450,6 +484,18 @@ class DirAskGPTV2 {
450
484
  }
451
485
  }
452
486
 
487
+ async checkMandatoryParameters(action) {
488
+ return new Promise((resolve, reject) => {
489
+ let params = ['question', 'llm', 'model']; // mandatory params
490
+ params.forEach((p) => {
491
+ if (!action[p]) {
492
+ reject(p)
493
+ }
494
+ })
495
+ resolve(true);
496
+ })
497
+ }
498
+
453
499
  /**
454
500
  * Transforms the transcirpt array in a dictionary like '0': { "question": "xxx", "answer":"xxx"}
455
501
  * merging consecutive messages with the same role in a single question or answer.
@@ -908,7 +908,7 @@ class TiledeskChatbotUtil {
908
908
  winston.debug("(TiledeskChatbotUtil) Adding Globals to context: ", _bot);
909
909
 
910
910
  if (_bot.attributes && _bot.attributes.globals) {
911
- winston.error("(TiledeskChatbotUtil) Got Globals: ", _bot.attributes.globals);
911
+ winston.debug("(TiledeskChatbotUtil) Got Globals: ", _bot.attributes.globals);
912
912
  _bot.attributes.globals.forEach(async (global_var) => {
913
913
  winston.error("(TiledeskChatbotUtil) Adding global: " + global_var.key + " value: " + global_var.value);
914
914
  await chatbot.addParameter(global_var.key, global_var.value);