wingbot 3.71.6 → 3.72.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 (152) hide show
  1. package/.babelrc +0 -0
  2. package/.github/workflows/deploy.yml +2 -2
  3. package/.github/workflows/pullRequest.yml +2 -2
  4. package/LICENSE +0 -0
  5. package/README.md +0 -0
  6. package/index.js +0 -0
  7. package/jsconfig.json +0 -0
  8. package/package.json +1 -1
  9. package/plugins/ai.wingbot.clearMessageSequences/plugin.js +0 -0
  10. package/plugins/ai.wingbot.conditionIfGoBackPossible/plugin.js +0 -0
  11. package/plugins/ai.wingbot.disambiguation/plugin.js +0 -0
  12. package/plugins/ai.wingbot.goBack/plugin.js +0 -0
  13. package/plugins/ai.wingbot.goToLastBreadcrumb/plugin.js +0 -0
  14. package/plugins/ai.wingbot.ifImageDetected/plugin.js +0 -0
  15. package/plugins/ai.wingbot.ifStickerDetected/plugin.js +0 -0
  16. package/plugins/ai.wingbot.jumpBack/plugin.js +0 -0
  17. package/plugins/ai.wingbot.jumpTo/plugin.js +0 -0
  18. package/plugins/ai.wingbot.keepInInteraction/plugin.js +0 -0
  19. package/plugins/ai.wingbot.keepInInteractionJustOnce/plugin.js +0 -0
  20. package/plugins/ai.wingbot.keepPreviousHandlers/plugin.js +0 -0
  21. package/plugins/ai.wingbot.keepPreviousHandlersJustOnce/plugin.js +0 -0
  22. package/plugins/ai.wingbot.oneTimeNotificationRequest/plugin.js +0 -0
  23. package/plugins/ai.wingbot.openai/plugin.js +0 -0
  24. package/plugins/ai.wingbot.passThreadToBot/plugin.js +0 -0
  25. package/plugins/ai.wingbot.persona/plugin.js +0 -0
  26. package/plugins/ai.wingbot.putABreadcrumb/plugin.js +0 -0
  27. package/plugins/ai.wingbot.regexp/plugin.js +0 -0
  28. package/plugins/ai.wingbot.setState/plugin.js +0 -0
  29. package/plugins/ai.wingbot.setStateFromInput/plugin.js +0 -0
  30. package/plugins/ai.wingbot.slotsContinue/plugin.js +0 -0
  31. package/plugins/ai.wingbot.slotsRegister/plugin.js +0 -0
  32. package/plugins/ai.wingbot.stopResponding/plugin.js +0 -0
  33. package/plugins/ai.wingbot.trackingEvent/plugin.js +0 -0
  34. package/plugins/ai.wingbot.upload/plugin.js +0 -0
  35. package/plugins/ai.wingbot.waitASecond/plugin.js +0 -0
  36. package/plugins/index.js +0 -0
  37. package/plugins/plugins.json +0 -0
  38. package/src/Ai.js +44 -3
  39. package/src/AiMatching.js +66 -40
  40. package/src/BatchConversationTester.js +0 -0
  41. package/src/BotApp.js +0 -0
  42. package/src/BotAppSender.js +0 -0
  43. package/src/BuildRouter.js +2 -0
  44. package/src/CallbackAuditLog.js +0 -0
  45. package/src/ChatGpt.js +0 -0
  46. package/src/ConversationTester.js +0 -0
  47. package/src/LLM.js +183 -2
  48. package/src/LLMMockProvider.js +0 -0
  49. package/src/LLMSession.js +90 -3
  50. package/src/MockAiModel.js +0 -0
  51. package/src/OrchestratorClient.js +0 -0
  52. package/src/Plugins.js +0 -0
  53. package/src/Processor.js +1 -1
  54. package/src/ReducerWrapper.js +0 -0
  55. package/src/Request.js +0 -0
  56. package/src/Responder.js +143 -3
  57. package/src/ReturnSender.js +4 -4
  58. package/src/Router.js +0 -0
  59. package/src/RouterWrap.js +0 -0
  60. package/src/SecurityMiddleware.js +0 -0
  61. package/src/Tester.js +44 -2
  62. package/src/analytics/GA4.js +0 -0
  63. package/src/analytics/consts.js +0 -0
  64. package/src/analytics/onInteractionHandler.js +0 -0
  65. package/src/defaultResourceMap.js +0 -0
  66. package/src/features.js +0 -0
  67. package/src/flags.js +0 -0
  68. package/src/fuzzy/factoryFuzzySearch.js +0 -0
  69. package/src/fuzzy/fuzzyUtils.js +0 -0
  70. package/src/fuzzy/index.js +0 -0
  71. package/src/fuzzy/levenshtein.js +0 -0
  72. package/src/fuzzy/normalize.js +0 -0
  73. package/src/fuzzy/prepareFuzzyIndex.js +0 -0
  74. package/src/graphApi/GraphApi.js +0 -0
  75. package/src/graphApi/WingbotApiConnector.js +0 -0
  76. package/src/graphApi/apiAuthorizer.js +0 -0
  77. package/src/graphApi/conversationTestApi.js +0 -0
  78. package/src/graphApi/conversationsApi.js +0 -0
  79. package/src/graphApi/index.js +0 -0
  80. package/src/graphApi/postBackApi.js +0 -0
  81. package/src/graphApi/schema.gql +0 -0
  82. package/src/graphApi/validateBotApi.js +0 -0
  83. package/src/notifications/Notifications.js +0 -0
  84. package/src/notifications/NotificationsStorage.js +0 -0
  85. package/src/notifications/api/index.js +0 -0
  86. package/src/notifications/api/notificationsApiFactory.js +0 -0
  87. package/src/notifications/index.js +0 -0
  88. package/src/resolvers/bounce.js +0 -0
  89. package/src/resolvers/button.js +0 -0
  90. package/src/resolvers/carousel.js +0 -0
  91. package/src/resolvers/contextMessage.js +21 -4
  92. package/src/resolvers/expected.js +0 -0
  93. package/src/resolvers/expectedInput.js +0 -0
  94. package/src/resolvers/hbs.js +0 -0
  95. package/src/resolvers/include.js +0 -0
  96. package/src/resolvers/index.js +0 -0
  97. package/src/resolvers/media.js +0 -0
  98. package/src/resolvers/message.js +43 -1
  99. package/src/resolvers/passThread.js +0 -0
  100. package/src/resolvers/path.js +0 -0
  101. package/src/resolvers/plugin.js +0 -0
  102. package/src/resolvers/postback.js +0 -0
  103. package/src/resolvers/resolverTags.js +0 -0
  104. package/src/resolvers/setState.js +0 -0
  105. package/src/resolvers/skip.js +0 -0
  106. package/src/resolvers/subscribtions.js +0 -0
  107. package/src/resolvers/utils.js +14 -5
  108. package/src/systemEntities/email.js +0 -0
  109. package/src/systemEntities/index.js +0 -0
  110. package/src/systemEntities/phone.js +0 -0
  111. package/src/systemEntities/regexps.js +0 -0
  112. package/src/templates/BaseTemplate.js +0 -0
  113. package/src/templates/ButtonTemplate.js +0 -0
  114. package/src/templates/GenericTemplate.js +0 -0
  115. package/src/templates/ListTemplate.js +0 -0
  116. package/src/templates/ReceiptTemplate.js +0 -0
  117. package/src/testTools/AnyResponseAssert.js +0 -0
  118. package/src/testTools/PromptAssert.js +184 -0
  119. package/src/testTools/ResponseAssert.js +0 -0
  120. package/src/testTools/asserts.js +42 -4
  121. package/src/testTools/index.js +0 -0
  122. package/src/tools/MemoryBotConfigStorage.js +0 -0
  123. package/src/tools/MemoryChatLogStorage.js +0 -0
  124. package/src/tools/MemoryStateStorage.js +0 -0
  125. package/src/tools/bufferloader.js +0 -0
  126. package/src/tools/index.js +0 -0
  127. package/src/tools/routeToEvents.js +0 -0
  128. package/src/transcript/extractText.js +0 -0
  129. package/src/transcript/textBodyFromTranscript.js +0 -0
  130. package/src/transcript/transcriptFromHistory.js +0 -0
  131. package/src/utils/ai.js +0 -0
  132. package/src/utils/compileWithState.js +0 -0
  133. package/src/utils/customCondition.js +14 -1
  134. package/src/utils/customFn.js +0 -0
  135. package/src/utils/datetime.js +0 -0
  136. package/src/utils/deepMapTools.js +0 -0
  137. package/src/utils/generateToken.js +0 -0
  138. package/src/utils/getCondition.js +16 -4
  139. package/src/utils/getUpdate.js +4 -4
  140. package/src/utils/headersToAuditMeta.js +0 -0
  141. package/src/utils/index.js +0 -0
  142. package/src/utils/pathUtils.js +0 -0
  143. package/src/utils/quickReplies.js +0 -0
  144. package/src/utils/slots.js +0 -0
  145. package/src/utils/stateData.js +2 -0
  146. package/src/utils/stateVariables.js +0 -0
  147. package/src/utils/tokenizer.js +0 -0
  148. package/src/utils/wrapPluginFunction.js +0 -0
  149. package/src/wingbot/CachedModel.js +0 -0
  150. package/src/wingbot/CustomEntityDetectionModel.js +0 -0
  151. package/src/wingbot/WingbotModel.js +0 -0
  152. package/src/wingbot/index.js +0 -0
