@miso.ai/client-sdk-ui 1.13.2-beta.0 → 1.14.0-beta.2

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 (214) hide show
  1. package/dist/cjs/asset/svgs.js +15 -4
  2. package/dist/cjs/combo/ask/index.js +2 -2
  3. package/dist/cjs/constants.js +118 -98
  4. package/dist/cjs/defaults/ask/controls.js +1 -1
  5. package/dist/cjs/defaults/hybrid-search/answer-box.js +4 -4
  6. package/dist/cjs/defaults.js +169 -0
  7. package/dist/cjs/element/container/index.js +14 -0
  8. package/dist/cjs/element/container/miso-ask.js +3 -3
  9. package/dist/cjs/element/container/miso-conversation.js +21 -0
  10. package/dist/cjs/element/container/miso-explore.js +1 -1
  11. package/dist/cjs/element/container/miso-history.js +21 -0
  12. package/dist/cjs/element/container/miso-hybrid-search.js +1 -1
  13. package/dist/cjs/element/container/miso-recommendation.js +1 -1
  14. package/dist/cjs/element/container/miso-search.js +1 -1
  15. package/dist/cjs/element/context/miso-follow-ups.js +1 -1
  16. package/dist/cjs/element/role/index.js +42 -0
  17. package/dist/cjs/element/role/miso-messages.js +20 -0
  18. package/dist/cjs/element/role/miso-new-thread.js +20 -0
  19. package/dist/cjs/element/role/miso-rename.js +20 -0
  20. package/dist/cjs/element/role/miso-subscription.js +20 -0
  21. package/dist/cjs/element/role/miso-threads.js +20 -0
  22. package/dist/cjs/element/role/miso-title.js +20 -0
  23. package/dist/cjs/layout/affiliation/affiliation.js +1 -1
  24. package/dist/cjs/layout/banner/banner.js +2 -1
  25. package/dist/cjs/layout/button/button.js +130 -0
  26. package/dist/cjs/layout/button/checkbox.js +115 -0
  27. package/dist/cjs/layout/button/more-button.js +3 -3
  28. package/dist/cjs/layout/container/container.js +1 -1
  29. package/dist/cjs/layout/error/error.js +2 -1
  30. package/dist/cjs/layout/index.js +28 -0
  31. package/dist/cjs/layout/input/facets.js +4 -3
  32. package/dist/cjs/layout/input/option-list.js +3 -2
  33. package/dist/cjs/layout/input/search-box.js +42 -9
  34. package/dist/cjs/layout/input/select.js +2 -1
  35. package/dist/cjs/layout/list/cards.js +2 -1
  36. package/dist/cjs/layout/list/carousel.js +2 -1
  37. package/dist/cjs/layout/list/collection.js +5 -0
  38. package/dist/cjs/layout/list/gallery.js +2 -1
  39. package/dist/cjs/layout/list/horizontal.js +2 -1
  40. package/dist/cjs/layout/list/list.js +2 -1
  41. package/dist/cjs/layout/list/messages.js +346 -0
  42. package/dist/cjs/layout/list/threads.js +257 -0
  43. package/dist/cjs/layout/mixin/trackable.js +4 -5
  44. package/dist/cjs/layout/mixin/triggerable.js +2 -2
  45. package/dist/cjs/layout/radio/feedback.js +4 -3
  46. package/dist/cjs/layout/templates.js +70 -0
  47. package/dist/cjs/layout/text/text.js +2 -1
  48. package/dist/cjs/layout/text/typewriter/index.js +4 -2
  49. package/dist/cjs/plugin.js +43 -104
  50. package/dist/cjs/util/confirm.js +33 -0
  51. package/dist/cjs/util/modal.js +48 -0
  52. package/dist/cjs/util/prompt.js +47 -0
  53. package/dist/cjs/version.js +1 -1
  54. package/package.json +5 -4
  55. package/src/CLAUDE.md +48 -105
  56. package/src/asset/svgs.js +14 -3
  57. package/src/combo/ask/index.js +2 -2
  58. package/src/constants.js +37 -147
  59. package/src/defaults/ask/controls.js +1 -1
  60. package/src/defaults/hybrid-search/answer-box.js +2 -2
  61. package/src/defaults.js +107 -0
  62. package/src/element/container/index.js +2 -0
  63. package/src/element/container/miso-ask.js +3 -3
  64. package/src/element/container/miso-conversation.js +19 -0
  65. package/src/element/container/miso-explore.js +1 -1
  66. package/src/element/container/miso-history.js +19 -0
  67. package/src/element/container/miso-hybrid-search.js +1 -1
  68. package/src/element/container/miso-recommendation.js +1 -1
  69. package/src/element/container/miso-search.js +1 -1
  70. package/src/element/context/miso-follow-ups.js +1 -1
  71. package/src/element/role/index.js +6 -0
  72. package/src/element/role/miso-messages.js +16 -0
  73. package/src/element/role/miso-new-thread.js +16 -0
  74. package/src/element/role/miso-rename.js +16 -0
  75. package/src/element/role/miso-subscription.js +16 -0
  76. package/src/element/role/miso-threads.js +16 -0
  77. package/src/element/role/miso-title.js +16 -0
  78. package/src/layout/affiliation/affiliation.js +2 -2
  79. package/src/layout/banner/banner.js +2 -1
  80. package/src/layout/button/button.js +116 -0
  81. package/src/layout/button/checkbox.js +91 -0
  82. package/src/layout/button/more-button.js +3 -3
  83. package/src/layout/container/container.js +2 -2
  84. package/src/layout/error/error.js +2 -1
  85. package/src/layout/index.js +4 -0
  86. package/src/layout/input/facets.js +3 -2
  87. package/src/layout/input/option-list.js +3 -2
  88. package/src/layout/input/search-box.js +41 -6
  89. package/src/layout/input/select.js +2 -1
  90. package/src/layout/list/cards.js +2 -1
  91. package/src/layout/list/carousel.js +2 -1
  92. package/src/layout/list/collection.js +6 -1
  93. package/src/layout/list/gallery.js +2 -1
  94. package/src/layout/list/horizontal.js +2 -1
  95. package/src/layout/list/list.js +2 -1
  96. package/src/layout/list/messages.js +318 -0
  97. package/src/layout/list/threads.js +206 -0
  98. package/src/layout/mixin/trackable.js +2 -3
  99. package/src/layout/mixin/triggerable.js +1 -1
  100. package/src/layout/radio/feedback.js +3 -2
  101. package/src/layout/templates.js +62 -0
  102. package/src/layout/text/text.js +2 -1
  103. package/src/layout/text/typewriter/index.js +5 -3
  104. package/src/plugin.js +31 -117
  105. package/src/util/confirm.js +28 -0
  106. package/src/util/modal.js +49 -0
  107. package/src/util/prompt.js +42 -0
  108. package/src/version.js +1 -1
  109. package/dist/cjs/actor/data.js +0 -132
  110. package/dist/cjs/actor/feedback.js +0 -29
  111. package/dist/cjs/actor/fields.js +0 -57
  112. package/dist/cjs/actor/filters.js +0 -161
  113. package/dist/cjs/actor/hub.js +0 -57
  114. package/dist/cjs/actor/index.js +0 -73
  115. package/dist/cjs/actor/interactions.js +0 -36
  116. package/dist/cjs/actor/sessions.js +0 -25
  117. package/dist/cjs/actor/tracker-states.js +0 -61
  118. package/dist/cjs/actor/tracker.js +0 -109
  119. package/dist/cjs/actor/trackers.js +0 -52
  120. package/dist/cjs/actor/utils.js +0 -15
  121. package/dist/cjs/actor/view.js +0 -294
  122. package/dist/cjs/actor/views.js +0 -209
  123. package/dist/cjs/source.js +0 -27
  124. package/dist/cjs/util/proxy.js +0 -88
  125. package/dist/cjs/util/trackers.js +0 -88
  126. package/dist/cjs/workflow/affiliations.js +0 -140
  127. package/dist/cjs/workflow/answer-based.js +0 -337
  128. package/dist/cjs/workflow/ask.js +0 -319
  129. package/dist/cjs/workflow/asks.js +0 -150
  130. package/dist/cjs/workflow/autocompletable.js +0 -63
  131. package/dist/cjs/workflow/autocomplete.js +0 -120
  132. package/dist/cjs/workflow/base.js +0 -418
  133. package/dist/cjs/workflow/context.js +0 -19
  134. package/dist/cjs/workflow/explore.js +0 -210
  135. package/dist/cjs/workflow/explores.js +0 -21
  136. package/dist/cjs/workflow/hybrid-search-answer.js +0 -88
  137. package/dist/cjs/workflow/hybrid-search-views.js +0 -109
  138. package/dist/cjs/workflow/hybrid-search.js +0 -213
  139. package/dist/cjs/workflow/index.js +0 -41
  140. package/dist/cjs/workflow/options/api.js +0 -41
  141. package/dist/cjs/workflow/options/auto-query.js +0 -97
  142. package/dist/cjs/workflow/options/configurable.js +0 -45
  143. package/dist/cjs/workflow/options/data-processor.js +0 -20
  144. package/dist/cjs/workflow/options/filters.js +0 -15
  145. package/dist/cjs/workflow/options/index.js +0 -126
  146. package/dist/cjs/workflow/options/interactions.js +0 -41
  147. package/dist/cjs/workflow/options/layouts.js +0 -79
  148. package/dist/cjs/workflow/options/options.js +0 -156
  149. package/dist/cjs/workflow/options/pagination.js +0 -25
  150. package/dist/cjs/workflow/options/roles.js +0 -15
  151. package/dist/cjs/workflow/options/templates.js +0 -30
  152. package/dist/cjs/workflow/options/trackers.js +0 -83
  153. package/dist/cjs/workflow/options/utils.js +0 -33
  154. package/dist/cjs/workflow/processors.js +0 -607
  155. package/dist/cjs/workflow/recommendation.js +0 -57
  156. package/dist/cjs/workflow/recommendations.js +0 -18
  157. package/dist/cjs/workflow/search-based.js +0 -337
  158. package/dist/cjs/workflow/search.js +0 -64
  159. package/dist/cjs/workflow/unit.js +0 -57
  160. package/dist/cjs/workflow/units.js +0 -42
  161. package/dist/cjs/workflow/use-link.js +0 -49
  162. package/src/actor/data.js +0 -106
  163. package/src/actor/feedback.js +0 -28
  164. package/src/actor/fields.js +0 -51
  165. package/src/actor/filters.js +0 -149
  166. package/src/actor/hub.js +0 -47
  167. package/src/actor/index.js +0 -10
  168. package/src/actor/interactions.js +0 -32
  169. package/src/actor/sessions.js +0 -21
  170. package/src/actor/tracker-states.js +0 -57
  171. package/src/actor/tracker.js +0 -104
  172. package/src/actor/trackers.js +0 -45
  173. package/src/actor/utils.js +0 -7
  174. package/src/actor/view.js +0 -272
  175. package/src/actor/views.js +0 -224
  176. package/src/source.js +0 -17
  177. package/src/util/proxy.js +0 -81
  178. package/src/util/trackers.js +0 -84
  179. package/src/workflow/affiliations.js +0 -121
  180. package/src/workflow/answer-based.js +0 -312
  181. package/src/workflow/ask.js +0 -284
  182. package/src/workflow/asks.js +0 -143
  183. package/src/workflow/autocompletable.js +0 -67
  184. package/src/workflow/autocomplete.js +0 -114
  185. package/src/workflow/base.js +0 -396
  186. package/src/workflow/context.js +0 -16
  187. package/src/workflow/explore.js +0 -194
  188. package/src/workflow/explores.js +0 -18
  189. package/src/workflow/hybrid-search-answer.js +0 -73
  190. package/src/workflow/hybrid-search-views.js +0 -116
  191. package/src/workflow/hybrid-search.js +0 -230
  192. package/src/workflow/index.js +0 -5
  193. package/src/workflow/options/api.js +0 -31
  194. package/src/workflow/options/auto-query.js +0 -70
  195. package/src/workflow/options/configurable.js +0 -48
  196. package/src/workflow/options/data-processor.js +0 -15
  197. package/src/workflow/options/filters.js +0 -10
  198. package/src/workflow/options/index.js +0 -11
  199. package/src/workflow/options/interactions.js +0 -36
  200. package/src/workflow/options/layouts.js +0 -73
  201. package/src/workflow/options/options.js +0 -175
  202. package/src/workflow/options/pagination.js +0 -18
  203. package/src/workflow/options/roles.js +0 -12
  204. package/src/workflow/options/templates.js +0 -27
  205. package/src/workflow/options/trackers.js +0 -80
  206. package/src/workflow/options/utils.js +0 -26
  207. package/src/workflow/processors.js +0 -490
  208. package/src/workflow/recommendation.js +0 -63
  209. package/src/workflow/recommendations.js +0 -14
  210. package/src/workflow/search-based.js +0 -329
  211. package/src/workflow/search.js +0 -73
  212. package/src/workflow/unit.js +0 -51
  213. package/src/workflow/units.js +0 -43
  214. package/src/workflow/use-link.js +0 -41
