wingbot 3.69.7 → 3.70.0-alpha.4

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/index.js CHANGED
@@ -3,8 +3,6 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
- /** @typedef {import('./src/Processor').ProcessorOptions<Router|BuildRouter>} ProcessorOptions */
7
-
8
6
  const Processor = require('./src/Processor');
9
7
  const Router = require('./src/Router');
10
8
  const Request = require('./src/Request');
package/jsconfig.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "module": "commonjs",
4
- "lib": ["es6"],
5
- "target": "es2019",
4
+ "lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string", "dom"],
5
+ "target": "ESNext",
6
6
  "allowSyntheticDefaultImports": true,
7
7
  "checkJs": true,
8
8
  "resolveJsonModule": true
@@ -14,4 +14,4 @@
14
14
  "doc",
15
15
  "docs"
16
16
  ]
17
- }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wingbot",
3
- "version": "3.69.7",
3
+ "version": "3.70.0-alpha.4",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -37,6 +37,7 @@
37
37
  },
38
38
  "homepage": "https://github.com/wingbot.ai/wingbot#readme",
39
39
  "devDependencies": {
40
+ "@types/mocha": "^10.0.10",
40
41
  "cpy-cli": "^5.0.0",
41
42
  "eslint": "^8.56.0",
42
43
  "eslint-config-airbnb": "^19.0.4",
@@ -61,7 +62,7 @@
61
62
  "graphql": "^16.8.1",
62
63
  "jsonwebtoken": "^9.0.2",
63
64
  "node-fetch": "^2.6.7",
64
- "path-to-regexp": "^6.2.1",
65
+ "path-to-regexp": "^6.3.0",
65
66
  "uuid": "^9.0.1",
66
67
  "webalize": "^0.1.0"
67
68
  },
@@ -69,4 +70,4 @@
69
70
  "axios": "^1.6.4",
70
71
  "handlebars": "^4.0.0"
71
72
  }
72
- }
73
+ }
@@ -77,6 +77,10 @@ const PLUGIN_RESOLVER_NAME = 'botbuild.customCode';
77
77
  * @typedef {Map<string|number,string>} LinksMap
78
78
  */
79
79
 
80
+ /**
81
+ * @typedef {Map<string|number, Block>} BlockMap
82
+ */
83
+
80
84
  /** @type {TransformedRoute} */
81
85
  const DUMMY_ROUTE = { id: 0, path: null, resolvers: [] };
82
86
 
@@ -136,6 +140,7 @@ const DUMMY_ROUTE = { id: 0, path: null, resolvers: [] };
136
140
 
137
141
  /**
138
142
  * @typedef {object} BotContextExtention
143
+ * @prop {BlockMap} [nestedBlocksByStaticId]
139
144
  * @prop {LinksMap} [linksMap]
140
145
  * @prop {boolean} [isLastIndex]
141
146
  * @prop {boolean} [isLastMessage]
@@ -565,11 +570,12 @@ class BuildRouter extends Router {
565
570
  ...this._resolvedContext, blockName, blockType, isRoot, staticBlockId, BuildRouter
566
571
  };
567
572
 
568
- this._linksMap = this._createLinksMap(block);
569
-
570
- this._setExpectedFromResponderRoutes(block.routes);
573
+ const [linksMap, nestedBlocksByStaticId] = this._createLinksMap(block);
574
+ // @ts-ignore
575
+ this._linksMap = linksMap;
571
576
 
572
- this._buildRoutes(block.routes);
577
+ // @ts-ignore
578
+ this._buildRoutes(block.routes, nestedBlocksByStaticId);
573
579
 
574
580
  this._configTs = setConfigTimestamp;
575
581
 
@@ -577,74 +583,79 @@ class BuildRouter extends Router {
577
583
  this.emit('rebuild');
578
584
  }
579
585
 
580
- _setExpectedFromResponderRoutes (routes) {
581
- const set = new Set();
582
-
583
- routes.forEach((route) => {
584
- if (!route.isResponder) {
585
- return;
586
- }
587
-
588
- // create the pseudopath ant set to set to corresponding route
589
- const referredRoutePath = this._linksMap.get(route.respondsToRouteId);
590
-
591
- if (!referredRoutePath) {
592
- return;
593
- }
594
-
595
- const expectedPath = `${referredRoutePath}_responder`
596
- .replace(/^\//, '');
597
-
598
- Object.assign(route, { path: expectedPath });
599
-
600
- // set expectedPath to referredRoute
601
-
602
- if (set.has(route.respondsToRouteId)) {
603
- return;
604
- }
605
- set.add(route.respondsToRouteId);
606
-
607
- const referredRoute = routes.find((r) => r.id === route.respondsToRouteId);
608
-
609
- Object.assign(referredRoute, { expectedPath });
610
- });
611
- }
612
-
613
586
  /**
587
+ *
588
+ * returns {[LinksMap, BlockMap]}
614
589
  *
615
590
  * @param {Block} block
616
- * @returns {LinksMap}
617
591
  */