package/src/LLM.js CHANGED
@@ -3,16 +3,72 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
+ const { getSetState } = require('./utils/getUpdate');
6
7
  const { PHONE_REGEX, EMAIL_REGEX } = require('./systemEntities/regexps');
8
+ const getCondition = require('./utils/getCondition');
9
+ const stateData = require('./utils/stateData');
10
+ const Ai = require('./Ai');
11
+ // const getCondition = require('./utils/getCondition');
7
12
 
8
13
  /** @typedef {import('./Responder')} Responder */
14
+ /** @typedef {import('./AiMatching').PreprocessorOutput} PreprocessorOutput */
15
+ /** @typedef {import('./Request')} Request */
9
16
  /** @typedef {import('./Responder').Persona} Persona */
10
17
  /** @typedef {import('./Router').BaseConfiguration} BaseConfiguration */
11
18
  /** @typedef {import('./LLMSession').LLMMessage<any>} LLMMessage */
12
19
  /** @typedef {import('./LLMSession').ToolCall} ToolCall */
13
20
  /** @typedef {import('./LLMSession').LLMRole} LLMRole */
21
+ /** @typedef {import('./LLMSession').FilterScope} FilterScope */
14
22
  /** @typedef {import('./LLMSession')} LLMSession */
15
23
  /** @typedef {import('./transcript/transcriptFromHistory').Transcript} Transcript */