@@ -1,121 +0,0 @@
1
- import { trimObj } from '@miso.ai/commons';
2
-
3
- export function processAffiliationData(data) {
4
- if (!data || !data.value) {
5
- return data;
6
- }
7
- const { value } = data;
8
- return {
9
- ...data,
10
- value: processValue(value)
11
- };
12
- }
13
-
14
- function processValue(value) {
15
- if (value.affiliation_products) {
16
- const { affiliation_products, ...rest } = value;
17
- value = {
18
- ...rest,
19
- affiliation: processMisoData(affiliation_products),
20
- };
21
- } else if (value.sovrn_aff) {
22
- const { sovrn_aff, ...rest } = value;
23
- value = {
24
- ...rest,
25
- affiliation: processSovrnData(sovrn_aff),
26
- };
27
- }
28
- return postProcessValue(value);
29
- }
30
-
31
- function postProcessValue(value) {
32
- const { affiliation } = value;
33
- if (!affiliation) {
34
- return value;
35
- }
36
- let { channel, products } = affiliation;
37
- if (!products) {
38
- return value;
39
- }
40
- products = products.map(product => ({ ...product }));
41
- let i = 0;
42
- for (const product of products) {
43
- if (channel) {
44
- product.channel = channel;
45
- }
46
- product.position = i++;
47
- }
48
- return {
49
- ...value,
50
- affiliation: {
51
- ...affiliation,
52
- products,
53
- },
54
- };
55
- }
56
-
57
- function processMisoData(products) {
58
- return {
59
- channel: 'miso',
60
- products,
61
- };
62
- }
63
-
64
- function processSovrnData({ products, ...data }) {
65
- return {
66
- channel: 'sovrn',
67
- ...data,
68
- products: products.map(processSovrnProduct),
69
- };
70
- }
71
-
72
- export function processSovrnProduct({
73
- id,
74
- deeplink: url,
75
- headline: title,
76
- description,
77
- currency,
78
- retailPrice: original_price,
79
- salePrice: sale_price,
80
- discountRate: discount_rate_percent,
81
- image: cover_image,
82
- thumbnail,
83
- merchant,
84
- ...product
85
- }) {
86
- const brand = merchant && merchant.name;
87
- const brand_logo = merchant && merchant.logo;
88
- return trimObj({
89
- id: `sovrn-${id}`,
90
- title,
91
- description,
92
- cover_image,
93
- url,
94
- currency,
95
- original_price,
96
- sale_price,
97
- discount_rate_percent,
98
- brand,
99
- brand_logo,
100
- custom_attributes: flatten({
101
- sovrn_id: id,
102
- thumbnail,
103
- merchant,
104
- ...product,
105
- }),
106
- });
107
- }
108
-
109
- function flatten(obj, prefix = '') {
110
- return Object.keys(obj).reduce((acc, key) => {
111
- const value = obj[key];
112
- if (value === undefined) {
113
- return acc;
114
- }
115
- const prefixedKey = prefix ? `${prefix}_${key}` : key;
116
- if (typeof value === 'object') {
117
- return { ...acc, ...flatten(value, prefixedKey) };
118
- }
119
- return { ...acc, [prefixedKey]: value };
120
- }, {});
121
- }
@@ -1,312 +0,0 @@
1
- import { API } from '@miso.ai/commons';
2
- import Workflow from './base.js';
3
- import { fields, FeedbackActor } from '../actor/index.js';
4
- import { ROLE, STATUS, QUESTION_SOURCE } from '../constants.js';
5
- import { SearchBoxLayout, TextLayout, ListLayout, GalleryLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
6
- import { processAffiliationData } from './affiliations.js';
7
- import { mergeRolesOptions, autoQuery as autoQueryFn, updateQueryParametersInUrl, DEFAULT_AUTO_QUERY_PARAM, DEFAULT_TRACKER_OPTIONS } from './options/index.js';
8
- import { mappingAnswerData, mappingReasoningData, writeAnswerStageToMeta, writeAnswerInfoToInteraction } from './processors.js';
9
- import { enableUseLink } from './use-link.js';
10
- import { isTracked, markAsTracked } from '../util/trackers.js';
11
-
12
- const DEFAULT_API_OPTIONS = Object.freeze({
13
- ...Workflow.DEFAULT_API_OPTIONS,
14
- group: API.GROUP.ASK,
15
- payload: {
16
- ...Workflow.DEFAULT_API_OPTIONS.payload,
17
- source_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at'],
18
- cite_link: 1,
19
- cite_start: '[',
20
- cite_end: ']',
21
- },
22
- });
23
-
24
- const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
25
- actor: false,
26
- api: {
27
- group: API.GROUP.ASK,
28
- name: API.NAME.AUTOCOMPLETE,
29
- },
30
- });
31
-
32
- const DEFAULT_LAYOUTS = Object.freeze({
33
- ...Workflow.DEFAULT_LAYOUTS,
34
- [ROLE.QUERY]: [SearchBoxLayout.type, { placeholder: 'Ask a question' }],
35
- [ROLE.QUESTION]: [TextLayout.type, { tag: 'h2' }],
36
- [ROLE.ANSWER]: TypewriterLayout.type,
37
- [ROLE.FEEDBACK]: FeedbackLayout.type,
38
- [ROLE.IMAGES]: [GalleryLayout.type, { incremental: true, itemType: 'image' }],
39
- [ROLE.SOURCES]: [ListLayout.type, { incremental: true, itemType: 'article', templates: { ordered: true } }],
40
- [ROLE.AFFILIATION]: [AffiliationLayout.type, { incremental: true, itemType: 'affiliation', link: { rel: 'noopener nofollow' } }],
41
- });
42
-
43
- const DEFAULT_TRACKERS = Object.freeze({
44
- ...Workflow.DEFAULT_TRACKERS,
45
- [ROLE.ANSWER]: {
46
- active: true,
47
- itemless: true,
48
- deduplicated: false,
49
- click: DEFAULT_TRACKER_OPTIONS.click, // click only
50
- },
51
- [ROLE.IMAGES]: DEFAULT_TRACKER_OPTIONS,
52
- [ROLE.SOURCES]: DEFAULT_TRACKER_OPTIONS,
53
- [ROLE.AFFILIATION]: DEFAULT_TRACKER_OPTIONS,
54
- [ROLE.PRODUCTS]: DEFAULT_TRACKER_OPTIONS,
55
- });
56
-
57
- const DEFAULT_OPTIONS = Object.freeze({
58
- ...Workflow.DEFAULT_OPTIONS,
59
- api: DEFAULT_API_OPTIONS,
60
- autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
61
- layouts: DEFAULT_LAYOUTS,
62
- trackers: DEFAULT_TRACKERS,
63
- });
64
-
65
- const ROLES_OPTIONS = mergeRolesOptions(Workflow.ROLES_OPTIONS, {
66
- main: ROLE.ANSWER,
67
- members: Object.keys(DEFAULT_LAYOUTS),
68
- mappings: {
69
- [ROLE.ANSWER]: mappingAnswerData,
70
- [ROLE.REASONING]: mappingReasoningData,
71
- },
72
- });
73
-
74
- export default class AnswerBasedWorkflow extends Workflow {
75
-
76
- // constructor //
77
- _initProperties(args) {
78
- super._initProperties(args);
79
- this._questionId = undefined;
80
- this._autoQuery = false;
81
- }
82
-
83
- _initActors(args) {
84
- super._initActors(args);
85
- this._feedback = new FeedbackActor(this._hub);
86
- }
87
-
88
- _initSubscriptions(args) {
89
- super._initSubscriptions(args);
90
- this._unsubscribes = [
91
- ...this._unsubscribes,
92
- this._hub.on(fields.query(), args => this._query(args)),
93
- this._views.on(ROLE.ANSWER, 'citation-click', event => this._onCitationClick(event)),
94
- this._views.on(ROLE.ANSWER, 'link-click', event => this._onAnswerLinkClick(event)),
95
- ];
96
- }
97
-
98
- // lifecycle //
99
- restart() {
100
- // clear question id from previous session
101
- if (this._questionId) {
102
- this._questionId = undefined;
103
- }
104
- // restart
105
- super.restart();
106
- }
107
-
108
- _shallEmitLifecycleEvent(name, event) {
109
- return name === 'answer-stage' || super._shallEmitLifecycleEvent(name, event);
110
- }
111
-
112
- _emitInterruptEventIfNecessary() {
113
- const state = this._hub.states[fields.view(this._roles.main)] || {};
114
- if (state.session && state.status !== STATUS.INITIAL && (state.status !== STATUS.READY || state.ongoing)) {
115
- // it's interrupted by a new question
116
- this._emitLifecycleEvent('interrupt', state);
117
- this._emitLifecycleEvent('finally', state);
118
- }
119
- }
120
-
121
- _onMainViewUpdate(state) {
122
- const { status, session } = state;
123
- const done = status === STATUS.READY && !state.ongoing;
124
- const erroneous = status === STATUS.ERRONEOUS;
125
- const eventName = done ? 'done' : erroneous ? 'error' : status;
126
-
127
- // answer-stage
128
- const context = this._getSessionContext(session);
129
- const oldAnswerStage = context.answerStage;
130
- const newAnswerStage = state.meta && state.meta.answer_stage;
131
- if (newAnswerStage && newAnswerStage !== oldAnswerStage) {
132
- this._emitLifecycleEvent('answer-stage', Object.freeze({ ...state, answer_stage: newAnswerStage }));
133
- context.answerStage = newAnswerStage;
134
- }
135
-
136
- // blocked reason
137
- const data = this._hub.states[fields.data()] || {};
138
- const { value } = data;
139
- if (value) {
140
- const { blocked_reason } = value;
141
- if (blocked_reason) {
142
- this._emitLifecycleEvent('blocked', { ...state, blockedReason: blocked_reason });
143
- }
144
- }
145
-
146
- // ready, done, or error
147
- this._emitLifecycleEvent(eventName, state);
148
- if (done || erroneous) {
149
- // finally
150
- this._emitLifecycleEvent('finally', state);
151
- }
152
- }
153
-
154
- // properties //
155
- get questionId() {
156
- return this._questionId;
157
- }
158
-
159
- // query //
160
- autoQuery(options = {}) {
161
- autoQueryFn.call(this, options);
162
- }
163
-
164
- query(args) {
165
- // TODO: also accept "question", "questionSource"?
166
- if (!args.q && !args.questionId) {
167
- throw new Error(`q is required in query() call`);
168
- }
169
- this._hub.update(fields.query(), args);
170
- }
171
-
172
- _query(args = {}) {
173
- if (this._linkFn) {
174
- this._submitToPage(args);
175
- return;
176
- }
177
- // start a new session
178
- this.restart();
179
-
180
- // keep track of question source on this session, for suggested questions interactions
181
- this._writeQuestionSourceToSession(args);
182
-
183
- // build payload and trigger request
184
- const payload = this._buildPayload(args);
185
- this._request({ payload });
186
- }
187
-
188
- _writeQuestionSourceToSession(args) {
189
- this.session.meta.question_source = args.qs || QUESTION_SOURCE.ORGANIC; // might be null, not undefined
190
- }
191
-
192
- _buildPayload() {
193
- throw new Error(`Not implemented`);
194
- }
195
-
196
- _writeWikiLinkTemplateToPayload(payload) {
197
- if (!this._autoQuery || !this._autoQuery.param || this._autoQuery.param === DEFAULT_AUTO_QUERY_PARAM) {
198
- return payload;
199
- }
200
- return {
201
- ...payload,
202
- wiki_link_template: `?${this._autoQuery.param}=%s`,
203
- };
204
- }
205
-
206
- // data //
207
- _updateData(data) {
208
- // capture question ID and register at context
209
- this._writeQuestionIdFromData(data);
210
-
211
- // if it's the head response, write question id and return
212
- if (data.value && !data.value.answer_stage) {
213
- this._handleHeadResponse(data);
214
- return;
215
- }
216
- super._updateData(data);
217
-
218
- // update URL if autoQuery.updateUrl is not false
219
- updateQueryParametersInUrl.call(this, data);
220
- }
221
-
222
- _handleHeadResponse(data) {}
223
-
224
- _defaultProcessData(data, oldData) {
225
- data = super._defaultProcessData(data, oldData);
226
- data = processAffiliationData(data);
227
- data = writeAnswerStageToMeta(data);
228
- return data;
229
- }
230
-
231
- _writeQuestionIdFromData({ value }) {
232
- value && this._writeQuestionId(value.question_id);
233
- }
234
-
235
- // interactions //
236
- _defaultProcessInteraction(payload, args) {
237
- payload = super._defaultProcessInteraction(payload, args);
238
- payload = writeAnswerInfoToInteraction(payload, args);
239
- return payload;
240
- }
241
-
242
- _getQuestionSourceFromViewState(args) {
243
- const { request } = this._hub.states[fields.view(args.role)] || {};
244
- const { payload } = request || {};
245
- return (payload && payload.metadata && payload.metadata.question_source) || undefined;
246
- }
247
-
248
- // handlers //
249
- _onCitationClick({ index, event }) {
250
- if (event.button !== 0) {
251
- return; // only left click
252
- }
253
- if (isTracked(event)) {
254
- return;
255
- }
256
- const { value } = this._hub.states[fields.data()] || {};
257
- const { sources } = value || {};
258
- // index is 1-based
259
- const source = sources && sources[index - 1];
260
- if (!source || !source.product_id) {
261
- return;
262
- }
263
- // TODO: should we track impression as well?
264
- markAsTracked(event);
265
- // distinguish from regular sources element click
266
- this._views.trackers.sources.click([source.product_id], { event_target: 'citation-link' });
267
- }
268
-
269
- _onAnswerLinkClick({ event, ...item }) {
270
- if (event.button !== 0) {
271
- return; // only left click
272
- }
273
- if (isTracked(event)) {
274
- return;
275
- }
276
- markAsTracked(event);
277
- // put everything into args and let _defaultProcessInteraction() handles it
278
- // for it's hard to make it a standard item
279
- this._views.trackers.answer.click([], { items: [item] });
280
- }
281
-
282
- // helpers //
283
- _writeQuestionId(questionId) {
284
- if (!this._questionId && questionId) {
285
- this._questionId = questionId;
286
- }
287
- }
288
-
289
- _clearQuestionId() {
290
- // clear question id from previous session
291
- this._questionId = undefined;
292
- }
293
-
294
- // destroy //
295
- _destroy(options) {
296
- this._feedback._destroy();
297
- // this._autocomplete._destroy();
298
- super._destroy(options);
299
- }
300
-
301
- }
302
-
303
- enableUseLink(AnswerBasedWorkflow.prototype);
304
-
305
- Object.assign(AnswerBasedWorkflow, {
306
- DEFAULT_API_OPTIONS,
307
- DEFAULT_AUTOCOMPLETE_OPTIONS,
308
- DEFAULT_LAYOUTS,
309
- DEFAULT_TRACKERS,
310
- DEFAULT_OPTIONS,
311
- ROLES_OPTIONS,
312
- });
@@ -1,284 +0,0 @@
1
- import { defineValues, trimObj, API, mergeInteractions } from '@miso.ai/commons';
2
- import AnswerBasedWorkflow from './answer-based.js';
3
- import { fields } from '../actor/index.js';
4
- import { ROLE, STATUS, QUESTION_SOURCE } from '../constants.js';
5
- import { OptionListLayout, ListLayout, SearchBoxLayout, TypewriterLayout } from '../layout/index.js';
6
- import { mergeRolesOptions, DEFAULT_TRACKER_OPTIONS } from './options/index.js';
7
- import { writeQuestionSourceToPayload, mappingSuggestionsData, mappingFollowUpQuestionsData } from './processors.js';
8
- import { followUp as followUpTemplate } from '../defaults/ask/templates.js';
9
- import { makeAutocompletable } from './autocompletable.js';
10
-
11
- const DEFAULT_API_OPTIONS = Object.freeze({
12
- ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
13
- name: API.NAME.QUESTIONS,
14
- payload: {
15
- ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS.payload,
16
- related_resource_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at'],
17
- },
18
- });
19
-
20
- const DEFAULT_LAYOUTS = Object.freeze({
21
- ...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
22
- [ROLE.QUERY]: [SearchBoxLayout.type, { templates: { buttonIcon: 'send' } }],
23
- [ROLE.REASONING]: TypewriterLayout.type,
24
- [ROLE.RELATED_RESOURCES]: [ListLayout.type, { incremental: true, itemType: 'article' }],
25
- [ROLE.QUERY_SUGGESTIONS]: OptionListLayout.type,
26
- [ROLE.FOLLOW_UP_QUESTIONS]: OptionListLayout.type,
27
- });
28
-
29
- const DEFAULT_TRACKERS = Object.freeze({
30
- ...AnswerBasedWorkflow.DEFAULT_TRACKERS,
31
- [ROLE.RELATED_RESOURCES]: DEFAULT_TRACKER_OPTIONS,
32
- [ROLE.QUERY_SUGGESTIONS]: {
33
- ...DEFAULT_TRACKER_OPTIONS,
34
- click: {
35
- ...DEFAULT_TRACKER_OPTIONS.click,
36
- validate: event => event.button === 0, // loosen criteria, for it's not a hyperlink
37
- },
38
- },
39
- });
40
-
41
- const DEFAULT_TEMPLATES = Object.freeze({
42
- followUp: followUpTemplate,
43
- });
44
-
45
- const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
46
- api: {
47
- group: API.GROUP.ASK,
48
- name: API.NAME.AUTOCOMPLETE,
49
- },
50
- });
51
-
52
- const DEFAULT_OPTIONS = Object.freeze({
53
- ...AnswerBasedWorkflow.DEFAULT_OPTIONS,
54
- api: DEFAULT_API_OPTIONS,
55
- layouts: DEFAULT_LAYOUTS,
56
- trackers: DEFAULT_TRACKERS,
57
- templates: DEFAULT_TEMPLATES,
58
- autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
59
- });
60
-
61
- const ROLES_OPTIONS = mergeRolesOptions(AnswerBasedWorkflow.ROLES_OPTIONS, {
62
- members: Object.keys(DEFAULT_LAYOUTS),
63
- mappings: {
64
- [ROLE.QUERY_SUGGESTIONS]: mappingSuggestionsData,
65
- [ROLE.FOLLOW_UP_QUESTIONS]: mappingFollowUpQuestionsData,
66
- },
67
- });
68
-
69
- export default class Ask extends AnswerBasedWorkflow {
70
-
71
- constructor(context, parentQuestionId) {
72
- super({
73
- name: 'ask',
74
- context,
75
- roles: ROLES_OPTIONS,
76
- defaults: DEFAULT_OPTIONS,
77
- parentQuestionId,
78
- });
79
- }
80
-
81
- _initProperties(args) {
82
- super._initProperties(args);
83
- this._initAutocomplete(args);
84
- const { parentQuestionId } = args;
85
- defineValues(this, { parentQuestionId });
86
- }
87
-
88
- _initSubscriptions(args) {
89
- super._initSubscriptions(args);
90
- this._unsubscribes = [
91
- ...this._unsubscribes,
92
- this._hub.on(fields.view(ROLE.REASONING), state => this._onReasoningViewUpdate(state)),
93
- this._views.on(ROLE.ANSWER, 'follow-up-click', event => this._onFollowUpClick(event)),
94
- this._views.on(ROLE.FOLLOW_UP_QUESTIONS, 'select', event => this._onFollowUpQuestionSelect(event)),
95
- this._views.on(ROLE.QUERY_SUGGESTIONS, 'select', event => this._onQuerySuggestionSelect(event)),
96
- ];
97
- }
98
-
99
- _initSession(args) {
100
- // register at context
101
- args.parentQuestionId && this._context._byPqid.set(args.parentQuestionId, this);
102
- this._context._events.emit('create', this);
103
- super._initSession(args);
104
- }
105
-
106
- // lifecycle //
107
- restart() {
108
- const { next } = this;
109
- next && next.destroy();
110
- if (this._questionId) {
111
- this._context._byQid.delete(this._questionId);
112
- }
113
- super.restart();
114
- }
115
-
116
- // properties //
117
- get rootQuestionId() {
118
- return this._context.root.questionId;
119
- }
120
-
121
- get previous() {
122
- const { parentQuestionId } = this;
123
- return parentQuestionId ? this._context.getByQuestionId(parentQuestionId) : undefined;
124
- }
125
-
126
- get next() {
127
- const { questionId } = this;
128
- return questionId ? this._context.getByParentQuestionId(questionId) : undefined;
129
- }
130
-
131
- getOrCreateNext() {
132
- const { questionId } = this;
133
- return questionId ? this._context.getByParentQuestionId(questionId, { autoCreate: true }) : undefined;
134
- }
135
-
136
- // query //
137
- _buildPayload({ q, qs, questionId, ...options } = {}) {
138
- if (questionId) {
139
- return trimObj({
140
- ...options,
141
- question_id: questionId,
142
- // TODO: specify this is a replayed session
143
- });
144
- }
145
- const { parentQuestionId } = this;
146
- let payload = trimObj({
147
- ...options,
148
- question: q, // question, not q
149
- parent_question_id: parentQuestionId,
150
- });
151
- payload = writeQuestionSourceToPayload({ ...payload, qs });
152
- payload = this._writeWikiLinkTemplateToPayload(payload);
153
- return payload;
154
- }
155
-
156
- // data //
157
- _updateData(data) {
158
- super._updateData(data);
159
- this._triggerSuggestionsRefreshIfNecessary();
160
- }
161
-
162
- _triggerSuggestionsRefreshIfNecessary() {
163
- const { next } = this;
164
- if (!next) {
165
- return;
166
- }
167
- for (const view of next._views.getAll(ROLE.QUERY_SUGGESTIONS)) {
168
- view.refresh();
169
- }
170
- }
171
-
172
- // view //
173
- _onReasoningViewUpdate({ status, ongoing }) {
174
- if (status !== STATUS.READY || ongoing) {
175
- return;
176
- }
177
- for (const view of this._views.getAll(ROLE.REASONING)) {
178
- const element = view.element && view.element.closest('[data-role="reasoning-box"]');
179
- element && element.classList.add('done');
180
- }
181
- }
182
-
183
- // interactions //
184
- _defaultProcessInteraction(payload, args) {
185
- payload = super._defaultProcessInteraction(payload, args);
186
- payload = this._writeAdditionalAskPropertiesToInteraction(payload, args);
187
- return payload;
188
- }
189
-
190
- _writeAdditionalAskPropertiesToInteraction(payload, args) {
191
- const root_question_id = this.rootQuestionId;
192
- let { property } = (payload.context && payload.context.custom_context) || {};
193
- let question_id, parent_question_id, question_source;
194
-
195
- if (args.role === ROLE.FOLLOW_UP_QUESTIONS || args.role === ROLE.QUERY_SUGGESTIONS) {
196
- property = 'suggested_followup_questions';
197
- }
198
-
199
- if (args.role === ROLE.QUERY_SUGGESTIONS) {
200
- parent_question_id = this.previous && this.previous.parentQuestionId;
201
- question_id = this.parentQuestionId;
202
- question_source = this.previous && this.previous.session.meta.question_source;
203
- } else {
204
- parent_question_id = this.parentQuestionId;
205
- }
206
-
207
- return mergeInteractions(payload, {
208
- context: {
209
- custom_context: trimObj({ // question_id, question_source can be undefined
210
- property,
211
- root_question_id,
212
- parent_question_id,
213
- question_id,
214
- question_source,
215
- }),
216
- }
217
- });
218
- }
219
-
220
- // handlers //
221
- _onFollowUpClick({ q, event } = {}) {
222
- if (event.button !== 0) {
223
- return; // only left click
224
- }
225
- this._submitFollowUpQuestion({ q, qs: QUESTION_SOURCE.INLINE_QUESTION_LINK });
226
- // TODO: track click?
227
- }
228
-
229
- _onFollowUpQuestionSelect({ value: q }) {
230
- this._submitFollowUpQuestion({ q, qs: QUESTION_SOURCE.SUGGESTED_QUESTIONS });
231
- }
232
-
233
- _submitFollowUpQuestion({ q = '', qs } = {}) {
234
- q = q.trim();
235
- if (!q) {
236
- return;
237
- }
238
- const next = this.getOrCreateNext();
239
- next.query({ q, qs });
240
- }
241
-
242
- _onQuerySuggestionSelect({ value: q }) {
243
- if (!q) {
244
- return;
245
- }
246
- // backward compatible: query on current workflow
247
- this.query({ q, qs: QUESTION_SOURCE.SUGGESTED_QUESTIONS });
248
- }
249
-
250
- // helpers //
251
- _writeQuestionId(questionId) {
252
- // capture question ID and register at context
253
- if (!this._questionId && questionId) {
254
- this._questionId = questionId;
255
- this._context._byQid.set(questionId, this);
256
- }
257
- }
258
-
259
- _clearQuestionId() {
260
- // clear question id from previous session
261
- if (this._questionId) {
262
- this._context._byQid.delete(this._questionId);
263
- this._questionId = undefined;
264
- }
265
- }
266
-
267
- // destroy //
268
- _destroy(options) {
269
- const { next, parentQuestionId, questionId } = this;
270
- if (next) {
271
- next.destroy(options);
272
- }
273
- if (parentQuestionId) {
274
- this._context._byPqid.delete(parentQuestionId);
275
- }
276
- if (questionId) {
277
- this._context._byQid.delete(questionId);
278
- }
279
- super._destroy(options);
280
- }
281
-
282
- }
283
-
284
- makeAutocompletable(Ask.prototype);