wingbot 3.74.8 → 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/index.js +6 -1
- package/jsconfig.json +2 -1
- package/package.json +1 -1
- package/src/BuildRouter.js +43 -7
- package/src/GlobalIntents.js +198 -0
- package/src/LLM.js +19 -3
- package/src/LLMDispatcher.js +508 -0
- package/src/LLMMockProvider.js +44 -1
- package/src/LLMRouter.js +325 -0
- package/src/LLMSession.js +85 -14
- package/src/Processor.js +18 -14
- package/src/ReducerWrapper.js +24 -0
- package/src/Request.js +88 -231
- package/src/Responder.js +28 -8
- package/src/Router.js +21 -26
- package/src/Tester.js +43 -2
- package/src/prompt.js +138 -0
- package/src/resolvers/bounce.js +4 -2
- package/src/resolvers/expected.js +4 -3
- package/src/tools/routeToEvents.js +1 -0
- package/src/wingbot/CustomEntityDetectionModel.js +1 -1
- package/.claude/settings.local.json +0 -8
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
|
-
* @
|
|
375
|
+
* @param {LLMCallPreset} [callPreset]
|
|
376
|
+
* @returns {LLMSession}
|
|
375
377
|
*/
|
|
376
|
-
|
|
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],
|
|
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, [],
|
|
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
|
-
],
|
|
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
|
-
|
|
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;
|
package/src/resolvers/bounce.js
CHANGED
|
@@ -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); },
|