24
+ /** @typedef {import('./utils/getCondition').ConditionDefinition} ConditionDefinition */
25
+ /** @typedef {import('./utils/getCondition').ConditionContext} ConditionContext */
26
+ /** @typedef {import('./utils/stateData').IStateRequest} IStateRequest */
27
+
28
+ /** @typedef {string|'_DISCARD'} EvaluationRuleAction */
29
+
30
+ /**
31
+ * @typedef {object} EvaluationRuleData
32
+ * @prop {EvaluationRuleAction} [action]
33
+ * @prop {object} [setState]
34
+ */
35
+
36
+ /**
37
+ * @typedef {object} RuleDefinitionData
38
+ * @prop {string[]} aiTags
39
+ * @prop {EvaluationRuleAction} [targetRouteId]
40
+ */
41
+
42
+ /**
43
+ * @typedef {EvaluationRuleData & RuleDefinitionData & ConditionDefinition} EvaluationRule
44
+ */
45
+
46
+ /**
47
+ * @typedef {object} PrepocessedRuleData
48
+ * @prop {Function} condition
49
+ * @prop {PreprocessorOutput} rule
50
+ */
51
+
52
+ /**
53
+ * @typedef {EvaluationRuleData & PrepocessedRuleData} PreprocessedRule
54
+ */
55
+
56
+ /**
57
+ * @typedef {object} RuleScore
58
+ * @prop {number} score
59
+ */
60
+
61
+ /**
62
+ * @typedef {RuleScore & PreprocessedRule} RuleWithScore
63
+ */
64
+
65
+ /**
66
+ * @typedef {object} EvaluationResult
67
+ * @prop {string} action
68
+ * @prop {boolean} discard
69
+ * @prop {RuleWithScore[]} results
70
+ * @prop {object} setState
71
+ */
16
72
 
