@miso.ai/client-sdk-ui 1.13.2-beta.1 → 1.14.0-beta.3

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 (226) hide show
  1. package/dist/cjs/asset/svgs.js +17 -4
  2. package/dist/cjs/combo/ask/index.js +2 -2
  3. package/dist/cjs/constants.js +120 -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 +259 -0
  7. package/dist/cjs/element/container/index.js +28 -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-message-item.js +91 -0
  14. package/dist/cjs/element/container/miso-recommendation.js +1 -1
  15. package/dist/cjs/element/container/miso-search.js +1 -1
  16. package/dist/cjs/element/container/miso-thread-item.js +91 -0
  17. package/dist/cjs/element/context/miso-follow-ups.js +1 -1
  18. package/dist/cjs/element/role/index.js +49 -0
  19. package/dist/cjs/element/role/miso-delete.js +20 -0
  20. package/dist/cjs/element/role/miso-messages.js +20 -0
  21. package/dist/cjs/element/role/miso-new-thread.js +20 -0
  22. package/dist/cjs/element/role/miso-rename.js +20 -0
  23. package/dist/cjs/element/role/miso-subscription.js +20 -0
  24. package/dist/cjs/element/role/miso-threads.js +20 -0
  25. package/dist/cjs/element/role/miso-title.js +20 -0
  26. package/dist/cjs/layout/affiliation/affiliation.js +1 -1
  27. package/dist/cjs/layout/banner/banner.js +2 -1
  28. package/dist/cjs/layout/button/button.js +170 -0
  29. package/dist/cjs/layout/button/checkbox.js +116 -0
  30. package/dist/cjs/layout/button/more-button.js +3 -3
  31. package/dist/cjs/layout/container/container.js +1 -1
  32. package/dist/cjs/layout/container/item-container.js +99 -0
  33. package/dist/cjs/layout/error/error.js +2 -1
  34. package/dist/cjs/layout/index.js +42 -0
  35. package/dist/cjs/layout/input/facets.js +4 -3
  36. package/dist/cjs/layout/input/option-list.js +3 -2
  37. package/dist/cjs/layout/input/search-box.js +50 -12
  38. package/dist/cjs/layout/input/select.js +2 -1
  39. package/dist/cjs/layout/list/cards.js +2 -1
  40. package/dist/cjs/layout/list/carousel.js +2 -1
  41. package/dist/cjs/layout/list/collection.js +13 -1
  42. package/dist/cjs/layout/list/gallery.js +2 -1
  43. package/dist/cjs/layout/list/horizontal.js +2 -1
  44. package/dist/cjs/layout/list/list.js +2 -1
  45. package/dist/cjs/layout/list/messages.js +359 -0
  46. package/dist/cjs/layout/list/threads.js +199 -0
  47. package/dist/cjs/layout/mixin/trackable.js +4 -5
  48. package/dist/cjs/layout/mixin/triggerable.js +2 -2
  49. package/dist/cjs/layout/radio/feedback.js +4 -3
  50. package/dist/cjs/layout/templates.js +97 -0
  51. package/dist/cjs/layout/text/question.js +71 -0
  52. package/dist/cjs/layout/text/text.js +2 -1
  53. package/dist/cjs/layout/text/typewriter/index.js +18 -23
  54. package/dist/cjs/plugin.js +43 -104
  55. package/dist/cjs/util/confirm.js +33 -0
  56. package/dist/cjs/util/dom.js +21 -0
  57. package/dist/cjs/util/modal.js +48 -0
  58. package/dist/cjs/util/prompt.js +47 -0
  59. package/dist/cjs/version.js +1 -1
  60. package/package.json +5 -4
  61. package/src/CLAUDE.md +51 -104
  62. package/src/asset/svgs.js +16 -3
  63. package/src/combo/ask/index.js +2 -2
  64. package/src/constants.js +39 -147
  65. package/src/defaults/ask/controls.js +1 -1
  66. package/src/defaults/hybrid-search/answer-box.js +2 -2
  67. package/src/defaults.js +174 -0
  68. package/src/element/container/index.js +4 -0
  69. package/src/element/container/miso-ask.js +3 -3
  70. package/src/element/container/miso-conversation.js +19 -0
  71. package/src/element/container/miso-explore.js +1 -1
  72. package/src/element/container/miso-history.js +19 -0
  73. package/src/element/container/miso-hybrid-search.js +1 -1
  74. package/src/element/container/miso-message-item.js +94 -0
  75. package/src/element/container/miso-recommendation.js +1 -1
  76. package/src/element/container/miso-search.js +1 -1
  77. package/src/element/container/miso-thread-item.js +94 -0
  78. package/src/element/context/miso-follow-ups.js +1 -1
  79. package/src/element/role/index.js +7 -0
  80. package/src/element/role/miso-delete.js +16 -0
  81. package/src/element/role/miso-messages.js +16 -0
  82. package/src/element/role/miso-new-thread.js +16 -0
  83. package/src/element/role/miso-rename.js +16 -0
  84. package/src/element/role/miso-subscription.js +16 -0
  85. package/src/element/role/miso-threads.js +16 -0
  86. package/src/element/role/miso-title.js +16 -0
  87. package/src/layout/affiliation/affiliation.js +2 -2
  88. package/src/layout/banner/banner.js +2 -1
  89. package/src/layout/button/button.js +152 -0
  90. package/src/layout/button/checkbox.js +92 -0
  91. package/src/layout/button/more-button.js +3 -3
  92. package/src/layout/container/container.js +2 -2
  93. package/src/layout/container/item-container.js +99 -0
  94. package/src/layout/error/error.js +2 -1
  95. package/src/layout/index.js +6 -0
  96. package/src/layout/input/facets.js +3 -2
  97. package/src/layout/input/option-list.js +3 -2
  98. package/src/layout/input/search-box.js +45 -8
  99. package/src/layout/input/select.js +2 -1
  100. package/src/layout/list/cards.js +2 -1
  101. package/src/layout/list/carousel.js +2 -1
  102. package/src/layout/list/collection.js +15 -2
  103. package/src/layout/list/gallery.js +2 -1
  104. package/src/layout/list/horizontal.js +2 -1
  105. package/src/layout/list/list.js +2 -1
  106. package/src/layout/list/messages.js +316 -0
  107. package/src/layout/list/threads.js +166 -0
  108. package/src/layout/mixin/trackable.js +2 -3
  109. package/src/layout/mixin/triggerable.js +1 -1
  110. package/src/layout/radio/feedback.js +3 -2
  111. package/src/layout/templates.js +97 -0
  112. package/src/layout/text/question.js +58 -0
  113. package/src/layout/text/text.js +2 -1
  114. package/src/layout/text/typewriter/index.js +15 -18
  115. package/src/plugin.js +31 -117
  116. package/src/util/confirm.js +28 -0
  117. package/src/util/dom.js +16 -0
  118. package/src/util/modal.js +49 -0
  119. package/src/util/prompt.js +42 -0
  120. package/src/version.js +1 -1
  121. package/dist/cjs/actor/data.js +0 -132
  122. package/dist/cjs/actor/feedback.js +0 -29
  123. package/dist/cjs/actor/fields.js +0 -57
  124. package/dist/cjs/actor/filters.js +0 -161
  125. package/dist/cjs/actor/hub.js +0 -57
  126. package/dist/cjs/actor/index.js +0 -73
  127. package/dist/cjs/actor/interactions.js +0 -36
  128. package/dist/cjs/actor/sessions.js +0 -25
  129. package/dist/cjs/actor/tracker-states.js +0 -61
  130. package/dist/cjs/actor/tracker.js +0 -109
  131. package/dist/cjs/actor/trackers.js +0 -52
  132. package/dist/cjs/actor/utils.js +0 -15
  133. package/dist/cjs/actor/view.js +0 -294
  134. package/dist/cjs/actor/views.js +0 -209
  135. package/dist/cjs/source.js +0 -27
  136. package/dist/cjs/util/proxy.js +0 -88
  137. package/dist/cjs/util/trackers.js +0 -88
  138. package/dist/cjs/workflow/affiliations.js +0 -140
  139. package/dist/cjs/workflow/answer-based.js +0 -337
  140. package/dist/cjs/workflow/ask.js +0 -319
  141. package/dist/cjs/workflow/asks.js +0 -150
  142. package/dist/cjs/workflow/autocompletable.js +0 -63
  143. package/dist/cjs/workflow/autocomplete.js +0 -120
  144. package/dist/cjs/workflow/base.js +0 -418
  145. package/dist/cjs/workflow/context.js +0 -19
  146. package/dist/cjs/workflow/explore.js +0 -210
  147. package/dist/cjs/workflow/explores.js +0 -21
  148. package/dist/cjs/workflow/hybrid-search-answer.js +0 -88
  149. package/dist/cjs/workflow/hybrid-search-views.js +0 -109
  150. package/dist/cjs/workflow/hybrid-search.js +0 -213
  151. package/dist/cjs/workflow/index.js +0 -41
  152. package/dist/cjs/workflow/options/api.js +0 -41
  153. package/dist/cjs/workflow/options/auto-query.js +0 -97
  154. package/dist/cjs/workflow/options/configurable.js +0 -45
  155. package/dist/cjs/workflow/options/data-processor.js +0 -20
  156. package/dist/cjs/workflow/options/filters.js +0 -15
  157. package/dist/cjs/workflow/options/index.js +0 -126
  158. package/dist/cjs/workflow/options/interactions.js +0 -41
  159. package/dist/cjs/workflow/options/layouts.js +0 -79
  160. package/dist/cjs/workflow/options/options.js +0 -156
  161. package/dist/cjs/workflow/options/pagination.js +0 -25
  162. package/dist/cjs/workflow/options/roles.js +0 -15
  163. package/dist/cjs/workflow/options/templates.js +0 -30
  164. package/dist/cjs/workflow/options/trackers.js +0 -83
  165. package/dist/cjs/workflow/options/utils.js +0 -33
  166. package/dist/cjs/workflow/processors.js +0 -607
  167. package/dist/cjs/workflow/recommendation.js +0 -57
  168. package/dist/cjs/workflow/recommendations.js +0 -18
  169. package/dist/cjs/workflow/search-based.js +0 -337
  170. package/dist/cjs/workflow/search.js +0 -64
  171. package/dist/cjs/workflow/unit.js +0 -57
  172. package/dist/cjs/workflow/units.js +0 -42
  173. package/dist/cjs/workflow/use-link.js +0 -49
  174. package/src/actor/data.js +0 -106
  175. package/src/actor/feedback.js +0 -28
  176. package/src/actor/fields.js +0 -51
  177. package/src/actor/filters.js +0 -149
  178. package/src/actor/hub.js +0 -47
  179. package/src/actor/index.js +0 -10
  180. package/src/actor/interactions.js +0 -32
  181. package/src/actor/sessions.js +0 -21
  182. package/src/actor/tracker-states.js +0 -57
  183. package/src/actor/tracker.js +0 -104
  184. package/src/actor/trackers.js +0 -45
  185. package/src/actor/utils.js +0 -7
  186. package/src/actor/view.js +0 -272
  187. package/src/actor/views.js +0 -224
  188. package/src/source.js +0 -17
  189. package/src/util/proxy.js +0 -81
  190. package/src/util/trackers.js +0 -84
  191. package/src/workflow/affiliations.js +0 -121
  192. package/src/workflow/answer-based.js +0 -312
  193. package/src/workflow/ask.js +0 -284
  194. package/src/workflow/asks.js +0 -143
  195. package/src/workflow/autocompletable.js +0 -67
  196. package/src/workflow/autocomplete.js +0 -114
  197. package/src/workflow/base.js +0 -396
  198. package/src/workflow/context.js +0 -16
  199. package/src/workflow/explore.js +0 -194
  200. package/src/workflow/explores.js +0 -18
  201. package/src/workflow/hybrid-search-answer.js +0 -73
  202. package/src/workflow/hybrid-search-views.js +0 -116
  203. package/src/workflow/hybrid-search.js +0 -230
  204. package/src/workflow/index.js +0 -5
  205. package/src/workflow/options/api.js +0 -31
  206. package/src/workflow/options/auto-query.js +0 -70
  207. package/src/workflow/options/configurable.js +0 -48
  208. package/src/workflow/options/data-processor.js +0 -15
  209. package/src/workflow/options/filters.js +0 -10
  210. package/src/workflow/options/index.js +0 -11
  211. package/src/workflow/options/interactions.js +0 -36
  212. package/src/workflow/options/layouts.js +0 -73
  213. package/src/workflow/options/options.js +0 -175
  214. package/src/workflow/options/pagination.js +0 -18
  215. package/src/workflow/options/roles.js +0 -12
  216. package/src/workflow/options/templates.js +0 -27
  217. package/src/workflow/options/trackers.js +0 -80
  218. package/src/workflow/options/utils.js +0 -26
  219. package/src/workflow/processors.js +0 -490
  220. package/src/workflow/recommendation.js +0 -63
  221. package/src/workflow/recommendations.js +0 -14
  222. package/src/workflow/search-based.js +0 -329
  223. package/src/workflow/search.js +0 -73
  224. package/src/workflow/unit.js +0 -51
  225. package/src/workflow/units.js +0 -43
  226. 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);