@miso.ai/client-sdk-ui 1.11.0-beta.1 → 1.11.0-beta.11
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/dist/cjs/actor/data.js +6 -7
- package/dist/cjs/actor/feedback.js +6 -39
- package/dist/cjs/actor/fields.js +14 -6
- package/dist/cjs/actor/hub.js +1 -2
- package/dist/cjs/actor/index.js +0 -7
- package/dist/cjs/actor/interactions.js +4 -15
- package/dist/cjs/actor/sessions.js +2 -33
- package/dist/cjs/actor/tracker.js +25 -26
- package/dist/cjs/actor/utils.js +0 -49
- package/dist/cjs/actor/view.js +40 -40
- package/dist/cjs/actor/views.js +32 -8
- package/dist/cjs/asset/svgs.js +18 -8
- package/dist/cjs/constants.js +18 -19
- package/dist/cjs/defaults/hybrid-search/answer-box.js +19 -3
- package/dist/cjs/defaults/hybrid-search/phrases.js +5 -5
- package/dist/cjs/defaults/hybrid-search/templates.js +37 -9
- package/dist/cjs/element/role/index.js +12 -5
- package/dist/cjs/element/role/{miso-hits.js → miso-more.js} +4 -4
- package/dist/cjs/element/role/miso-total.js +20 -0
- package/dist/cjs/layout/affiliation/affiliation.js +0 -3
- package/dist/cjs/layout/banner/banner.js +0 -4
- package/dist/cjs/layout/button/more-button.js +73 -0
- package/dist/cjs/layout/container/container.js +0 -3
- package/dist/cjs/layout/error/error.js +0 -4
- package/dist/cjs/layout/index.js +7 -0
- package/dist/cjs/layout/input/facets.js +5 -5
- package/dist/cjs/layout/input/option-list.js +0 -4
- package/dist/cjs/layout/input/search-box.js +35 -17
- package/dist/cjs/layout/list/cards.js +0 -3
- package/dist/cjs/layout/list/carousel.js +0 -3
- package/dist/cjs/layout/list/collection.js +22 -7
- package/dist/cjs/layout/list/list.js +0 -3
- package/dist/cjs/layout/radio/feedback.js +0 -3
- package/dist/cjs/layout/radio/radio.js +0 -4
- package/dist/cjs/layout/raf.js +4 -2
- package/dist/cjs/layout/text/text.js +0 -4
- package/dist/cjs/layout/text/typewriter/index.js +0 -3
- package/dist/cjs/layout/triggerable.js +79 -0
- package/dist/cjs/util/states.js +0 -15
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/answer-based.js +109 -111
- package/dist/cjs/workflow/ask.js +35 -27
- package/dist/cjs/workflow/asks.js +1 -1
- package/dist/cjs/workflow/autocompletable.js +33 -0
- package/dist/cjs/workflow/autocomplete.js +122 -0
- package/dist/cjs/workflow/base.js +169 -102
- package/dist/cjs/workflow/explore.js +26 -19
- package/dist/cjs/workflow/hybrid-search-answer.js +99 -0
- package/dist/cjs/workflow/hybrid-search-results.js +66 -0
- package/dist/cjs/workflow/hybrid-search-views.js +122 -0
- package/dist/cjs/workflow/hybrid-search.js +98 -103
- package/dist/cjs/workflow/options.js +32 -17
- package/dist/cjs/workflow/processors.js +191 -17
- package/dist/cjs/workflow/recommendation.js +36 -49
- package/dist/cjs/workflow/search-based.js +228 -0
- package/dist/cjs/workflow/search.js +21 -68
- package/package.json +2 -2
- package/src/actor/data.js +2 -4
- package/src/actor/feedback.js +6 -23
- package/src/actor/fields.js +14 -6
- package/src/actor/hub.js +1 -2
- package/src/actor/index.js +0 -1
- package/src/actor/interactions.js +4 -10
- package/src/actor/sessions.js +3 -30
- package/src/actor/tracker.js +25 -19
- package/src/actor/utils.js +0 -47
- package/src/actor/view.js +27 -15
- package/src/actor/views.js +36 -8
- package/src/asset/svgs.js +19 -7
- package/src/constants.js +25 -16
- package/src/defaults/hybrid-search/answer-box.js +17 -5
- package/src/defaults/hybrid-search/phrases.js +4 -4
- package/src/defaults/hybrid-search/templates.js +25 -9
- package/src/element/role/index.js +2 -1
- package/src/element/role/{miso-hits.js → miso-more.js} +3 -3
- package/src/element/role/miso-total.js +16 -0
- package/src/layout/affiliation/affiliation.js +1 -5
- package/src/layout/banner/banner.js +0 -5
- package/src/layout/button/more-button.js +69 -0
- package/src/layout/container/container.js +1 -5
- package/src/layout/error/error.js +0 -5
- package/src/layout/index.js +2 -1
- package/src/layout/input/facets.js +5 -6
- package/src/layout/input/option-list.js +0 -5
- package/src/layout/input/search-box.js +29 -19
- package/src/layout/list/cards.js +0 -4
- package/src/layout/list/carousel.js +0 -4
- package/src/layout/list/collection.js +21 -9
- package/src/layout/list/list.js +0 -4
- package/src/layout/radio/feedback.js +0 -4
- package/src/layout/radio/radio.js +0 -5
- package/src/layout/raf.js +2 -2
- package/src/layout/text/text.js +0 -5
- package/src/layout/text/typewriter/index.js +1 -5
- package/src/layout/trackable.js +1 -1
- package/src/layout/triggerable.js +76 -0
- package/src/util/states.js +0 -14
- package/src/version.js +1 -1
- package/src/workflow/answer-based.js +101 -77
- package/src/workflow/ask.js +33 -25
- package/src/workflow/asks.js +1 -1
- package/src/workflow/autocompletable.js +29 -0
- package/src/workflow/autocomplete.js +113 -0
- package/src/workflow/base.js +147 -93
- package/src/workflow/explore.js +23 -8
- package/src/workflow/hybrid-search-answer.js +92 -0
- package/src/workflow/hybrid-search-results.js +62 -0
- package/src/workflow/hybrid-search-views.js +124 -0
- package/src/workflow/hybrid-search.js +102 -73
- package/src/workflow/options.js +26 -11
- package/src/workflow/processors.js +169 -14
- package/src/workflow/recommendation.js +32 -33
- package/src/workflow/search-based.js +222 -0
- package/src/workflow/search.js +21 -65
- package/dist/cjs/actor/autocomplete.js +0 -160
- package/dist/cjs/workflow/utils.js +0 -42
- package/src/actor/autocomplete.js +0 -133
- package/src/workflow/utils.js +0 -29
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { API } from '@miso.ai/commons';
|
|
2
2
|
import Workflow from './base.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import { fields, FeedbackActor, AutocompleteActor } from '../actor/index.js';
|
|
6
|
-
import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE, DATA_ASPECT } from '../constants.js';
|
|
3
|
+
import { fields, FeedbackActor } from '../actor/index.js';
|
|
4
|
+
import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
|
|
7
5
|
import { SearchBoxLayout, TextLayout, ListLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
|
|
8
6
|
import { processData as processAffiliationData } from '../affiliation/index.js';
|
|
9
|
-
import {
|
|
7
|
+
import { mergeRolesOptions } from './options.js';
|
|
8
|
+
import { writeAnswerStageToMeta, mergeInteraction } from './processors.js';
|
|
10
9
|
|
|
11
10
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
11
|
+
...Workflow.DEFAULT_API_OPTIONS,
|
|
12
12
|
group: API.GROUP.ASK,
|
|
13
13
|
payload: {
|
|
14
|
+
...Workflow.DEFAULT_API_OPTIONS.payload,
|
|
14
15
|
source_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at'],
|
|
15
16
|
cite_link: 1,
|
|
16
17
|
cite_start: '[',
|
|
@@ -27,6 +28,7 @@ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
|
27
28
|
});
|
|
28
29
|
|
|
29
30
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
31
|
+
...Workflow.DEFAULT_LAYOUTS,
|
|
30
32
|
[ROLE.QUERY]: [SearchBoxLayout.type, { placeholder: 'Ask a question' }],
|
|
31
33
|
[ROLE.QUESTION]: [TextLayout.type, { tag: 'h2' }],
|
|
32
34
|
[ROLE.ANSWER]: TypewriterLayout.type,
|
|
@@ -36,17 +38,25 @@ const DEFAULT_LAYOUTS = Object.freeze({
|
|
|
36
38
|
});
|
|
37
39
|
|
|
38
40
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
41
|
+
...Workflow.DEFAULT_TRACKERS,
|
|
39
42
|
[ROLE.SOURCES]: {},
|
|
40
43
|
[ROLE.AFFILIATION]: {},
|
|
44
|
+
[ROLE.PRODUCTS]: {},
|
|
41
45
|
});
|
|
42
46
|
|
|
43
47
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
48
|
+
...Workflow.DEFAULT_OPTIONS,
|
|
44
49
|
api: DEFAULT_API_OPTIONS,
|
|
45
50
|
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
46
51
|
layouts: DEFAULT_LAYOUTS,
|
|
47
52
|
trackers: DEFAULT_TRACKERS,
|
|
48
53
|
});
|
|
49
54
|
|
|
55
|
+
const ROLES_OPTIONS = mergeRolesOptions(Workflow.ROLES_OPTIONS, {
|
|
56
|
+
main: ROLE.ANSWER,
|
|
57
|
+
members: Object.keys(DEFAULT_LAYOUTS),
|
|
58
|
+
});
|
|
59
|
+
|
|
50
60
|
export default class AnswerBasedWorkflow extends Workflow {
|
|
51
61
|
|
|
52
62
|
// constructor //
|
|
@@ -59,12 +69,6 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
59
69
|
_initActors(args) {
|
|
60
70
|
super._initActors(args);
|
|
61
71
|
this._feedback = new FeedbackActor(this._hub);
|
|
62
|
-
/*
|
|
63
|
-
this._autocomplete = new AutocompleteActor(this._hub, {
|
|
64
|
-
source: sources.api(this._client),
|
|
65
|
-
options: this._options,
|
|
66
|
-
});
|
|
67
|
-
*/
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
_initSubscriptions(args) {
|
|
@@ -72,30 +76,49 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
72
76
|
this._unsubscribes = [
|
|
73
77
|
...this._unsubscribes,
|
|
74
78
|
this._hub.on(fields.query(), args => this._query(args)),
|
|
75
|
-
this._hub.on(fields.view(ROLE.ANSWER), data => this._onAnswerViewUpdate(data)),
|
|
76
79
|
this._views.get(ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event)),
|
|
77
80
|
];
|
|
78
81
|
}
|
|
79
82
|
|
|
83
|
+
// configuration //
|
|
84
|
+
useLink(fn) {
|
|
85
|
+
if (typeof fn !== 'function' && fn !== false) {
|
|
86
|
+
throw new Error('useLink(fn) expects fn to be a function or false');
|
|
87
|
+
}
|
|
88
|
+
this._linkFn = fn;
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
80
92
|
// lifecycle //
|
|
81
93
|
restart() {
|
|
82
94
|
// clear question id from previous session
|
|
83
95
|
if (this._questionId) {
|
|
84
96
|
this._questionId = undefined;
|
|
85
97
|
}
|
|
86
|
-
// interrupt event
|
|
87
|
-
// TODO: move to workflow base
|
|
88
|
-
const { session, status, ongoing } = this._hub.states[fields.view(ROLE.ANSWER)] || {};
|
|
89
|
-
if (session && status !== STATUS.INITIAL && (status !== STATUS.READY || ongoing)) {
|
|
90
|
-
// it's interrupted by a new question
|
|
91
|
-
const state = Object.freeze({ session, status, ongoing });
|
|
92
|
-
this._emit('interrupt', state);
|
|
93
|
-
this._emit('finally', state);
|
|
94
|
-
}
|
|
95
98
|
// restart
|
|
96
99
|
super.restart();
|
|
97
100
|
}
|
|
98
101
|
|
|
102
|
+
_emitInterruptEventIfNecessary() {
|
|
103
|
+
const state = this._hub.states[fields.view(this._roles.main)] || {};
|
|
104
|
+
if (state.session && state.status !== STATUS.INITIAL && (state.status !== STATUS.READY || state.ongoing)) {
|
|
105
|
+
// it's interrupted by a new question
|
|
106
|
+
this._emitLifecycleEvent('interrupt', state);
|
|
107
|
+
this._emitLifecycleEvent('finally', state);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_onMainViewUpdate(state) {
|
|
112
|
+
const { status } = state;
|
|
113
|
+
const done = status === STATUS.READY && !state.ongoing;
|
|
114
|
+
const erroneous = status === STATUS.ERRONEOUS;
|
|
115
|
+
const eventName = done ? 'done' : erroneous ? 'error' : status;
|
|
116
|
+
this._emitLifecycleEvent(eventName, state);
|
|
117
|
+
if (done || erroneous) {
|
|
118
|
+
this._emitLifecycleEvent('finally', state);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
99
122
|
// properties //
|
|
100
123
|
get questionId() {
|
|
101
124
|
return this._questionId;
|
|
@@ -130,53 +153,61 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
130
153
|
}
|
|
131
154
|
|
|
132
155
|
_query(args = {}) {
|
|
156
|
+
if (this._linkFn) {
|
|
157
|
+
this._submit(args);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
133
160
|
// start a new session
|
|
134
161
|
this.restart();
|
|
135
162
|
|
|
136
|
-
// keep track of question source on this session
|
|
137
|
-
|
|
138
|
-
session.meta.question_source = args.questionSource || ORGANIC_QUESTION_SOURCE; // might be null, not undefined
|
|
163
|
+
// keep track of question source on this session, for suggested questions interactions
|
|
164
|
+
this._writeQuestionSourceToSession(args);
|
|
139
165
|
|
|
140
166
|
// build payload and trigger request
|
|
141
167
|
const payload = this._buildPayload(args);
|
|
142
|
-
|
|
143
|
-
this._request(event);
|
|
168
|
+
this._request({ payload });
|
|
144
169
|
}
|
|
145
170
|
|
|
146
|
-
|
|
147
|
-
this.
|
|
171
|
+
_submit(args) {
|
|
172
|
+
if (!this._linkFn) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// TODO: we want a submit event, but only with linkFn
|
|
176
|
+
const url = this._linkFn(args.q);
|
|
177
|
+
window.open(url, '_blank');
|
|
148
178
|
}
|
|
149
179
|
|
|
150
|
-
|
|
151
|
-
|
|
180
|
+
_writeQuestionSourceToSession(args) {
|
|
181
|
+
this.session.meta.question_source = args.qs || ORGANIC_QUESTION_SOURCE; // might be null, not undefined
|
|
152
182
|
}
|
|
153
183
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
updateCompletions(event) {
|
|
157
|
-
// TODO: verify
|
|
158
|
-
this._hub.update(fields.data(DATA_ASPECT.AUTOCOMPLETE), {
|
|
159
|
-
...event,
|
|
160
|
-
source: 'manual',
|
|
161
|
-
});
|
|
162
|
-
return this;
|
|
184
|
+
_buildPayload() {
|
|
185
|
+
throw new Error(`Not implemented`);
|
|
163
186
|
}
|
|
164
|
-
*/
|
|
165
187
|
|
|
166
188
|
// data //
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
189
|
+
_updateData(data) {
|
|
190
|
+
// if it's the head response, write question id and return
|
|
191
|
+
if (data.value && !data.value.answer_stage) {
|
|
192
|
+
this._handleHeadResponse(data);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
super._updateData(data);
|
|
172
196
|
|
|
173
197
|
// update URL if autoQuery.updateUrl is not false
|
|
174
198
|
this._updateUrlIfNecessary(data);
|
|
199
|
+
}
|
|
175
200
|
|
|
176
|
-
|
|
177
|
-
|
|
201
|
+
_handleHeadResponse(data) {
|
|
202
|
+
// capture question ID and register at context
|
|
203
|
+
this._writeQuestionIdFromData(data);
|
|
204
|
+
}
|
|
178
205
|
|
|
179
|
-
|
|
206
|
+
_defaultProcessData(data) {
|
|
207
|
+
data = super._defaultProcessData(data);
|
|
208
|
+
data = processAffiliationData(data);
|
|
209
|
+
data = writeAnswerStageToMeta(data);
|
|
210
|
+
return data;
|
|
180
211
|
}
|
|
181
212
|
|
|
182
213
|
_writeQuestionIdFromData({ value }) {
|
|
@@ -204,38 +235,32 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
204
235
|
}
|
|
205
236
|
|
|
206
237
|
// interactions //
|
|
207
|
-
|
|
208
|
-
payload = super.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
238
|
+
_defaultProcessInteraction(payload, args) {
|
|
239
|
+
payload = super._defaultProcessInteraction(payload, args);
|
|
240
|
+
payload = this._writeAskPropertiesToInteraction(payload, args);
|
|
241
|
+
return payload;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
_writeAskPropertiesToInteraction(payload = {}, args) {
|
|
245
|
+
const question_source = this._getQuestionSourceFromViewState(args);
|
|
246
|
+
const question_id = this.questionId;
|
|
247
|
+
return mergeInteraction(payload, {
|
|
214
248
|
context: {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
question_id
|
|
218
|
-
|
|
219
|
-
}),
|
|
249
|
+
custom_context: {
|
|
250
|
+
question_source,
|
|
251
|
+
question_id,
|
|
252
|
+
},
|
|
220
253
|
},
|
|
221
|
-
};
|
|
254
|
+
});
|
|
222
255
|
}
|
|
223
256
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
const done = status === STATUS.READY && !ongoing;
|
|
230
|
-
const erroneous = status === STATUS.ERRONEOUS;
|
|
231
|
-
const eventName = done ? 'done' : erroneous ? 'error' : status;
|
|
232
|
-
const state = Object.freeze({ session, status, ongoing });
|
|
233
|
-
this._emit(eventName, state);
|
|
234
|
-
if (done || erroneous) {
|
|
235
|
-
this._emit('finally', state);
|
|
236
|
-
}
|
|
257
|
+
_getQuestionSourceFromViewState(args) {
|
|
258
|
+
const { request } = this._hub.states[fields.view(args.role)] || {};
|
|
259
|
+
const { payload } = request || {};
|
|
260
|
+
return (payload && payload._meta && payload._meta.question_source) || undefined;
|
|
237
261
|
}
|
|
238
262
|
|
|
263
|
+
// handlers //
|
|
239
264
|
_onCitationClick({ index }) {
|
|
240
265
|
const { value } = this.states[fields.data()] || {};
|
|
241
266
|
const { sources } = value || {};
|
|
@@ -269,12 +294,11 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
269
294
|
|
|
270
295
|
}
|
|
271
296
|
|
|
272
|
-
// makeConfigurable(AnswerBasedWorkflow.prototype, ['autocomplete']);
|
|
273
|
-
|
|
274
297
|
Object.assign(AnswerBasedWorkflow, {
|
|
275
298
|
DEFAULT_API_OPTIONS,
|
|
276
299
|
DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
277
300
|
DEFAULT_LAYOUTS,
|
|
278
301
|
DEFAULT_TRACKERS,
|
|
279
302
|
DEFAULT_OPTIONS,
|
|
303
|
+
ROLES_OPTIONS,
|
|
280
304
|
});
|
package/src/workflow/ask.js
CHANGED
|
@@ -2,7 +2,8 @@ import { defineValues, trimObj, API } from '@miso.ai/commons';
|
|
|
2
2
|
import AnswerBasedWorkflow from './answer-based.js';
|
|
3
3
|
import { fields } from '../actor/index.js';
|
|
4
4
|
import { ROLE, ORGANIC_QUESTION_SOURCE } from '../constants.js';
|
|
5
|
-
import { OptionListLayout, ListLayout,
|
|
5
|
+
import { OptionListLayout, ListLayout, SearchBoxLayout } from '../layout/index.js';
|
|
6
|
+
import { mergeInteraction } from './processors.js';
|
|
6
7
|
|
|
7
8
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
8
9
|
...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
|
|
@@ -15,6 +16,7 @@ const DEFAULT_API_OPTIONS = Object.freeze({
|
|
|
15
16
|
|
|
16
17
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
17
18
|
...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
|
|
19
|
+
[ROLE.QUERY]: [SearchBoxLayout.type, { templates: { buttonIcon: 'send' } }],
|
|
18
20
|
[ROLE.RELATED_RESOURCES]: [ListLayout.type, { incremental: true, itemType: 'article' }],
|
|
19
21
|
[ROLE.QUERY_SUGGESTIONS]: OptionListLayout.type,
|
|
20
22
|
});
|
|
@@ -36,13 +38,15 @@ const DEFAULT_OPTIONS = Object.freeze({
|
|
|
36
38
|
trackers: DEFAULT_TRACKERS,
|
|
37
39
|
});
|
|
38
40
|
|
|
41
|
+
const ROLES_OPTIONS = AnswerBasedWorkflow.ROLES_OPTIONS;
|
|
42
|
+
|
|
39
43
|
export default class Ask extends AnswerBasedWorkflow {
|
|
40
44
|
|
|
41
45
|
constructor(context, parentQuestionId) {
|
|
42
46
|
super({
|
|
43
47
|
name: 'ask',
|
|
44
48
|
context,
|
|
45
|
-
roles:
|
|
49
|
+
roles: ROLES_OPTIONS,
|
|
46
50
|
defaults: DEFAULT_OPTIONS,
|
|
47
51
|
parentQuestionId,
|
|
48
52
|
});
|
|
@@ -64,16 +68,17 @@ export default class Ask extends AnswerBasedWorkflow {
|
|
|
64
68
|
if (!previous) {
|
|
65
69
|
return;
|
|
66
70
|
}
|
|
71
|
+
// TODO: write question_source from payload._meta, so we don't need to write it to session.meta
|
|
67
72
|
const values = previous.states[fields.data()].value;
|
|
68
73
|
const value = values.suggested_followup_questions || values.followup_questions || [];
|
|
69
74
|
this._hub.update(fields.suggestions(), { value: value.map(text => ({ text })) });
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
_initSession(args) {
|
|
73
78
|
// register at context
|
|
74
79
|
args.parentQuestionId && this._context._byPqid.set(args.parentQuestionId, this);
|
|
75
80
|
this._context._events.emit('create', this);
|
|
76
|
-
super.
|
|
81
|
+
super._initSession(args);
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
// lifecycle //
|
|
@@ -119,30 +124,33 @@ export default class Ask extends AnswerBasedWorkflow {
|
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
// interactions //
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
127
|
+
_writeAskPropertiesToInteraction(payload, args) {
|
|
128
|
+
const root_question_id = this.rootQuestionId;
|
|
129
|
+
let { property } = (payload.context && payload.context.custom_context) || {};
|
|
130
|
+
let question_id, parent_question_id, question_source;
|
|
131
|
+
|
|
132
|
+
if (args.role === ROLE.QUERY_SUGGESTIONS) {
|
|
133
|
+
property = 'suggested_followup_questions';
|
|
134
|
+
parent_question_id = this.previous && this.previous.parentQuestionId;
|
|
135
|
+
question_id = this.parentQuestionId;
|
|
136
|
+
question_source = this.previous && this.previous.session.meta.question_source;
|
|
137
|
+
} else {
|
|
138
|
+
parent_question_id = this.parentQuestionId;
|
|
139
|
+
question_id = this.questionId;
|
|
140
|
+
question_source = this._getQuestionSourceFromViewState(args);
|
|
134
141
|
}
|
|
135
|
-
custom_context.question_id = questionId;
|
|
136
|
-
custom_context.root_question_id = rootQuestionId;
|
|
137
|
-
custom_context.parent_question_id = parentQuestionId;
|
|
138
142
|
|
|
139
|
-
return {
|
|
140
|
-
...payload,
|
|
143
|
+
return mergeInteraction(payload, {
|
|
141
144
|
context: {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
custom_context: {
|
|
146
|
+
property,
|
|
147
|
+
root_question_id,
|
|
148
|
+
parent_question_id,
|
|
149
|
+
question_id,
|
|
150
|
+
question_source,
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
});
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
// helpers //
|
package/src/workflow/asks.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mixin } from '@miso.ai/commons';
|
|
2
|
+
import { fields } from '../actor/index.js';
|
|
3
|
+
import Autocomplete from './autocomplete.js';
|
|
4
|
+
|
|
5
|
+
export function makeAutocompletable(prototype) {
|
|
6
|
+
mixin(prototype, AutocompletableMixin.prototype);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class AutocompletableMixin {
|
|
10
|
+
|
|
11
|
+
_initAutocomplete(args) {
|
|
12
|
+
this._autocomplete = new Autocomplete(this, { defaults: args.defaults.autocomplete });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get autocomplete() {
|
|
16
|
+
return this._autocomplete;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
updateCompletions(data) {
|
|
20
|
+
this._hub.update(fields.completions(), data);
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_destroyAutocomplete() {
|
|
25
|
+
this._autocomplete && this._autocomplete._destroy();
|
|
26
|
+
this._autocomplete = undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { STATUS } from '../constants.js';
|
|
2
|
+
import { fields } from '../actor/index.js';
|
|
3
|
+
import Workflow from './base.js';
|
|
4
|
+
|
|
5
|
+
const ROLES_OPTIONS = Object.freeze({
|
|
6
|
+
members: [],
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
function shimDefaults({ layouts, trackers, ...options } = {}) {
|
|
10
|
+
return {
|
|
11
|
+
active: false,
|
|
12
|
+
...options,
|
|
13
|
+
layouts: {},
|
|
14
|
+
trackers: {},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function sameInputValue(a, b) {
|
|
19
|
+
return getInputValue(a) === getInputValue(b);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getInputValue(args) {
|
|
23
|
+
return (args && args.value && args.value.trim()) || undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default class Autocomplete extends Workflow {
|
|
27
|
+
|
|
28
|
+
constructor(superworkflow, { defaults, ...args } = {}) {
|
|
29
|
+
super({
|
|
30
|
+
name: 'autocomplete',
|
|
31
|
+
plugin: superworkflow._plugin,
|
|
32
|
+
client: superworkflow._client,
|
|
33
|
+
defaults: shimDefaults(defaults),
|
|
34
|
+
roles: ROLES_OPTIONS,
|
|
35
|
+
superworkflow,
|
|
36
|
+
...args,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_initProperties(args) {
|
|
41
|
+
super._initProperties(args);
|
|
42
|
+
this._superworkflow = args.superworkflow;
|
|
43
|
+
this._active = args.defaults.active;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_initSubscriptions(args) {
|
|
47
|
+
// TODO: how to sync options updates
|
|
48
|
+
super._initSubscriptions(args);
|
|
49
|
+
this._unsubscribes = [
|
|
50
|
+
...this._unsubscribes,
|
|
51
|
+
args.superworkflow._hub.on(fields.input(), args => this._query(args)),
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// API //
|
|
56
|
+
get enabled() {
|
|
57
|
+
return this._active;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
enable() {
|
|
61
|
+
this._active = true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
disable() {
|
|
65
|
+
this._active = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// query //
|
|
69
|
+
_query(args) {
|
|
70
|
+
if (!this._active || sameInputValue(args, this._args)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this._args = args;
|
|
74
|
+
|
|
75
|
+
// start a new session
|
|
76
|
+
this.restart();
|
|
77
|
+
const { session } = this;
|
|
78
|
+
session.meta.input = args;
|
|
79
|
+
|
|
80
|
+
// if input value is blank, emit empty response
|
|
81
|
+
if (!getInputValue(args)) {
|
|
82
|
+
this._updateCompletions({ session, status: STATUS.INITIAL });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// payload
|
|
87
|
+
const payload = this._buildPayload(args);
|
|
88
|
+
|
|
89
|
+
// request
|
|
90
|
+
this._request({ payload });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_buildPayload(args) {
|
|
94
|
+
return { q: getInputValue(args) };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// data //
|
|
98
|
+
_updateDataInHub(data) {
|
|
99
|
+
if (data.value) {
|
|
100
|
+
data = {
|
|
101
|
+
...data,
|
|
102
|
+
value: data.value.completions,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// update completion field in superworkflow hub
|
|
106
|
+
this._updateCompletions(data);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_updateCompletions(data) {
|
|
110
|
+
this._superworkflow.updateCompletions(data);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|