618
592
  _createLinksMap (block) {
593
+ const { linksMap: prevLinksMap, blocks = [] } = this._resolvedContext;
594
+
619
595
  /** @type {LinksMap} */
620
596
  const linksMap = new Map();
621
597
 
598
+ if (prevLinksMap) {
599
+ for (const [from, to] of prevLinksMap.entries()) {
600
+ linksMap.set(from, `../${to}`); // this._joinPaths('..', to)
601
+ }
602
+ }
603
+
604
+ const expectedFromResponders = new Set();
605
+
606
+ const blocksById = new Map();
607
+
622
608
  block.routes
623
- .filter((route) => !route.isResponder)
624
- .forEach((route) => linksMap.set(route.id, route.path));
609
+ .forEach((route) => {
610
+ if (!route.isResponder) {
611
+ linksMap.set(route.id, route.path);
612
+ }
613
+ blocksById.set(route.id, route);
614
+ });
625
615
 
626
- const { linksMap: prevLinksMap } = this._resolvedContext;
616
+ let { nestedBlocksByStaticId } = this._resolvedContext;
617
+ if (!nestedBlocksByStaticId) {
618
+ nestedBlocksByStaticId = new Map();
627
619
 
628
- if (prevLinksMap) {
629
- for (const [from, to] of prevLinksMap.entries()) {
630
- if (!linksMap.has(from)) {
631
- linksMap.set(from, this._joinPaths('..', to));
620
+ blocks.forEach((b) => {
621
+ if (b.staticBlockId && !b.disabled) {
622
+ nestedBlocksByStaticId.set(b.staticBlockId, b);
632
623
  }
633
- }
624
+ });
625
+
626
+ Object.assign(this._resolvedContext, { nestedBlocksByStaticId });
634
627
  }
635
628
 
636
629
  block.routes.forEach((route) => {
637
- const enabledNestedBlock = this._getBlockById(this._getIncludedBlockId(route));
638
- if (!enabledNestedBlock) {
639
- return;
630
+ const enabledNestedBlock = nestedBlocksByStaticId.get(this._getIncludedBlockId(route));
631
+ if (enabledNestedBlock) {
632
+ const routeConfig = this._getRouteConfig(route);
633
+ if (this._enabledByRouteConfig(routeConfig)) {
634
+ this._findEntryPointsInResolver(linksMap, enabledNestedBlock, route);
635
+ }
640
636
  }
641
- const routeConfig = this._getRouteConfig(route);
642
- if (this._enabledByRouteConfig(routeConfig)) {
643
- this._findEntryPointsInResolver(linksMap, enabledNestedBlock, route);
637
+
638
+ if (route.isResponder) {
639
+ // create the pseudopath ant set to set to corresponding route
640
+ const referredRoutePath = linksMap.get(route.respondsToRouteId);
641
+
642
+ if (referredRoutePath) {
643
+ const expectedPath = `${referredRoutePath}_responder`
644
+ .replace(/^\//, '');
645
+
646
+ Object.assign(route, { path: expectedPath });
647
+
648
+ if (!expectedFromResponders.has(route.respondsToRouteId)) {
649
+ expectedFromResponders.add(route.respondsToRouteId);
650
+
651
+ const referredRoute = blocksById.get(route.respondsToRouteId);
652
+ Object.assign(referredRoute, { expectedPath });
653
+ }
654
+ }
644
655
  }
645
656
  });
646
657
 
647
- return linksMap;
658
+ return [linksMap, nestedBlocksByStaticId];
648
659
  }
649
660
 
650
661
  /**
@@ -682,24 +693,6 @@ class BuildRouter extends Router {
682
693
  : null;
683
694
  }
684
695
 
685
- /**
686
- *
687
- * @param {string} staticBlockId
688
- * @returns {Block|null}
689
- */
690
- _getBlockById (staticBlockId) {
691
- if (!staticBlockId) {
692
- return null;
693
- }
694
- const nestedBlock = (this._resolvedContext.blocks || [])
695
- .find((b) => b.staticBlockId === staticBlockId);
696
-
697
- if (!nestedBlock || nestedBlock.disabled) {
698
- return null;
699
- }
700
- return nestedBlock;
701
- }
702
-
703
696
  /**
704
697
  *
705
698
  * @param {TransformedRoute} route
@@ -811,8 +804,9 @@ class BuildRouter extends Router {
811
804
  /**
812
805
  *
813
806
  * @param {TransformedRoute[]} routes
807
+ * @param {BlockMap} nestedBlocksByStaticId
814
808
  */
815
- _buildRoutes (routes) {
809
+ _buildRoutes (routes, nestedBlocksByStaticId) {
816
810
  routes.forEach((route, i) => {
817
811
  const routeConfig = this._getRouteConfig(route);
818
812
 
@@ -821,7 +815,7 @@ class BuildRouter extends Router {
821
815
  }
822
816
 
823
817
  const includedBlockId = this._getIncludedBlockId(route);
824
- const nestedBlock = this._getBlockById(includedBlockId);
818
+ const nestedBlock = nestedBlocksByStaticId.get(includedBlockId);
825
819
 
826
820
  if (includedBlockId && (!nestedBlock || !this._enabledByRouteConfig(routeConfig))) {
827
821
  return;
@@ -882,9 +876,10 @@ class BuildRouter extends Router {
882
876
  * @param {Resolver[]} resolvers
883
877
  * @param {TransformedRoute} [route]
884
878
  * @param {BuildInfo} [buildInfo]
879
+ * @param {BlockMap} [nestedBlocksByStaticId=null]
885
880
  * @returns {Middleware<S,C>[]}
886
881
  */
887
- buildResolvers (resolvers, route = DUMMY_ROUTE, buildInfo = {}) {
882
+ buildResolvers (resolvers, route = DUMMY_ROUTE, buildInfo = {}, nestedBlocksByStaticId = null) {
888
883
  const {
889
884
  path: ctxPath, isFallback, isResponder, expectedPath, id
890
885
  } = route;
@@ -911,7 +906,8 @@ class BuildRouter extends Router {
911
906
  expectedPath,
912
907
  routeId: id,
913
908
  configuration,
914
- resolverId: resolver.id
909
+ resolverId: resolver.id,
910
+ nestedBlocksByStaticId
915
911
  };
916
912
 
917
913
  const resFn = this._resolverFactory(resolver, context, buildInfo);
package/src/ChatGpt.js CHANGED
@@ -6,11 +6,14 @@
6
6
  const nodeFetch = require('node-fetch').default;
7
7
  const util = require('util');
8
8
  const { PHONE_REGEX, EMAIL_REGEX } = require('./systemEntities/regexps');
9
+ const LLM = require('./LLM');
9
10
 
10
11
  /** @typedef {import('node-fetch').default} Fetch */
11
12
  /** @typedef {import('./Request')} Request */
12
13
  /** @typedef {import('./Responder')} Responder */
13
14
  /** @typedef {import('./Responder').QuickReply} QuickReply */
15
+ /** @typedef {import('./LLM').LLMMessage} LLMMessage */
16
+ /** @typedef {import('./LLM').LLMProviderOptions} LLMProviderOptions */
14
17
 
15
18
  /**
16
19
  * @typedef {object} Transcript
@@ -59,7 +62,7 @@ const { PHONE_REGEX, EMAIL_REGEX } = require('./systemEntities/regexps');
59
62
 
60
63
  /**
61
64
  * @typedef {object} ChatGPTChoice
62
- * @prop {'stop'|'length'|'function_call'|'content_filter'|null} finish_reason
65
+ * @prop {'stop'|'length'|'tool_calls'|'content_filter'|null} finish_reason
63
66
  * @prop {number} index
64
67
  * @prop {Message} message
65
68
  */
@@ -237,16 +240,31 @@ class ChatGpt {
237
240
  }));
238
241
  }
239
242
 
243
+ /**
244
+ * @param {LLMMessage[]} prompt
245
+ * @param {LLMProviderOptions} [options]
246
+ * @returns {Promise<LLMMessage>}
247
+ */
248
+ async requestChat (prompt, options) {
249
+
250
+ const choice = await this._request(prompt, options);
251
+
252
+ const { finish_reason: finishReason, message } = choice;
253
+
254
+ return {
255
+ finishReason,
256
+ ...message
257
+ };
258
+ }
259
+
240
260
  /**
241
261
  *
242
- * @param {string} content
243
- * @param {string} [system]
244
- * @param {Transcript[]} [transcript]
245
- * @param {RequestOptions} [requestOptions]
246
- * @param {string|Request} [user]
262
+ * @param {LLMMessage[]} chat
263
+ * @param {RequestOptions} requestOptions
264
+ * @param {string} user
247
265
  * @returns {Promise<ChatGPTChoice>}
248
266
  */
249
- async request (content, system = null, transcript = [], requestOptions = {}, user = null) {
267
+ async _request (chat, requestOptions, user = null) {
250
268
  const {
251
269
  requestTokens,
252
270
  tokensLimit,
@@ -259,50 +277,51 @@ class ChatGpt {
259
277
  ...requestOptions
260
278
  };
261
279
 
280
+ let messages = chat;
262
281
  const maxTokens = Math.min(requestTokens, tokensLimit);
263
282
 
264
283
  let body;
265
-
266
284
  try {
285
+ let lastUserIndex = 0;
286
+ let totalTokens = messages
287
+ .reduce((total, m, i) => {
288
+ if (m.role === LLM.ROLE_USER) {
289
+ lastUserIndex = i;
290
+ }
291
+ return (m.content ? 0 : m.content.length) + total;
292
+ }, 0);
293
+
294
+ if (totalTokens > tokensLimit) {
295
+ messages = messages.filter((m, i) => {
296
+ if (m.role === LLM.ROLE_SYSTEM
297
+ || i >= lastUserIndex
298
+ || totalTokens <= tokensLimit
299
+ || !m.content) {
300
+
301
+ return true;
302
+ }
303
+ totalTokens -= m.content.length;
304
+ return false;
305
+ });
306
+ }
307
+
267
308
  body = {
268
309
  model,
269
310
  frequency_penalty: 0,
270
311
  presence_penalty: presencePenalty,
271
312
  max_tokens: maxTokens,
272
313
  temperature,
273
- ...(functions.length ? { functions } : {})
314
+ messages
274
315
  };
275
316
 
276
- if (typeof user === 'string') {
317
+ if (user) {
277
318
  Object.assign(body, { user });
278
- } else if (user) {
279
- Object.assign(body, { user: `${user.pageId}|${user.senderId}` });
280
- } else if (this._defaultUser) {
281
- Object.assign(body, { user: this._defaultUser });
282
319
  }
283
320
 
284
- let total = (system ? system.length : 0)
285
- + maxTokens
286
- + content.length;
287
-
288
- const ts = transcript.slice();
289
-
290
- for (let i = ts.length - 1; i >= 0; i--) {
291
- total += ts[i].text.length;
292
- if (total > tokensLimit) {
293
- ts.splice(i, 1);
294
- }
321
+ if (functions.length) {
322
+ Object.assign(body, { functions });
295
323
  }
296
324
 
297
- /** @type {Message[]} */
298
- const messages = [
299
- ...(system ? [{ role: 'system', content: system }] : []),
300
- ...ts.map((t) => ({ role: t.fromBot ? 'assistant' : 'user', content: t.text })),
301
- { role: 'user', content }
302
- ];
303
-
304
- Object.assign(body, { messages });
305
-
306
325
  const apiUrl = `${this._openAiEndpoint}/chat/completions${this._apiKey ? '?api-version=2023-03-15-preview' : ''}`;
307
326
 
308
327
  this._log('#GPT request', body);
@@ -342,6 +361,37 @@ class ChatGpt {
342
361
  }
343
362
  }
344
363
 
364
+ /**
365
+ *
366
+ * @deprecated
367
+ * @param {string} content
368
+ * @param {string} [system]
369
+ * @param {Transcript[]} [transcript]
370
+ * @param {RequestOptions} [requestOptions]
371
+ * @param {string|Request} [user]
372
+ * @returns {Promise<ChatGPTChoice>}
373
+ */
374
+ async request (content, system = null, transcript = [], requestOptions = {}, user = null) {
375
+
376
+ /** @type {Message[]} */
377
+ const messages = [
378
+ ...(system ? [{ role: 'system', content: system }] : []),
379
+ ...transcript.map((t) => ({ role: t.fromBot ? 'assistant' : 'user', content: t.text })),
380
+ { role: 'user', content }
381
+ ];
382
+
383
+ let useUser;
384
+ if (typeof user === 'string') {
385
+ useUser = user;
386
+ } else if (user) {
387
+ useUser = `${user.pageId}|${user.senderId}`;
388
+ } else if (this._defaultUser) {
389
+ useUser = this._defaultUser;
390
+ }
391
+
392
+ return this._request(messages, requestOptions, useUser);
393
+ }
394
+
345
395
  /**
346
396
  *
347
397
  * @param {ChatGPTChoice} choice
package/src/LLM.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ const { PHONE_REGEX, EMAIL_REGEX } = require('./systemEntities/regexps');
7
+
8
+ /** @typedef {import('./Responder')} Responder */
9
+ /** @typedef {import('./Responder').Persona} Persona */
10
+ /** @typedef {import('./Router').BaseConfiguration} BaseConfiguration */
11
+ /** @typedef {import('./LLMSession').LLMMessage<any>} LLMMessage */
12
+ /** @typedef {import('./LLMSession').LLMRole} LLMRole */
13
+ /** @typedef {import('./LLMSession')} LLMSession */
14
+ /** @typedef {import('./transcript/transcriptFromHistory').Transcript} Transcript */
15
+
16
+ /**
17
+ * @callback LLMChatProviderPrompt
18
+ * @param {LLMMessage[]} prompt
19
+ * @param {LLMProviderOptions} [options]
20
+ * @returns {Promise<LLMMessage>}
21
+ */
22
+
23
+ /**
24
+ * @typedef {object} LLMProviderOptions
25
+ * @prop {string} [model]
26
+ */
27
+
28
+ /**
29
+ * @typedef {object} LLMChatProvider
30
+ * @prop {LLMChatProviderPrompt} requestChat
31
+ */
32
+
33
+ /** @typedef {import('node-fetch').default} Fetch */
34
+
35
+ /**
36
+ * @typedef {object} LLMConfiguration
37
+ * @prop {LLMChatProvider} provider
38
+ * @prop {string} [model]
39
+ * @prop {number} [transcriptLength=-5]
40
+ * @prop {'gpt'|string} [transcriptFlag]
41
+ * @prop {boolean} [transcriptAnonymize]
42
+ * @prop {Persona|string|null} [persona]
43
+ */
44
+
45
+ /**
46
+ * @typedef {object} AnonymizeRegexp
47
+ * @prop {string} [replacement]
48
+ * @prop {RegExp} regex
49
+ */
50
+
51
+ /**
52
+ * @class LLM
53
+ */
54
+ class LLM {
55
+
56
+ /** @type {LLMRole} */
57
+ static ROLE_USER = 'user';
58
+
59
+ /** @type {LLMRole} */
60
+ static ROLE_ASSISTANT = 'assistant';
61
+
62
+ /** @type {LLMRole} */
63
+ static ROLE_SYSTEM = 'system';
64
+
65
+ static GPT_FLAG = 'gpt';
66
+
67
+ /** @type {AnonymizeRegexp[]} */
68
+ static anonymizeRegexps = [
69
+ { replacement: '@PHONE', regex: new RegExp(PHONE_REGEX.source, 'g') },
70
+ { replacement: '@EMAIL', regex: new RegExp(EMAIL_REGEX.source, 'g') }
71
+ ];
72
+
73
+ /**
74
+ *
75
+ * @param {LLMConfiguration} configuration
76
+ */
77
+ constructor (configuration) {
78
+ const { provider, ...rest } = configuration;
79
+
80
+ this._configuration = {
81
+ transcriptFlag: 'gpt',
82
+ transcriptLength: 5,
83
+ provider: null,
84
+ ...rest
85
+ };
86
+
87
+ /** @type {LLMChatProvider} */
88
+ this._provider = provider;
89
+ }
90
+
91
+ /**
92
+ * @returns {Omit<LLMConfiguration, 'provider'>}
93
+ */
94
+ get configuration () {
95
+ return this._configuration;
96
+ }
97
+
98
+ /**
99
+ *
100
+ * @param {Transcript[]} chat
101
+ * @param {boolean} [transcriptAnonymize]
102
+ * @returns {LLMMessage[]}
103
+ */
104
+ static anonymizeTranscript (chat, transcriptAnonymize) {
105
+ return chat.map((c) => ({
106
+ role: c.fromBot ? LLM.ROLE_ASSISTANT : LLM.ROLE_USER,
107
+ content: transcriptAnonymize
108
+ ? LLM.anonymizeRegexps
109
+ .reduce((text, { replacement, regex }) => {
110
+ const replaced = text.replace(regex, replacement);
111
+ return replaced;
112
+ }, c.text)
113
+ : c.text
114
+ }));
115
+ }
116
+
117
+ /**
118
+ *
119
+ * @param {LLMSession} session
120
+ * @param {LLMProviderOptions} [options={}]
121
+ * @returns {Promise<LLMMessage>}
122
+ */
123
+ async generate (session, options = {}) {
124
+ /** @type {LLMProviderOptions} */
125
+ const opts = {
126
+ model: this._configuration.model,
127
+ ...options
128
+ };
129
+
130
+ const prompt = session.toArray();
131
+ const result = await this._provider.requestChat(prompt, opts);
132
+
133
+ return result;
134
+ }
135
+
136
+ /**
137
+ *
138
+ * @param {LLMMessage} result
139
+ * @returns {LLMMessage[]}
140
+ */
141
+ static toMessages (result) {
142
+ let filtered = result.content
143
+ .replace(/\n\n+/g, '\n')
144
+ .split(/\n+(?!-)/g)
145
+ .map((t) => t.trim())
146
+ .filter((t) => !!t);
147
+
148
+ if (result.finishReason === 'length' && filtered.length <= 0) {
149
+ filtered = filtered.slice(0, filtered.length - 1);
150
+ }
151
+
152
+ return filtered.map((content) => ({
153
+ content,
154
+ role: result.role
155
+ }));
156
+ }
157
+
158
+ }
159
+
160
+ module.exports = LLM;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ const LLM = require('./LLM');
7
+
8
+ /** @typedef {import('./LLM').LLMChatProvider} LLMChatProvider */
9
+ /** @typedef {import('./LLM').LLMMessage} LLMMessage */
10
+ /** @typedef {import('./LLM').LLMProviderOptions} LLMProviderOptions */
11
+
12
+ /**
13
+ * @class LLMMockProvider
14
+ * @implements {LLMChatProvider}
15
+ */
16
+ class LLMMockProvider {
17
+
18
+ static DEFAULT_MODEL = 'mockmodel';
19
+
20
+ constructor () {
21
+ this._index = 0;
22
+ this._sequence = [
23
+ 'lorem',
24
+ 'ipsum',
25
+ 'dolor',
26
+ 'sit',
27
+ 'amet'
28
+ ];
29
+ }
30
+
31
+ /**
32
+ * @param {LLMMessage[]} prompt
33
+ * @param {LLMProviderOptions} [options]
34
+ * @returns {Promise<LLMMessage>}
35
+ */
36
+ // eslint-disable-next-line no-unused-vars
37
+ async requestChat (prompt, options) {
38
+ if (prompt.length === 0) {
39
+ throw new Error('Empty prompt');
40
+ }
41
+ // const stats = prompt.reduce((o, m) => Object.assign(o, {
42
+ // [m.role]: (o[m.role] || 0) + 1
43
+ // }), { system: 0, assistant: 0, user: 0 });
44
+ //
45
+ // const statsText = JSON.stringify(stats)
46
+ // .replace(/"/g, '');
47
+ //
48
+ /// / const message = this._sequence[this._index];
49
+ /// / this._index = (this._index + 1) % this._sequence.length;
50
+ //
51
+ // return {
52
+ // role: LLM.ROLE_ASSISTANT,
53
+ // finishReason: 'length',
54
+ // eslint-disable-next-line max-len
55
+ // content: `${statsText} > ${LLMMockProvider.DEFAULT_MODEL}: ${prompt.map((m) => m.content).join(' ')}`
56
+ // };
57
+
58
+ return {
59
+ role: LLM.ROLE_ASSISTANT,
60
+ finishReason: 'length',
61
+ content: `${options.model || LLMMockProvider.DEFAULT_MODEL}:${prompt.map((m) => m.content).join(' ')}`
62
+ };
63
+ }
64
+
65
+ }
66
+
67
+ module.exports = LLMMockProvider;