wingbot 3.74.7 → 3.75.9-alpha.1

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/src/Responder.js CHANGED
@@ -45,6 +45,7 @@ const EXCEPTION_HOPCOUNT_THRESHOLD = 5;
45
45
  /** @typedef {import('./LLMSession').LLMMessageSrc} LLMMessageSrc */
46
46
  /** @typedef {import('./LLMSession').AsyncLLMMessage} AsyncLLMMessage */
47
47
  /** @typedef {import('./utils/stateData').IStateRequest} IStateRequest */
48
+ /** @typedef {import('./BuildRouter').BounceAllow} BounceAllow */
48
49
 
49
50
  /**
50
51
  * @enum {string} ExpectedInput
@@ -371,21 +372,32 @@ class Responder {
371
372
  /**
372
373
  *
373
374
  * @param {string} contextType
374
- * @returns {Promise<LLMSession>}
375
+ * @param {LLMCallPreset} [callPreset]
376
+ * @returns {LLMSession}
375
377
  */
376
- async llmSession (contextType = this.LLM_CTX_DEFAULT) {
378
+ llmSession (contextType = this.LLM_CTX_DEFAULT, callPreset = undefined) {
377
379
  const system = this._getSystemMessagesForType(contextType);
378
380
 
379
381
  const filters = this._filtersForContext(contextType);
380
- return new LLMSession(this.llm, [system], this._llmSend.bind(this), filters);
382
+ return new LLMSession(this.llm, [system], {
383
+ onSend: this._llmSend.bind(this),
384
+ filters,
385
+ preset: callPreset,
386
+ res: this
387
+ });
381
388
  }
382
389
 
383
390
  /**
384
391
  *
392
+ * @param {LLMCallPreset} callPreset
385
393
  * @returns {LLMSession}
386
394
  */
387
- llmSessionEmpty () {
388
- return new LLMSession(this.llm, [], this._llmSend.bind(this));
395
+ llmSessionEmpty (callPreset) {
396
+ return new LLMSession(this.llm, [], {
397
+ onSend: this._llmSend.bind(this),
398
+ preset: callPreset,
399
+ res: this
400
+ });
389
401
  }
390
402
 
391
403
  /**
@@ -493,7 +505,12 @@ class Responder {
493
505
  return new LLMSession(this.llm, [
494
506
  this._getSystemMessagesForType(contextType),
495
507
  this._getTranscriptMessages(transcriptLength, transcriptFlag, transcriptAnonymize)
496
- ], this._llmSend.bind(this), filters);
508
+ ], {
509
+ onSend: this._llmSend.bind(this),
510
+ filters,
511
+ preset: callPreset,
512
+ res: this
513
+ });
497
514
  }
498
515
 
499
516
  async _getTranscriptMessages (transcriptLength, transcriptFlag, transcriptAnonymize) {
@@ -524,6 +541,7 @@ class Responder {
524
541
  _llmSend (messages, quickReplies) {
525
542
  this.setFlag(LLM.GPT_FLAG);
526
543
 
544
+ // @ts-ignore
527
545
  const { persona } = this.llm.configuration;
528
546
 
529
547
  if (typeof persona === 'string') {
@@ -1183,9 +1201,10 @@ class Responder {
1183
1201
  *
1184
1202
  * @param {string} action - desired action
1185
1203
  * @param {object} data - desired action data
1204
+ * @param {BounceAllow} bounce
1186
1205
  * @returns {this}
1187
1206
  */
1188
- expected (action, data = {}) {
1207
+ expected (action, data = {}, bounce = null) {
1189
1208
  if (!action) {
1190
1209
  return this.setState({ _expected: null });
1191
1210
  }
@@ -1193,7 +1212,8 @@ class Responder {
1193
1212
  return this.setState({
1194
1213
  _expected: {
1195
1214
  action: makeAbsolute(action, this.path),
1196
- data
1215
+ data,
1216
+ bounce
1197
1217
  }
1198
1218
  });
1199
1219
  }
package/src/Router.js CHANGED
@@ -6,8 +6,11 @@
6
6
  const { pathToRegexp } = require('path-to-regexp');
7
7
  const ReducerWrapper = require('./ReducerWrapper');
8
8
  const { makeAbsolute } = require('./utils');
9
+ const GlobalIntents = require('./GlobalIntents');
9
10
 
10
11
  /** @typedef {import('./Responder')} Responder */
12
+ /** @typedef {import('./LLMDispatcher').Routing} Routing */
13
+ /** @typedef {import('./GlobalIntents').GlobalIntentResolved} GlobalIntentResolved */
11
14
 
12
15
  /**
13
16
  * @template {object} [S=object]
@@ -52,7 +55,7 @@ function defaultPathContext () {
52
55
  * @param {Responder} [res]
53
56
  * @param {PostBack} [postBack]
54
57
  * @param {string} [path]
55
- * @returns {Promise<RoutingInstruction>}
58
+ * @returns {Promise<RoutingInstruction>|RoutingInstruction}
56
59
  */
57
60
 
58
61
  /**
@@ -93,6 +96,17 @@ function defaultPathContext () {
93
96
  * @prop {string} [gaApiSecret]
94
97
  */
95
98
 
99
+ /**
100
+ * @template {BaseConfiguration} [C=object]
101
+ * @typedef {object} ResolvedReducer
102
+ * @prop {string} resolverPath
103
+ * @prop {boolean} isReducer
104
+ * @prop {Function} reduce
105
+ * @prop {Map<number, GlobalIntentResolved>} globalIntents
106
+ * @prop {object} globalIntentsMeta
107
+ * @prop {BaseConfiguration} configuration
108
+ */
109
+
96
110
  /**
97
111
  * Cascading router
98
112
  *
@@ -119,8 +133,6 @@ class Router extends ReducerWrapper {
119
133
  : configuration || {};
120
134
 
121
135
  this._routes = [];
122
-
123
- this.globalIntents = new Map();
124
136
  }
125
137
 
126
138
  /**
@@ -202,29 +214,7 @@ class Router extends ReducerWrapper {
202
214
  path: pathContext.path
203
215
  });
204
216
 
205
- reducers.forEach(({ globalIntents }) => {
206
- for (const gi of globalIntents.values()) {
207
- const {
208
- id, matcher, action: intentPath, local, title,
209
- entitiesSetState = {}, usedEntities, meta = {}
210
- } = gi;
211
- const action = intentPath === '/*'
212
- ? pathContext.path
213
- : `${pathContext.path}${intentPath}`.replace(/^\/\*/, '');
214
-
215
- this.globalIntents.set(id, {
216
- id,
217
- matcher,
218
- usedEntities,
219
- entitiesSetState,
220
- action,
221
- localPath: pathContext.path,
222
- local,
223
- title,
224
- meta: { ...pathContext.globalIntentsMeta, ...meta }
225
- });
226
- }
227
- });
217
+ GlobalIntents.mergeGlobalIntents(reducers, this.globalIntents, pathContext);
228
218
 