17
73
  /**
18
74
  * @callback LLMChatProviderPrompt
@@ -82,6 +138,13 @@ class LLM {
82
138
 
83
139
  static GPT_FLAG = 'gpt';
84
140
 
141
+ /** @type {FilterScope} */
142
+ static FILTER_SCOPE_CONVERSATION = 'conversation';
143
+
144
+ static EVALUATION_ACTIONS = {
145
+ DISCARD: '_DISCARD'
146
+ };
147
+
85
148
  /** @type {AnonymizeRegexp[]} */
86
149
  static anonymizeRegexps = [
87
150
  { replacement: '@PHONE', regex: new RegExp(PHONE_REGEX.source, 'g') },
@@ -91,8 +154,9 @@ class LLM {
91
154
  /**
92
155
  *
93
156
  * @param {LLMConfiguration} configuration
157
+ * @param {Ai} ai
94
158
  */
95
- constructor (configuration) {
159
+ constructor (configuration, ai) {
96
160
  const { provider, ...rest } = configuration;
97
161
 
98
162
  this._configuration = {
@@ -107,6 +171,25 @@ class LLM {
107
171
 
108
172
  /** @type {LLMChatProvider} */
109
173
  this._provider = provider;
174
+
175
+ this._ai = ai;
176
+
177
+ /** @type {LLMMessage} */
178
+ this._lastResult = null;
179
+ }
180
+
181
+ /**
182
+ * @returns {Ai}
183
+ */
184
+ get ai () {
185
+ return this._ai;
186
+ }
187
+
188
+ /**
189
+ * @returns {LLMMessage}
190
+ */
191
+ get lastResult () {
192
+ return this._lastResult;
110
193
  }
111
194
 
112
195
  /**
@@ -148,7 +231,7 @@ class LLM {
148
231
  ...options
149
232
  };
150
233
 
151
- const prompt = session.toArray();
234
+ const prompt = session.toArray(true);
152
235
  const result = await this._provider.requestChat(prompt, opts);
153
236
  this._logPrompt(prompt, result);
154
237
  return result;
@@ -160,6 +243,7 @@ class LLM {
160
243
  * @param {LLMMessage} result
161
244
  */
162
245
  _logPrompt (prompt, result) {
246
+ this._lastResult = result;
163
247
  this._configuration.logger.logPrompt({
164
248
  prompt, result
165
249
  });
@@ -188,6 +272,103 @@ class LLM {
188
272
  }));
189
273
  }
190
274
 
275
+ /**
276
+ *
277
+ * @param {EvaluationRule[]} rules
278
+ * @param {ConditionContext} [context]
279
+ * @returns {PreprocessedRule[]}
280
+ */
281
+ static preprocessEvaluationRules (rules, context = {}) {
282
+ const {
283
+ linksMap = new Map(),
284
+ ai = Ai.ai
285
+ } = context;
286
+
287
+ return rules.map((evalRule) => {
288
+ const { aiTags, targetRouteId, ...rest } = evalRule;
289
+
290
+ const condition = getCondition(rest, context);
291
+ const rule = ai.matcher.preprocessRule(aiTags);
292
+
293
+ let { action = null } = evalRule;
294
+
295
+ if (!action && targetRouteId && linksMap.has(targetRouteId)) {
296
+ action = linksMap.get(targetRouteId);
297
+ }
298
+
299
+ return {
300
+ ...rest,
301
+ condition,
302
+ rule
303
+ };
304
+ });
305
+ }
306
+
307
+ /**
308
+ * Returns all actions, which has been recognized
309
+ * with higher score than threshold, but
310
+ *
311
+ * - _DISCARD action discards any other rules (will return all relevant _DISCARD actions)
312
+ * - only the TOP ranked "interaction" action will be returned
313
+ * - actions will come in THE SAME order, so the "setState" will be applied in the same order
314
+ *
315
+ *
316
+ * @param {LLMMessage|string} result
317
+ * @param {PreprocessedRule[]} rules
318
+ * @param {IStateRequest} req
319
+ * @param {Responder} res
320
+ * @returns {Promise<EvaluationResult>}
321
+ */
322
+ async evaluateResultWithRules (result, rules, req, res) {
323
+ const text = typeof result === 'string' ? result : result.content;
324
+ const nlpResult = await this._ai.queryModel(text, req);
325
+ const state = stateData(req, res);
326
+
327
+ let topRankedAction = null;
328
+ let topActionScore = 0;
329
+ let discard = false;
330
+ const setState = {};
331
+
332
+ const sAct = Object.values(LLM.EVALUATION_ACTIONS);
333
+
334
+ const results = rules
335
+ .filter((rule) => rule.condition(req, res))
336
+ .map((rule) => {
337
+ const matched = this._ai.matcher
338
+ .matchText(text, rule.rule, nlpResult, state);
339
+
340
+ if (!matched || matched.score < this._ai.threshold) {
341
+ return null;
342
+ }
343
+
344
+ if (rule.action === LLM.EVALUATION_ACTIONS.DISCARD) {
345
+ discard = true;
346
+ } else if (rule.action && topActionScore < matched.score) {
347
+ topRankedAction = rule.action;
348
+ topActionScore = matched.score;
349
+ }
350
+
351
+ return {
352
+ ...rule,
353
+ score: matched.score
354
+ };
355
+ })
356
+ .filter((rule) => rule !== null
357
+ && (!discard || rule.action === LLM.EVALUATION_ACTIONS.DISCARD)
358
+ && (!rule.action || rule.action === topRankedAction || sAct.includes(rule.action)));
359
+
360
+ results.forEach((rule) => {
361
+ Object.assign(setState, getSetState(rule.setState, req, res, setState));
362
+ });
363
+
364
+ return {
365
+ setState,
366
+ results,
367
+ discard,
368
+ action: discard ? null : topRankedAction
369
+ };
370
+ }
371
+
191
372
  }
192
373
 
193
374
  module.exports = LLM;
File without changes
package/src/LLMSession.js CHANGED
@@ -13,6 +13,8 @@ const LLM = require('./LLM');
13
13
  /** @typedef {'tool'} LLMToolRole */
14
14
  /** @typedef {LLMChatRole|LLMSystemRole|LLMToolRole|string} LLMRole */
15
15
 
16
+ /** @typedef {LLMRole|'conversation'} FilterScope */
17
+
16
18
  /** @typedef {'stop'|'length'|'tool_calls'|'content_filter'} LLMFinishReason */
17
19
 
18
20
  /**
@@ -38,6 +40,19 @@ const LLM = require('./LLM');
38
40
  * @param {QuickReply[]} quickReplies
39
41
  */
40
42
 
43
+ /**
44
+ * @callback LLMFilterFn
45
+ * @param {string} text
46
+ * @param {LLMRole} role
47
+ * @returns {boolean|string}
48
+ */
49
+
50
+ /**
51
+ * @typedef {object} LLMFilter
52
+ * @prop {LLMFilterFn} filter
53
+ * @prop {FilterScope} scope
54
+ */
55
+
41
56
  /**
42
57
  * @class LLMSession
43
58
  */
@@ -48,8 +63,9 @@ class LLMSession {
48
63
  * @param {LLM} llm
49
64
  * @param {LLMMessage<any>[]} [chat]
50
65
  * @param {SendCallback} [onSend]
66
+ * @param {LLMFilter[]} [filters=[]]
51
67
  */
52
- constructor (llm, chat = [], onSend = () => {}) {
68
+ constructor (llm, chat = [], onSend = () => {}, filters = []) {
53
69
  this._llm = llm;
54
70
 
55
71
  this._onSend = onSend;
@@ -60,6 +76,13 @@ class LLMSession {
60
76
  this._generatedIndex = null;
61
77
 
62
78
  this._sort();
79
+
80
+ /** @type {LLMFilter[]} */
81
+ this._filters = filters;
82
+
83
+ this._SCOPE_CONVERSATION_ROLES = [
84
+ LLM.ROLE_ASSISTANT, LLM.ROLE_USER
85
+ ];
63
86
  }
64
87
 
65
88
  _sort (what = this._chat) {
@@ -114,10 +137,43 @@ class LLMSession {
114
137
  }
115
138
 
116
139
  /**
140
+ *
141
+ * @param {boolean} [filtered=false]
117
142
  * @returns {LLMMessage[]}
118
143
  */
119
- toArray () {
120
- return this._mergeSystem();
144
+ toArray (filtered = false) {
145
+ const messages = this._mergeSystem();
146
+ if (!filtered || this._filters.length === 0) {
147
+ return messages;
148
+ }
149
+ return messages
150
+ .map((message) => {
151
+ if (!message.content) {
152
+ return message;
153
+ }
154
+ const content = this._filters.reduce((text, filter) => {
155
+ if (!text) {
156
+ return text;
157
+ }
158
+ if (filter.scope !== message.role
159
+ && (filter.scope !== LLM.FILTER_SCOPE_CONVERSATION
160
+ || !this._SCOPE_CONVERSATION_ROLES.includes(message.role))) {
161
+ return text;
162
+ }
163
+ const res = filter.filter(text, message.role);
164
+ return res === true ? text : res;
165
+ }, message.content);
166
+
167
+ if (!content) {
168
+ return null;
169
+ }
170
+
171
+ return {
172
+ ...message,
173
+ content
174
+ };
175
+ })
176
+ .filter((message) => message !== null);
121
177
  }
122
178
 
123
179
  /**
@@ -200,6 +256,20 @@ class LLMSession {
200
256
  return this;
201
257
  }
202
258
 
259
+ /**
260
+ *
261
+ * @param {LLMFilter|LLMFilter[]} filter
262
+ * @returns {this}
263
+ */
264
+ addFilter (filter) {
265
+ if (Array.isArray(filter)) {
266
+ this._filters.push(...filter);
267
+ } else {
268
+ this._filters.push(filter);
269
+ }
270
+ return this;
271
+ }
272
+
203
273
  /**
204
274
  *
205
275
  * @param {LLMProviderOptions} [options={}]
@@ -214,6 +284,23 @@ class LLMSession {
214
284
  return result;
215
285
  }
216
286
 
287
+ /**
288
+ *
289
+ * @returns {string}
290
+ */
291
+ lastResponse () {
292
+ const messages = [];
293
+ for (let i = this._chat.length - 1; i >= 0; i--) {
294
+ const message = this._chat[i];
295
+
296
+ if (message.role !== LLM.ROLE_ASSISTANT || !message.content) {
297
+ break;
298
+ }
299
+ messages.unshift(message.content);
300
+ }
301
+ return messages.join('\n\n');
302
+ }
303
+
217
304
  /**
218
305
  *
219
306
  * @param {boolean} [dontMarkAsSent=false]
File without changes
File without changes
package/src/Plugins.js CHANGED
File without changes
package/src/Processor.js CHANGED
@@ -416,7 +416,7 @@ class Processor extends EventEmitter {
416
416
  });
417
417
  }
418
418
 
419
- const llm = new LLM(llmOptions);
419
+ const llm = new LLM(llmOptions, Ai.ai);
420
420
 
421
421
  const result = await this
422
422
  ._dispatch(message, pageId, messageSender, responderData, preloadPromise, llm);
File without changes
package/src/Request.js CHANGED
File without changes
package/src/Responder.js CHANGED
@@ -34,7 +34,14 @@ const EXCEPTION_HOPCOUNT_THRESHOLD = 5;
34
34
  /** @typedef {import('./analytics/consts').TrackingType} TrackingType */
35
35
 
36
36
  /** @typedef {import('./LLM').LLMConfiguration} LLMConfiguration */
37
+ /** @typedef {import('./LLM').PreprocessedRule} PreprocessedRule */
38
+ /** @typedef {import('./LLM').EvaluationRuleAction} EvaluationRuleAction */
39
+ /** @typedef {import('./LLM').EvaluationResult} EvaluationResult */
37
40
  /** @typedef {import('./LLMSession').LLMMessage} LLMMessage */
41
+ /** @typedef {import('./LLMSession').LLMFilterFn} LLMFilterFn */
42
+ /** @typedef {import('./LLMSession').LLMFilter} LLMFilter */
43
+ /** @typedef {import('./LLMSession').FilterScope} FilterScope */
44
+ /** @typedef {import('./utils/stateData').IStateRequest} IStateRequest */
38
45
 
39
46
  /**
40
47
  * @enum {string} ExpectedInput
@@ -243,6 +250,28 @@ class Responder {
243
250
  this._llmContext = new Map([
244
251
  [this.LLM_CTX_DEFAULT, []]
245
252
  ]);
253
+
254
+ /** @type {Map<string,PreprocessedRule[]>} */
255
+ this._llmResultRules = new Map([
256
+ [this.LLM_CTX_DEFAULT, []]
257
+ ]);
258
+
259
+ /** @type {Map<string,LLMFilter[]>} */
260
+ this._llmFilters = new Map([
261
+ [this.LLM_CTX_DEFAULT, []],
262
+ [null, []]
263
+ ]);
264
+ }
265
+
266
+ /**
267
+ *
268
+ * @deprecated use llmAddInstructions() instead
269
+ * @param {PromptSource} systemPrompt
270
+ * @param {string} [contextType]
271
+ * @returns {this}
272
+ */
273
+ llmAddSystemPrompt (systemPrompt, contextType) {
274
+ return this.llmAddInstructions(systemPrompt, contextType);
246
275
  }
247
276
 
248
277
  /**
@@ -251,7 +280,7 @@ class Responder {
251
280
  * @param {string} contextType
252
281
  * @returns {this}
253
282
  */
254
- llmAddSystemPrompt (systemPrompt, contextType = this.LLM_CTX_DEFAULT) {
283
+ llmAddInstructions (systemPrompt, contextType = this.LLM_CTX_DEFAULT) {
255
284
  if (!systemPrompt) {
256
285
  return this;
257
286
  }
@@ -264,12 +293,109 @@ class Responder {
264
293
  return this;
265
294
  }
266
295
 
296
+ /**
297
+ *
298
+ * @param {LLMFilter|LLMFilterFn} filter
299
+ * @param {FilterScope} [scope]
300
+ * @param {string} [contextType]
301
+ * @returns {this}
302
+ */
303
+ llmAddFilter (
304
+ filter,
305
+ scope = LLM.FILTER_SCOPE_CONVERSATION,
306
+ contextType = null
307
+ ) {
308
+ /** @type {LLMFilter} */
309
+ const addFilter = typeof filter === 'function'
310
+ ? {
311
+ filter,
312
+ scope
313
+ }
314
+ : filter;
315
+
316
+ if (!this._llmFilters.has(contextType)) {
317
+ this._llmFilters.set(contextType, []);
318
+ }
319
+ this._llmFilters.get(contextType).push(addFilter);
320
+ return this;
321
+ }
322
+
323
+ /**
324
+ *
325
+ * @param {string[]|PreprocessedRule} rule
326
+ * @param {EvaluationRuleAction} [action]
327
+ * @param {object} [setState]
328
+ * @param {string} [contextType]
329
+ * @returns {this}
330
+ */
331
+ llmAddResultRule (
332
+ rule,
333
+ action = null,
334
+ setState = null,
335
+ contextType = this.LLM_CTX_DEFAULT
336
+ ) {
337
+ let addRule = rule;
338
+
339
+ if (Array.isArray(addRule)) {
340
+ [addRule] = LLM.preprocessEvaluationRules([{
341
+ // @ts-ignore
342
+ aiTags: rule,
343
+ action,
344
+ setState
345
+ }], {
346
+ ai: this.llm.ai
347
+ });
348
+ }
349
+
350
+ if (!this._llmResultRules.has(contextType)) {
351
+ this._llmResultRules.set(contextType, []);
352
+ }
353
+ this._llmResultRules.get(contextType).push(addRule);
354
+ return this;
355
+ }
356
+
267
357
  async llmSession (contextType = this.LLM_CTX_DEFAULT) {
268
358
  const system = await this._getSystemContentForType(contextType);
269
359
 
270
360
  const chat = system.map((content) => ({ role: LLM.ROLE_SYSTEM, content }));
271
361
 
272
- return new LLMSession(this.llm, chat, this._llmSend.bind(this));
362
+ const filters = this._filtersForContext(contextType);
363
+ return new LLMSession(this.llm, chat, this._llmSend.bind(this), filters);
364
+ }
365
+
366
+ /**
367
+ *
368
+ * @param {LLMSession} session
369
+ * @param {string} [contextType]
370
+ * @returns {Promise<EvaluationResult>}
371
+ */
372
+ async llmEvaluate (session, contextType = this.LLM_CTX_DEFAULT) {
373
+ const rules = this._llmResultRules.get(contextType) || [];
374
+ const text = session.lastResponse();
375
+
376
+ if (rules.length === 0 || !text) {
377
+ return {
378
+ action: null,
379
+ setState: {},
380
+ results: [],
381
+ discard: false
382
+ };
383
+ }
384
+
385
+ /** @type {IStateRequest} */
386
+ const req = {
387
+ state: this.options.state,
388
+ text: () => text,
389
+ senderId: this._senderId,
390
+ pageId: this._pageId,
391
+ actionData: () => this._data,
392
+ isConfidentInput: () => false
393
+ };
394
+
395
+ const result = await this.llm.evaluateResultWithRules(text, rules, req, this);
396
+ this.setState(result.setState);
397
+
398
+ return result;
273
399
  }
274
400
 
275
401
  async _replaceAsync (str, regex, asyncFn) {
@@ -339,7 +465,20 @@ class Responder {
339
465
  ...LLM.anonymizeTranscript(transcript, transcriptAnonymize)
340
466
  ];
341
467
 
342
- return new LLMSession(this.llm, chat, this._llmSend.bind(this));
468
+ const filters = this._filtersForContext(contextType);
469
+ return new LLMSession(this.llm, chat, this._llmSend.bind(this), filters);
470
+ }
471
+
472
+ /**
473
+ *
474
+ * @param {string|null} contextType
475
+ * @returns {LLMFilter[]}
476
+ */
477
+ _filtersForContext (contextType) {
478
+ return [
479
+ ...(this._llmFilters.get(contextType) || []),
480
+ ...this._llmFilters.get(null)
481
+ ];
343
482
  }
344
483
 
345
484
  /**
@@ -394,6 +533,7 @@ class Responder {
394
533
  */
395
534
  setFlag (flag) {
396
535
  this._senderMeta.flag = flag;
536
+ // @ts-ignore
397
537
  return this;
398
538
  }
399
539
 
@@ -162,7 +162,7 @@ class ReturnSender {
162
162
  };
163
163
 
164
164
  /** @type {PromptInfo[]} */
165
- this._prompts = [];
165
+ this.prompts = [];
166
166
 
167
167
  this._responseTexts = [];
168
168
 
@@ -199,7 +199,7 @@ class ReturnSender {
199
199
  * @param {PromptInfo} promptInfo
200
200
  */
201
201
  logPrompt (promptInfo) {
202
- this._prompts.push(promptInfo);
202
+ this.prompts.push(promptInfo);
203
203
  }
204
204
 
205
205
  /**
@@ -669,7 +669,7 @@ class ReturnSender {
669
669
  const payload = {};
670
670
  const meta = {
671
671
  actions: this._visitedInteractions.slice(),
672
- prompts: this._prompts
672
+ prompts: this.prompts
673
673
  };
674
674
 
675
675
  if (req) {
@@ -697,7 +697,7 @@ class ReturnSender {
697
697
  _createMeta (req = null, res = null) { // eslint-disable-line no-unused-vars
698
698
  const meta = {
699
699
  visitedInteractions: this._visitedInteractions.slice(),
700
- prompts: this._prompts
700
+ prompts: this.prompts
701
701
  };
702
702
 
703
703
  if (req) {
package/src/Router.js CHANGED
File without changes
package/src/RouterWrap.js CHANGED
File without changes
File without changes