229
219
  return this;
230
220
  }
@@ -282,6 +272,11 @@ class Router extends ReducerWrapper {
282
272
  });
283
273
  }
284
274
 
275
+ /**
276
+ * @param {*} reducer
277
+ * @param {string} thePath
278
+ * @returns {ResolvedReducer}
279
+ */
285
280
  _createReducer (reducer, thePath) {
286
281
  let resolverPath = thePath;
287
282
  let reduce = reducer;
package/src/Tester.js CHANGED
@@ -18,13 +18,15 @@ const ResponseAssert = require('./testTools/ResponseAssert');
18
18
  const Router = require('./Router'); // eslint-disable-line no-unused-vars
19
19
  const ReducerWrapper = require('./ReducerWrapper'); // eslint-disable-line no-unused-vars
20
20
  const { FEATURE_TEXT } = require('./features');
21
- const LLMMockProvider = require('./LLMMockProvider');
22
21
  const PromptAssert = require('./testTools/PromptAssert');
23
22
 
24
23
  /** @typedef {import('./Processor').ProcessorOptions<Router>} ProcessorOptions */
25
24
  /** @typedef {import('./LLM').PromptInfo} PromptInfo */
26
25
  /** @typedef {import('./LLM').LLMRole} LLMRole */
27
26
  /** @typedef {import('./LLM').LLMMessage} LLMMessage */
27
+ /** @typedef {import('./LLM').LLMPresetName} LLMPresetName */
28
+ /** @typedef {import('./LLMMockProvider').LLMMockResponse} LLMMockResponse */
29
+ /** @typedef {import('./LLMMockProvider').LLMRoutingResponse} LLMRoutingResponse */
28
30
 
29
31
  /**
30
32
  * Utility for testing requests
@@ -106,7 +108,6 @@ class Tester {
106
108
  // @ts-ignore
107
109
  loadUsers: false,
108
110
  llm: {
109
- provider: new LLMMockProvider(),
110
111
  ...processorOptions.llm
111
112
  },
112
113
  ...processorOptions
@@ -497,6 +498,46 @@ class Tester {
497
498
  return this.processMessage(Request.intent(this.senderId, intent, score));
498
499
  }
499
500
 
501
+ /**
502
+ *
503
+ * @param {string} text
504
+ * @param {string|object} routingMock
505
+ * @param {(string|object)[]} [defaultMocks]
506
+ * @returns {Promise}
507
+ */
508
+ llm (text, routingMock = text, ...defaultMocks) {
509
+ const routingMocks = this._makeLLMMocks('routing', [
510
+ typeof routingMock === 'string' ? { action: routingMock } : routingMock
511
+ ]);
512
+ const llmMocks = this._makeLLMMocks('default', defaultMocks);
513
+ const req = Request.llm(this.senderId, text, [...routingMocks, ...llmMocks]);
514
+ return this.processMessage(req);
515
+ }
516
+
517
+ /**
518
+ *
519
+ * @param {LLMPresetName} preset
520
+ * @param {(string|object)[]} mocks
521
+ * @returns {LLMMockResponse[]}
522
+ */
523
+ _makeLLMMocks (preset, mocks) {
524
+ return mocks.map((content) => ({
525
+ preset, content
526
+ }));
527
+ }
528
+
529
+ // /**
530
+ // *
531
+ // * @param {string} text
532
+ // * @param {(string|object)[]} [defaultMocks]
533
+ // * @returns {Promise}
534
+ // */
535
+ // llm (text, ...defaultMocks) {
536
+ // const llmMocks = this._makeLLMMocks('default', defaultMocks);
537
+ // const req = Request.llm(this.senderId, text, llmMocks);
538
+ // return this.processMessage(req);
539
+ // }
540
+
500
541
  /**
501
542
  * Makes recognised AI intent request with entity
502
543
  *
package/src/prompt.js ADDED
@@ -0,0 +1,138 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ const hbs = require('handlebars');
7
+ const stateData = require('./utils/stateData');
8
+
9
+ /** @typedef {import('./Request')} Request */
10
+ /** @typedef {import('./Responder')} Responder */
11
+
12
+ /**
13
+ * @callback Renderer
14
+ * @param {object|Request} req
15
+ * @param {Responder} [res]
16
+ * @returns {Promise<string>}
17
+ */
18
+
19
+ /** @typedef {Renderer} Prompt */
20
+
21
+ /**
22
+ * @typedef {string|number} TemplateValue
23
+ */
24
+
25
+ /**
26
+ * @typedef {TemplateValue|object} ReturnValue
27
+ */
28
+
29
+ /**
30
+ * @callback ExecutableInput
31
+ * @param {object} data
32
+ * @returns {Promise<ReturnValue>|ReturnValue}
33
+ */
34
+
35
+ /**
36
+ * @typedef {ExecutableInput|TemplateValue|object} Input
37
+ */
38
+
39
+ let uq = 0;
40
+
41
+ const LEFT_HBS = /\{\{[^}]*$/;
42
+ const RIGHT_HBS = /^[^{]*\}\}/;
43
+
44
+ const insideHbs = (left, right) => LEFT_HBS.exec(left) && RIGHT_HBS.exec(right);
45
+
46
+ /**
47
+ *
48
+ * @param {TemplateStringsArray} strings
49
+ * @param {...Input} args
50
+ * @returns {Prompt}
51
+ */
52
+ function prompt (strings, ...args) {
53
+ const prefix = `_t_${uq++}_`;
54
+ const argKey = (n) => `${prefix}${n}`;
55
+
56
+ const inputData = {};
57
+
58
+ let executeOnce = [];
59
+ const executeRepeatedly = [];
60
+
61
+ let result = strings[0];
62
+ for (let i = 0, l = args.length; i < l; i++) {
63
+ const key = argKey(i);
64
+ const arg = args[i];
65
+ const isScalar = typeof arg === 'string'
66
+ || typeof arg === 'number';
67
+
68
+ if (!isScalar) {
69
+ if (typeof arg !== 'function') {
70
+ inputData[key] = arg;
71
+ } else if (arg.length) {
72
+ executeRepeatedly.push([key, arg]);
73
+ } else {
74
+ executeOnce.push([key, arg]);
75
+ }
76
+ }
77
+
78
+ if (insideHbs(strings[0], strings[i + 1])) {
79
+ if (isScalar) {
80
+ result += (typeof arg === 'string' ? `'${arg.replace(/'/g, '\\\'')}'` : arg)
81
+ + strings[i + 1];
82
+ } else {
83
+ result += key + strings[i + 1];
84
+ }
85
+ } else if (isScalar) {
86
+ result += `${arg}${strings[i + 1]}`;
87
+ } else {
88
+ result += `{{{${key}}}}${strings[i + 1]}`;
89
+ }
90
+ }
91
+ const precompiled = hbs.compile(result);
92
+ let oncePromise = null;
93
+
94
+ const renderer = async (req, res = null) => {
95
+ const reqIsRequest = 'action' in req && typeof req.action === 'function';
96
+ const data = {
97
+ ...(reqIsRequest ? stateData(req, res) : req),
98
+ ...inputData
99
+ };
100
+
101
+ if (executeOnce.length || executeRepeatedly.length) {
102
+ if (!oncePromise) {
103
+ oncePromise = executeOnce.map(async ([key, val]) => {
104
+ const useVal = await val();
105
+ inputData[key] = useVal;
106
+ return [key, useVal];
107
+ });
108
+ }
109
+
110
+ const resulted = await Promise.all([
111
+ ...oncePromise,
112
+ ...executeRepeatedly.map(async ([key, val]) => {
113
+ const useVal = await val(data);
114
+ return [key, useVal];
115
+ })
116
+ ])
117
+ .then((r) => {
118
+ executeOnce = [];
119
+ return r;
120
+ })
121
+ .finally(() => {
122
+ oncePromise = null;
123
+ });
124
+
125
+ Object.assign(data, Object.fromEntries(resulted));
126
+ }
127
+
128
+ return precompiled(data);
129
+ };
130
+
131
+ Object.assign(renderer, {
132
+ toString: () => result
133
+ });
134
+
135
+ return renderer;
136
+ }
137
+
138
+ module.exports = prompt;
@@ -8,8 +8,10 @@
8
8
  */
9
9
  const BOUNCE_ALLOW = {
10
10
  NOT_ALLOWED: null,
11
- ALLOWED_TO_FAQ: 'faq',
12
- ALLOWED: 'allow'
11
+ ALLOWED_TO_FAQ: 'faq', // let it deprecate
12
+ ALLOWED: 'allow' // when something's detected, allow move, otherwise?
13
+
14
+ // lets deal with implicit expected - put it into the router above (enabled in specific context)
13
15
  };
14
16
 
15
17
  /**
@@ -5,19 +5,20 @@
5
5
 
6
6
  const Router = require('../Router');
7
7
 
8
- function expected ({ path, attachedRouter }, { isLastIndex }) {
8
+ function expected ({ path, attachedRouter }, { isLastIndex, bounceAllowedTo }) {
9
9
 
10
10
  if (attachedRouter) {
11
11
  return (req, res, postBack) => postBack(path, {
12
12
  _useExpected: {
13
13
  action: res.toAbsoluteAction(path),
14
- data: {}
14
+ data: {},
15
+ bounceAllowedTo
15
16
  }
16
17
  }, true);
17
18
  }
18
19
 
19
20
  return (req, res) => {
20
- res.expected(path);
21
+ res.expected(path, {}, bounceAllowedTo);
21
22
 
22
23
  return isLastIndex ? Router.END : Router.CONTINUE;
23
24
  };
@@ -39,6 +39,7 @@ async function routeToEvents (pageId, senderId, state, resolvers) {
39
39
 
40
40
  const req = new Request(event, state, pageId);
41
41
  const res = new Responder(senderId, returnSender);
42
+ await req.dispatcher.dispatch(req, res);
42
43
 
43
44
  Object.assign(res, {
44
45
  subscribe (tag) { subscribe.push(tag); },
@@ -41,7 +41,7 @@ const { iterateThroughWords } = require('../utils/ai');
41
41
  /**
42
42
  * @typedef {object} Intent
43
43
  * @prop {string} intent
44
- * @prop {number} score
44
+ * @prop {number} [score]
45
45
  * @prop {Entity[]} [entities]
46
46
  */
47
47
 
@@ -1,8 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npx mocha:*)",
5
- "Bash(npx tsc *)"
6
- ]
7
- }
8
- }