@envive-ai/react-hooks 0.2.6-alpha-arthur-3 → 0.2.6-alpha-arthur-4

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 (249) hide show
  1. package/dist/{AmplitudeOperations-BjC8DOqm.js → AmplitudeOperations-BNFYCh-W.js} +2 -2
  2. package/dist/{AmplitudeOperations-CQs4sVHN.cjs → AmplitudeOperations-CHlghWFQ.cjs} +2 -2
  3. package/dist/{NewOrgConfig-CRakarmw.js → NewOrgConfig-BeoqDaSB.js} +2 -2
  4. package/dist/{NewOrgConfig-D48KabOj.cjs → NewOrgConfig-DgWHQyUc.cjs} +2 -2
  5. package/dist/{TrackComponentVisibleEvent-C9RvfdS9.js → TrackComponentVisibleEvent-HbfzgXtF.js} +4 -4
  6. package/dist/{TrackComponentVisibleEvent-_Fb-JXkV.cjs → TrackComponentVisibleEvent-vsaQaHKi.cjs} +4 -4
  7. package/dist/amplitudeContext-Dp-Tm43M.cjs +253 -0
  8. package/dist/amplitudeContext-DwszOulA.js +237 -0
  9. package/dist/{amplitudeTrackEventAtom-f22P2U0u.cjs → amplitudeTrackEventAtom-nkZxYoLu.cjs} +1 -1
  10. package/dist/{amplitudeTrackEventAtom-D66l5oFp.js → amplitudeTrackEventAtom-pJbLG4En.js} +1 -1
  11. package/dist/app-BCuEBoPJ.cjs +36 -0
  12. package/dist/app-D73Rksby.js +14 -0
  13. package/dist/application/models/graphql/index.d.ts +1 -1
  14. package/dist/application/models/guards/api/index.d.ts +2 -2
  15. package/dist/application/models/guards/utils.d.ts +1 -1
  16. package/dist/application/models/index.cjs +2 -2
  17. package/dist/application/models/index.d.ts +4 -4
  18. package/dist/application/models/index.js +2 -2
  19. package/dist/application/utils/index.cjs +3 -3
  20. package/dist/application/utils/index.d.ts +4 -4
  21. package/dist/application/utils/index.js +3 -3
  22. package/dist/atoms/app/index.cjs +5 -17
  23. package/dist/atoms/app/index.d.cts +7 -8
  24. package/dist/atoms/app/index.d.ts +7 -8
  25. package/dist/atoms/app/index.js +5 -16
  26. package/dist/atoms/atomStore/index.d.cts +1 -1
  27. package/dist/atoms/chat/index.cjs +14 -11
  28. package/dist/atoms/chat/index.d.ts +33 -33
  29. package/dist/atoms/chat/index.js +14 -11
  30. package/dist/atoms/globalSearch/index.cjs +1 -1
  31. package/dist/atoms/globalSearch/index.d.cts +6 -6
  32. package/dist/atoms/globalSearch/index.d.ts +6 -6
  33. package/dist/atoms/globalSearch/index.js +1 -1
  34. package/dist/atoms/org/index.cjs +7 -6
  35. package/dist/atoms/org/index.d.cts +16 -16
  36. package/dist/atoms/org/index.d.ts +17 -17
  37. package/dist/atoms/org/index.js +3 -2
  38. package/dist/atoms/search/index.cjs +7 -6
  39. package/dist/atoms/search/index.d.cts +14 -14
  40. package/dist/atoms/search/index.d.ts +15 -15
  41. package/dist/atoms/search/index.js +7 -6
  42. package/dist/atoms/search/utils.cjs +1 -1
  43. package/dist/atoms/search/utils.d.cts +1 -1
  44. package/dist/atoms/search/utils.d.ts +1 -1
  45. package/dist/atoms/search/utils.js +1 -1
  46. package/dist/{cdnContext-BoPraJxf.cjs → cdnContext-Bs73r4Xd.cjs} +2 -2
  47. package/dist/{cdnContext-BJT_Wn9Z.js → cdnContext-DJ1pDg-l.js} +2 -2
  48. package/dist/chat-BqUkaIbS.js +226 -0
  49. package/dist/chat-zxjIy0qQ.cjs +326 -0
  50. package/dist/{chatState-DlJpHAsW.cjs → chatState-CMoQ1TMs.cjs} +2 -2
  51. package/dist/{chatState-BbI93m6r.js → chatState-DRJrYuno.js} +2 -2
  52. package/dist/config/index.d.ts +4 -4
  53. package/dist/config/locators/components/chat/index.d.ts +1 -1
  54. package/dist/config/locators/components/common/index.d.ts +1 -1
  55. package/dist/config/locators/components/index.d.ts +1 -1
  56. package/dist/config/locators/components/search/index.d.cts +1 -1
  57. package/dist/config/locators/index.d.ts +4 -4
  58. package/dist/contexts/amplitudeContext/index.cjs +7 -19
  59. package/dist/contexts/amplitudeContext/index.js +7 -19
  60. package/dist/contexts/cdnContext/index.cjs +3 -3
  61. package/dist/contexts/cdnContext/index.js +3 -3
  62. package/dist/contexts/enviveConfigContext/index.cjs +4 -4
  63. package/dist/contexts/enviveConfigContext/index.js +4 -4
  64. package/dist/contexts/enviveCssContext/index.cjs +12 -12
  65. package/dist/contexts/enviveCssContext/index.js +12 -12
  66. package/dist/contexts/featureFlagContext/index.cjs +4 -4
  67. package/dist/contexts/featureFlagContext/index.js +4 -4
  68. package/dist/contexts/featureFlagServiceContext/index.cjs +3 -3
  69. package/dist/contexts/featureFlagServiceContext/index.d.ts +1 -1
  70. package/dist/contexts/featureFlagServiceContext/index.js +3 -3
  71. package/dist/contexts/graphqlContext/index.cjs +6 -6
  72. package/dist/contexts/graphqlContext/index.d.cts +1 -1
  73. package/dist/contexts/graphqlContext/index.js +6 -6
  74. package/dist/contexts/localStorageContext/index.cjs +2 -2
  75. package/dist/contexts/localStorageContext/index.d.cts +1 -1
  76. package/dist/contexts/localStorageContext/index.js +2 -2
  77. package/dist/contexts/newOrgConfigContext/index.cjs +11 -11
  78. package/dist/contexts/newOrgConfigContext/index.js +11 -11
  79. package/dist/contexts/searchContext/index.cjs +18 -15
  80. package/dist/contexts/searchContext/index.js +18 -15
  81. package/dist/contexts/sessionStorageContext/index.cjs +1 -1
  82. package/dist/contexts/sessionStorageContext/index.js +1 -1
  83. package/dist/contexts/shopifyUrlContext/index.cjs +1 -1
  84. package/dist/contexts/shopifyUrlContext/index.d.cts +1 -1
  85. package/dist/contexts/shopifyUrlContext/index.js +1 -1
  86. package/dist/contexts/systemSettingsContext/index.cjs +3 -3
  87. package/dist/contexts/systemSettingsContext/index.d.cts +2 -2
  88. package/dist/contexts/systemSettingsContext/index.d.ts +2 -2
  89. package/dist/contexts/systemSettingsContext/index.js +3 -3
  90. package/dist/contexts/userIdentityContext/index.cjs +13 -10
  91. package/dist/contexts/userIdentityContext/index.d.ts +1 -1
  92. package/dist/contexts/userIdentityContext/index.js +11 -8
  93. package/dist/{dist-VxRI6eQv.cjs → dist-B7BErEyV.cjs} +1 -1
  94. package/dist/{dist-C38adNK1.js → dist-CtkINi1R.js} +1 -1
  95. package/dist/{enviveConfig-CHXb9xwk.cjs → enviveConfig-6XJa6HAF.cjs} +2 -2
  96. package/dist/{enviveConfig-CUJgI97-.js → enviveConfig-Cw7o9TLb.js} +2 -2
  97. package/dist/{enviveConfigContext-C91Air9z.js → enviveConfigContext-D_bCeK56.js} +2 -2
  98. package/dist/{enviveConfigContext-zZAJwv87.cjs → enviveConfigContext-DoBbJZp_.cjs} +2 -2
  99. package/dist/exceptions/index.d.cts +1 -1
  100. package/dist/exceptions/index.d.ts +1 -1
  101. package/dist/{featureFlagServiceContext-x-hAAKdL.d.ts → featureFlagServiceContext-C6nTNI_i.d.ts} +1 -1
  102. package/dist/featureFlagServiceContext-ClnlCJV5.d.cts +1 -1
  103. package/dist/{featureFlagServiceContext-DHtkQAtq.cjs → featureFlagServiceContext-DQYo0d6Q.cjs} +2 -2
  104. package/dist/{featureFlagServiceContext-Cvp7NlpC.js → featureFlagServiceContext-GIO9xKV0.js} +2 -2
  105. package/dist/{globalSearch-nmrfGLOn.js → globalSearch-B8jHLScz.js} +1 -1
  106. package/dist/{globalSearch-Cpc8egsM.cjs → globalSearch-JJI1Fijh.cjs} +1 -1
  107. package/dist/{graphqlContext-DqWvz7Op.cjs → graphqlContext-CXyZamIk.cjs} +3 -3
  108. package/dist/{graphqlContext-C3T_K97L.js → graphqlContext-cAZtpn-W.js} +3 -3
  109. package/dist/hooks/AmplitudeOperations/index.cjs +8 -20
  110. package/dist/hooks/AmplitudeOperations/index.js +8 -20
  111. package/dist/hooks/AppDetails/index.cjs +16 -13
  112. package/dist/hooks/AppDetails/index.d.cts +12 -3
  113. package/dist/hooks/AppDetails/index.d.ts +12 -3
  114. package/dist/hooks/AppDetails/index.js +16 -13
  115. package/dist/hooks/BlockBackButton/index.d.ts +1 -1
  116. package/dist/hooks/CdnOperations/index.cjs +3 -3
  117. package/dist/hooks/CdnOperations/index.js +3 -3
  118. package/dist/hooks/ChatToggle/index.cjs +18 -15
  119. package/dist/hooks/ChatToggle/index.d.cts +1 -1
  120. package/dist/hooks/ChatToggle/index.js +18 -15
  121. package/dist/hooks/ChatToggleAnalytics/index.cjs +10 -22
  122. package/dist/hooks/ChatToggleAnalytics/index.d.cts +1 -1
  123. package/dist/hooks/ChatToggleAnalytics/index.js +10 -22
  124. package/dist/hooks/CustomerSupportHandoff/index.d.cts +1 -1
  125. package/dist/hooks/Debounce/index.d.cts +1 -1
  126. package/dist/hooks/Debounce/index.d.ts +1 -1
  127. package/dist/hooks/ElementObserver/index.d.ts +1 -1
  128. package/dist/hooks/GrabAndScroll/index.d.cts +1 -1
  129. package/dist/hooks/GrabAndScroll/index.d.ts +2 -2
  130. package/dist/hooks/GraphQLConfig/index.cjs +7 -7
  131. package/dist/hooks/GraphQLConfig/index.js +7 -7
  132. package/dist/hooks/IdentifyUser/index.cjs +13 -10
  133. package/dist/hooks/IdentifyUser/index.js +12 -9
  134. package/dist/hooks/ImageResolver/index.cjs +2 -2
  135. package/dist/hooks/ImageResolver/index.js +2 -2
  136. package/dist/hooks/Intersection/index.cjs +1 -1
  137. package/dist/hooks/Intersection/index.d.ts +1 -1
  138. package/dist/hooks/Intersection/index.js +1 -1
  139. package/dist/hooks/IsSmallScreen/index.d.ts +1 -1
  140. package/dist/hooks/LocalStorageOperations/index.cjs +2 -2
  141. package/dist/hooks/LocalStorageOperations/index.d.cts +1 -1
  142. package/dist/hooks/LocalStorageOperations/index.js +2 -2
  143. package/dist/hooks/MessageFilter/index.cjs +1 -1
  144. package/dist/hooks/MessageFilter/index.d.cts +1 -1
  145. package/dist/hooks/MessageFilter/index.js +1 -1
  146. package/dist/hooks/NewOrgConfig/index.cjs +12 -12
  147. package/dist/hooks/NewOrgConfig/index.d.ts +2 -2
  148. package/dist/hooks/NewOrgConfig/index.js +12 -12
  149. package/dist/hooks/Search/index.cjs +19 -29
  150. package/dist/hooks/Search/index.d.cts +1 -1
  151. package/dist/hooks/Search/index.js +18 -28
  152. package/dist/hooks/SearchOperations/index.cjs +19 -16
  153. package/dist/hooks/SearchOperations/index.d.cts +1 -1
  154. package/dist/hooks/SearchOperations/index.js +19 -16
  155. package/dist/hooks/SessionStorageOperations/index.cjs +1 -1
  156. package/dist/hooks/SessionStorageOperations/index.js +1 -1
  157. package/dist/hooks/ShopifyUrlOperations/index.cjs +1 -1
  158. package/dist/hooks/ShopifyUrlOperations/index.d.cts +2 -2
  159. package/dist/hooks/ShopifyUrlOperations/index.d.ts +2 -2
  160. package/dist/hooks/ShopifyUrlOperations/index.js +1 -1
  161. package/dist/hooks/SystemSettingsContext/index.cjs +3 -3
  162. package/dist/hooks/SystemSettingsContext/index.d.cts +2 -2
  163. package/dist/hooks/SystemSettingsContext/index.d.ts +3 -3
  164. package/dist/hooks/SystemSettingsContext/index.js +3 -3
  165. package/dist/hooks/TrackComponentVisibleEvent/index.cjs +9 -21
  166. package/dist/hooks/TrackComponentVisibleEvent/index.js +9 -21
  167. package/dist/hooks/UpdateAnalyticsProps/index.cjs +11 -21
  168. package/dist/hooks/UpdateAnalyticsProps/index.js +9 -19
  169. package/dist/hooks/utils.cjs +1 -1
  170. package/dist/hooks/utils.d.ts +1 -1
  171. package/dist/hooks/utils.js +1 -1
  172. package/dist/index-CMZcE7pk.d.cts +1 -1
  173. package/dist/{index-BiDHHLjr.d.ts → index-ChRMX2kc.d.ts} +2 -2
  174. package/dist/index-ChiZg0yw.d.cts +1 -1
  175. package/dist/{index-dc4j0jws.d.ts → index-CkaLTFlB.d.ts} +1 -1
  176. package/dist/{index-DywcCZdp.d.ts → index-Cl35ht05.d.ts} +1 -1
  177. package/dist/{index-B95cXAA4.d.ts → index-DIq5F_-r.d.ts} +1 -1
  178. package/dist/{index-DZU7c0jP.d.ts → index-DijHU7yp.d.ts} +1 -1
  179. package/dist/{index-CAXM2KiM.d.ts → index-PktRD1En.d.ts} +1 -1
  180. package/dist/index-npqPeJ1g.d.cts +1 -1
  181. package/dist/{index--OKiRCTl.d.ts → index-smzckpKv.d.ts} +1 -1
  182. package/dist/interceptors/index.cjs +1 -1
  183. package/dist/interceptors/index.d.cts +1 -1
  184. package/dist/interceptors/index.d.ts +1 -1
  185. package/dist/interceptors/index.js +1 -1
  186. package/dist/{localStorageContext-BFwvuEcf.js → localStorageContext-CvwraLEo.js} +2 -2
  187. package/dist/{localStorageContext-CWc5xJ6U.cjs → localStorageContext-DIIUUEvL.cjs} +2 -2
  188. package/dist/{models-Cw0QcbQv.js → models-DmsMlaHT.js} +2 -2
  189. package/dist/{models-Dl0_Ujgj.cjs → models-wh2gh_Qz.cjs} +2 -2
  190. package/dist/{newOrgConfigAtom-CDttTiuu.cjs → newOrgConfigAtom-vEChAMrW.cjs} +1 -1
  191. package/dist/{newOrgConfigAtom-C8h3w_Ji.js → newOrgConfigAtom-wQeGYEFq.js} +1 -1
  192. package/dist/{newOrgConfigContext-D1sgTmVU.cjs → newOrgConfigContext-C8uWGgkE.cjs} +5 -5
  193. package/dist/{newOrgConfigContext-B_rJMpwN.js → newOrgConfigContext-garCXaH1.js} +5 -5
  194. package/dist/{nodeSelector-NqW-FBED.d.ts → nodeSelector-DU-o1I1d.d.ts} +1 -1
  195. package/dist/org-DEzeBBk6.js +22 -0
  196. package/dist/org-Ky10pcuq.cjs +77 -0
  197. package/dist/orgAnalyticsConfig-Bxm8BZch.js +14 -0
  198. package/dist/orgAnalyticsConfig-DU1aESDh.cjs +39 -0
  199. package/dist/{search-OWKKaQQj.js → search-C4ZLnfzE.js} +5 -5
  200. package/dist/{search-CWkDtqQV.cjs → search-DUJiAeEo.cjs} +5 -5
  201. package/dist/{searchContext-Bhhp_q_P.js → searchContext-BrPSGjRo.js} +5 -5
  202. package/dist/{searchContext-3VsAb17A.cjs → searchContext-Ck94DuBO.cjs} +5 -5
  203. package/dist/{searchServiceAdapter-B0h7psvh.js → searchServiceAdapter-C3_FRUly.js} +1 -1
  204. package/dist/{searchServiceAdapter-BclWy4fE.cjs → searchServiceAdapter-tPd0NClV.cjs} +1 -1
  205. package/dist/{sessionStorageContext-kQJRbkHL.js → sessionStorageContext-CBwNI1Va.js} +1 -1
  206. package/dist/{sessionStorageContext-L3f_btsR.cjs → sessionStorageContext-CmHIsV7a.cjs} +1 -1
  207. package/dist/{shopifyUrlContext-CB9LQU_i.js → shopifyUrlContext-C3gw4ZIN.js} +1 -1
  208. package/dist/{shopifyUrlContext-BsYGfLvw.cjs → shopifyUrlContext-ZJtT_0XX.cjs} +1 -1
  209. package/dist/{systemSettingsContext-Cac6mmfA.js → systemSettingsContext-DzAyy0iP.js} +2 -2
  210. package/dist/{systemSettingsContext-B5plhu8S.cjs → systemSettingsContext-ru4nA9k_.cjs} +2 -2
  211. package/dist/types/index.d.ts +1 -1
  212. package/dist/useAppDetails-Bg1yCUZi.cjs +41 -0
  213. package/dist/useAppDetails-Buzm9yIj.js +33 -0
  214. package/dist/{useGraphQLConfig-Cm_lEb1T.cjs → useGraphQLConfig-B6CiGP57.cjs} +2 -2
  215. package/dist/{useGraphQLConfig-CeYY5maa.js → useGraphQLConfig-f2MK-FPn.js} +2 -2
  216. package/dist/{useIntersection-bCSteycU.js → useIntersection-UEO0Cezc.js} +1 -1
  217. package/dist/{useIntersection-DuwPFRY9.cjs → useIntersection-rV0Q8mBH.cjs} +1 -1
  218. package/dist/userIdentityContext-B8XLgxMQ.cjs +431 -0
  219. package/dist/userIdentityContext-DgFLendI.js +414 -0
  220. package/dist/{utils-DjhLO2vO.d.ts → utils-BLe5oreh.d.ts} +1 -1
  221. package/dist/{utils-DQhbbAnt.js → utils-B_cnJJAH.js} +1 -1
  222. package/dist/{utils-DMwh3QbT.js → utils-CxDOv-yL.js} +3 -3
  223. package/dist/{utils-BZT_oZ3n.js → utils-D_kATUj6.js} +1 -1
  224. package/dist/{utils-D3MjNkd3.cjs → utils-DucG4gQ7.cjs} +3 -3
  225. package/dist/{utils-CqVRbvfN.cjs → utils-_Q_-LvZS.cjs} +1 -1
  226. package/dist/{utils-qtHPLFby.cjs → utils-hYTjy7hJ.cjs} +1 -1
  227. package/dist/variant-Ben5gKtM.js +93 -0
  228. package/dist/variant-CvYVVCqU.cjs +107 -0
  229. package/package.json +1 -1
  230. package/src/application/commerce-api.ts +5 -2
  231. package/src/atoms/app/index.ts +2 -20
  232. package/src/atoms/chat/messageQueue.ts +8 -3
  233. package/src/contexts/amplitudeContext/amplitudeContext.tsx +2 -2
  234. package/src/contexts/chatContext/chatContext.tsx +512 -0
  235. package/src/hooks/AppDetails/useAppDetails.ts +15 -2
  236. package/dist/amplitudeContext-D5HSmIWg.cjs +0 -253
  237. package/dist/amplitudeContext-wW37Ziq-.js +0 -237
  238. package/dist/app-CGw4C9Bn.js +0 -515
  239. package/dist/app-Di_sBmzj.cjs +0 -570
  240. package/dist/chat-ZaY3KY-R.js +0 -226
  241. package/dist/chat-rhEjVfrd.cjs +0 -326
  242. package/dist/org-BNs_maoW.cjs +0 -111
  243. package/dist/org-CScQqL4k.js +0 -32
  244. package/dist/useAppDetails-B-lZpIPK.js +0 -30
  245. package/dist/useAppDetails-BAJjqvyF.cjs +0 -38
  246. /package/dist/{enviveConfigContext-CZPfJkcS.cjs → enviveConfigContext-DJLIdWAK.cjs} +0 -0
  247. /package/dist/{enviveConfigContext-Hc1JBLu-.js → enviveConfigContext-Qh6nF9qc.js} +0 -0
  248. /package/dist/{featureFlagServiceContext-CISyb90N.js → featureFlagServiceContext-CG3rFJov.js} +0 -0
  249. /package/dist/{featureFlagServiceContext-Csgo-MUv.cjs → featureFlagServiceContext-C_wrr2WY.cjs} +0 -0
@@ -0,0 +1,512 @@
1
+ import { UserEventCategory } from "@spiffy-ai/commerce-api-client";
2
+ import { useAtom, useAtomValue, useSetAtom } from "jotai";
3
+ import {
4
+ createContext,
5
+ useEffect,
6
+ useState,
7
+ ReactNode,
8
+ useCallback,
9
+ useMemo,
10
+ } from "react";
11
+ import CommerceApiClient from "src/application/commerce-api";
12
+ import { v4 as uuid } from "uuid";
13
+ import { SessionRestartRequired } from "src/types/exceptions/sessionExceptions";
14
+ import Logger from "src/application/logging/logger";
15
+ import {
16
+ Message,
17
+ MessageRole,
18
+ MessageType,
19
+ NextMessageRequest,
20
+ Response,
21
+ } from "src/application/models";
22
+ import { SpiffyMetricsEventName } from "src/contexts/amplitudeContext/amplitudeContext";
23
+ import { messageFromResponse } from "src/application/utils";
24
+ import { chatIdAtom, variantInfoAtom } from "src/atoms/app";
25
+ import {
26
+ messagesAtom,
27
+ requestFailureAtom,
28
+ responseStreamingAtom,
29
+ userHasRepliedAtom,
30
+ PerfMetricsEvents,
31
+ logPerfMetricAtom,
32
+ userEventsAtom,
33
+ suggestionsLoadingAtom,
34
+ suggestionsAtom,
35
+ } from "src/atoms/chat";
36
+ import {
37
+ chatSearchProductSortingAtom,
38
+ chatSearchProducts,
39
+ chatSearchStateAtom,
40
+ handleSearchResultsAtom,
41
+ chatSearchIsLoadingAtom,
42
+ } from "src/atoms/search/chatSearch";
43
+ import { createAppLoadedEvent, createVisitUserEvent } from "src/hooks/utils";
44
+ import { useMessageInterceptor } from "src/interceptors/useMessageInterceptor";
45
+ import { supportedEventAtom } from "src/atoms/app/variant";
46
+ import { chatAtom } from "src/atoms/chat";
47
+ import { getAtomStore } from "src/atoms/atomStore";
48
+ import {
49
+ clearUserEventAtom,
50
+ createResponsePayload,
51
+ processUserEventAtom,
52
+ userEventQueueAtom,
53
+ userQueueEventCountAtom,
54
+ } from "src/atoms/chat/messageQueue";
55
+ import { useAmplitudeTracking } from "src/hooks/AmplitudeOperations/useAmplitudeOperations";
56
+ import { useSystemSettingsContext } from "src/hooks/SystemSettingsContext";
57
+ import { useUserIdentity } from "../userIdentityContext";
58
+
59
+ /**
60
+ * Record the chat assistant response in Amplitude
61
+ *
62
+ * @param startTimeMs The start time of the assistant response
63
+ * @param payload The payload used to generate the response
64
+ */
65
+ const recordAssistantResponse = (
66
+ startTimeMs: number,
67
+ payload: NextMessageRequest,
68
+ track: (
69
+ eventName: SpiffyMetricsEventName,
70
+ eventProps?: Record<string, unknown>
71
+ ) => void
72
+ ) => {
73
+ const atomStore = getAtomStore();
74
+ const chatState = atomStore.get(chatAtom);
75
+ const chatSearchState = atomStore.get(chatSearchStateAtom);
76
+ const searchProducts = atomStore.get(chatSearchProducts);
77
+ const searchProductsSort = atomStore.get(chatSearchProductSortingAtom);
78
+ const assistantResponseTimeMs = { start: startTimeMs, end: Date.now() };
79
+ let userQueryProperty: string | undefined;
80
+
81
+ if (
82
+ chatState.replyEventCategory === UserEventCategory.SuggestionClicked &&
83
+ chatState.suggestion
84
+ ) {
85
+ userQueryProperty = chatState.suggestion.content;
86
+ } else if (chatState.userQuery && chatState.userQuery.length > 0) {
87
+ userQueryProperty = chatState.userQuery;
88
+ }
89
+
90
+ const eventProps: Record<string, unknown> = {
91
+ response_time_ms:
92
+ assistantResponseTimeMs.end - assistantResponseTimeMs.start,
93
+ user_event_type: chatState.replyEventCategory,
94
+ user_query: userQueryProperty,
95
+ };
96
+
97
+ if (chatState.replyEventCategory === UserEventCategory.FormSubmitted) {
98
+ const lastAssistantTurn = chatState.messages
99
+ .filter(
100
+ (turn) => turn.length > 0 && turn[0].role === MessageRole.Assistant
101
+ )
102
+ .pop();
103
+ const formType = payload.userEvents?.find(
104
+ (event) => event.category === UserEventCategory.FormSubmitted
105
+ )?.attributes.formType;
106
+ const formStatus = lastAssistantTurn?.some(
107
+ (response) => response.type === MessageType.Order
108
+ );
109
+ eventProps.form_submitted_attributes = {
110
+ form_type: formType,
111
+ status: formStatus ? "success" : "failed",
112
+ };
113
+ }
114
+
115
+ if (chatSearchState === "product-page") {
116
+ eventProps.search_products_returned = searchProducts.length;
117
+ eventProps.search_products_sort_type = searchProductsSort;
118
+ }
119
+
120
+ track(SpiffyMetricsEventName.ChatAssistantResponse, {
121
+ eventProps,
122
+ });
123
+ };
124
+
125
+ interface ChatContextParams {}
126
+
127
+ const ChatContext = createContext<ChatContextParams | undefined>(undefined);
128
+
129
+ const updateMessageState = (
130
+ message: Message,
131
+ lastMessage: Message,
132
+ setMessages: (updater: (prev: Message[][]) => Message[][]) => void
133
+ ): Message => {
134
+ if (lastMessage == null) {
135
+ setMessages((prev) => [...prev, [message]]);
136
+ return message;
137
+ }
138
+ if (
139
+ lastMessage.type === MessageType.Text &&
140
+ message.type === MessageType.Text
141
+ ) {
142
+ const newMessage = {
143
+ ...lastMessage,
144
+ metadata: {
145
+ ...lastMessage.metadata,
146
+ content: lastMessage.metadata.content + message.metadata.content,
147
+ },
148
+ };
149
+ setMessages((prev) => {
150
+ const lastTurn = prev[prev.length - 1];
151
+ return [
152
+ ...prev.slice(0, prev.length - 1),
153
+ [...lastTurn.slice(0, lastTurn.length - 1), newMessage],
154
+ ];
155
+ });
156
+ return newMessage;
157
+ }
158
+ setMessages((prev) => [
159
+ ...prev.slice(0, prev.length - 1),
160
+ [...prev[prev.length - 1], message],
161
+ ]);
162
+ return message;
163
+ };
164
+
165
+ const handleStreamingError = (
166
+ _error: unknown,
167
+ setRequestFailure: (failed: boolean) => void,
168
+ setMessages: (updater: (prev: Message[][]) => Message[][]) => void
169
+ ) => {
170
+ setRequestFailure(true);
171
+ setMessages((prev) => [
172
+ ...prev,
173
+ [
174
+ {
175
+ id: uuid(),
176
+ role: MessageRole.Assistant,
177
+ type: MessageType.Text,
178
+ createdAt: new Date().toISOString(),
179
+ metadata: {
180
+ content:
181
+ "I'm sorry! I'm having trouble right now. Please refresh the page or try again in a moment.",
182
+ },
183
+ },
184
+ ],
185
+ ]);
186
+ };
187
+
188
+ const processStreamingResponse = async (
189
+ stream: AsyncIterable<Response>,
190
+ messageInterceptor: {
191
+ intercept: (response?: Response) => boolean | undefined;
192
+ },
193
+ handleSearchResults: (message: Message) => void,
194
+ setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
195
+ setSearchIsLoading: (loading: boolean) => void,
196
+ chatId: string
197
+ ): Promise<{ hasSearchResults: boolean }> => {
198
+ let lastMessage: Message | undefined;
199
+ let hasSearchResults = false;
200
+
201
+ for await (const response of stream) {
202
+ try {
203
+ if (messageInterceptor.intercept(response)) {
204
+ return { hasSearchResults };
205
+ }
206
+
207
+ const message = messageFromResponse(response);
208
+ if (!message) {
209
+ throw new Error("Failed to transform API response to client message");
210
+ }
211
+
212
+ if (message.type === MessageType.ProductSearch) {
213
+ handleSearchResults(message);
214
+ hasSearchResults = true;
215
+ setSearchIsLoading(false); // Update search loading immediately when results are detected
216
+ }
217
+
218
+ lastMessage = updateMessageState(message, lastMessage!, setMessages);
219
+ } catch (error: unknown) {
220
+ Logger.logWarn(
221
+ `[spiffy-ai] Failed to generate responses from stream chat_id=${chatId}`,
222
+ error,
223
+ {
224
+ lastResponse: lastMessage,
225
+ response,
226
+ }
227
+ );
228
+ }
229
+ }
230
+
231
+ return { hasSearchResults };
232
+ };
233
+
234
+ const ChatContextProvider = ({ children }: { children: ReactNode }) => {
235
+ const logPerfMetric = useSetAtom(logPerfMetricAtom);
236
+ const [widgetInitialized, setWidgetInitialized] = useState(false);
237
+ const setUserHasReplied = useSetAtom(userHasRepliedAtom);
238
+ // TODO: create atoms for setting/getting the last message turn
239
+ const [messages, setMessages] = useAtom<Message[][]>(messagesAtom);
240
+ const setUserEvents = useSetAtom(userEventsAtom);
241
+ const setSuggestions = useSetAtom(suggestionsAtom);
242
+ const [suggestionsLoading, setSuggestionsLoading] = useAtom<boolean>(
243
+ suggestionsLoadingAtom
244
+ );
245
+ const [responseStreaming, setResponseStreaming] = useAtom<boolean>(
246
+ responseStreamingAtom
247
+ );
248
+ const setRequestFailure = useSetAtom(requestFailureAtom);
249
+ const userEvents = useAtomValue(userEventQueueAtom);
250
+ const userQueueEventCount = useAtomValue(userQueueEventCountAtom);
251
+ const markUserEventsProcessed = useSetAtom(processUserEventAtom);
252
+ const clearUserEventQueue = useSetAtom(clearUserEventAtom);
253
+ const { getUserIdOrDefault } = useUserIdentity();
254
+ const userId = getUserIdOrDefault();
255
+
256
+ const chatId = useAtomValue(chatIdAtom);
257
+ const supportedEvent = useAtomValue(supportedEventAtom);
258
+ // TODO: Replace with actual orgId from useEnviveConfig or NewOrgConfigContext when available
259
+ const orgId = "mock-org-id";
260
+
261
+ const variantInfo = useAtomValue(variantInfoAtom);
262
+ const settingsContext = useSystemSettingsContext();
263
+ const messageInterceptor = useMessageInterceptor();
264
+ const handleSearchResults = useSetAtom(handleSearchResultsAtom);
265
+ const setSearchIsLoading = useSetAtom(chatSearchIsLoadingAtom);
266
+ const { track } = useAmplitudeTracking();
267
+
268
+ const getStreamingResponses = useCallback(
269
+ async (
270
+ payload: NextMessageRequest
271
+ ): Promise<{ hasSearchResults: boolean }> => {
272
+ logPerfMetric(PerfMetricsEvents.FirstResponseStarted);
273
+ const stream = CommerceApiClient.getNextResponseStreaming(payload);
274
+
275
+ try {
276
+ setRequestFailure(false);
277
+
278
+ const { hasSearchResults } = await processStreamingResponse(
279
+ stream,
280
+ messageInterceptor,
281
+ handleSearchResults,
282
+ setMessages,
283
+ setSearchIsLoading,
284
+ chatId
285
+ );
286
+
287
+ return { hasSearchResults };
288
+ } catch (e) {
289
+ handleStreamingError(e, setRequestFailure, setMessages);
290
+ throw e;
291
+ } finally {
292
+ logPerfMetric(PerfMetricsEvents.FirstResponseCompleted);
293
+ }
294
+ },
295
+ [
296
+ logPerfMetric,
297
+ setRequestFailure,
298
+ messageInterceptor,
299
+ handleSearchResults,
300
+ setMessages,
301
+ setSearchIsLoading,
302
+ chatId,
303
+ ]
304
+ );
305
+
306
+ const getSuggestions = useCallback(async () => {
307
+ logPerfMetric(PerfMetricsEvents.FirstSuggestionsStarted);
308
+ setSuggestionsLoading(true);
309
+ setSuggestions([]);
310
+
311
+ const payloadWithoutAppLoaded = createResponsePayload({
312
+ userEvents: [],
313
+ generationParams: settingsContext.generationParams,
314
+ });
315
+ const response = await CommerceApiClient.getNextSuggestions(
316
+ payloadWithoutAppLoaded
317
+ );
318
+
319
+ // sort the suggestions by shortest length so the pills can be stacked horizontally
320
+ setSuggestions(
321
+ response.sort((a, b) => a.content.length - b.content.length)
322
+ );
323
+ setSuggestionsLoading(false);
324
+ logPerfMetric(PerfMetricsEvents.FirstSuggestionsCompleted);
325
+ }, [
326
+ logPerfMetric,
327
+ setSuggestionsLoading,
328
+ setSuggestions,
329
+ settingsContext.generationParams,
330
+ ]);
331
+
332
+ const getResponses = useCallback(
333
+ async (payload?: NextMessageRequest) => {
334
+ try {
335
+ const requestPayload =
336
+ payload ??
337
+ createResponsePayload({
338
+ userEvents,
339
+ generationParams: settingsContext.generationParams,
340
+ });
341
+
342
+ setResponseStreaming(true);
343
+ setSuggestions([]);
344
+ const startTimeMs = Date.now();
345
+
346
+ await getStreamingResponses(requestPayload);
347
+
348
+ recordAssistantResponse(startTimeMs, requestPayload, track);
349
+ await getSuggestions();
350
+ } catch (error) {
351
+ Logger.logError("[spiffy-ai] getResponses error", error);
352
+ } finally {
353
+ // Remove search loading management from here - it's now handled independently
354
+ // in the processStreamingResponse function when search results are detected
355
+ markUserEventsProcessed(userEvents.map(({ eventId }) => eventId));
356
+ setUserHasReplied(false);
357
+ setResponseStreaming(false);
358
+ }
359
+ },
360
+ [
361
+ userEvents,
362
+ settingsContext.generationParams,
363
+ setResponseStreaming,
364
+ setSuggestions,
365
+ getStreamingResponses,
366
+ markUserEventsProcessed,
367
+ getSuggestions,
368
+ setUserHasReplied,
369
+ track,
370
+ ]
371
+ );
372
+
373
+ useEffect(() => {
374
+ const processUserEvents = async () => {
375
+ if (responseStreaming || !widgetInitialized) {
376
+ return;
377
+ }
378
+
379
+ if (
380
+ (variantInfo.variant === "pdp" && !variantInfo.productId) ||
381
+ (variantInfo.variant === "plp" && !variantInfo.plpId) ||
382
+ (variantInfo.variant === "page_visit" && !variantInfo.url)
383
+ ) {
384
+ Logger.logDebug(
385
+ "[spiffy-ai] variantInfo has invalid values, skipping...",
386
+ {
387
+ variantInfo,
388
+ supportedEvent,
389
+ }
390
+ );
391
+ return;
392
+ }
393
+
394
+ Logger.logDebug(
395
+ `Assistants Turn is_currently_streaming=${responseStreaming} initialized=${widgetInitialized}`
396
+ );
397
+ try {
398
+ await getResponses();
399
+ Logger.logInfo(`Assistants Turn [finished]`);
400
+ } catch (error: unknown) {
401
+ Logger.logError("[spiffy-ai] Assistants Turn error", error);
402
+ }
403
+ };
404
+ if (userQueueEventCount > 0) {
405
+ processUserEvents();
406
+ }
407
+ }, [
408
+ getResponses,
409
+ responseStreaming,
410
+ userQueueEventCount,
411
+ widgetInitialized,
412
+ variantInfo,
413
+ supportedEvent,
414
+ ]);
415
+
416
+ useEffect(() => {
417
+ if (widgetInitialized || responseStreaming) {
418
+ Logger.logDebug(
419
+ `[spiffy-ai] initializeWidget [skipped] is_currently_streaming=${responseStreaming} is_initialized=${widgetInitialized}`
420
+ );
421
+ return;
422
+ }
423
+
424
+ const hydrateChat = async () => {
425
+ try {
426
+ Logger.logDebug(
427
+ `[spiffy-ai] initializeWidget is_currently_streaming=${responseStreaming} is_initialized=${widgetInitialized}`
428
+ );
429
+ // on mount, try to get the responses from an active session if one exists
430
+ if (!orgId) {
431
+ throw new Error("orgId is not available");
432
+ }
433
+ const { messages: existingMessages, userEvents } =
434
+ await CommerceApiClient.getResponses(orgId, chatId, userId);
435
+ setMessages([...existingMessages]);
436
+ setUserEvents([...userEvents]);
437
+ getResponses();
438
+ } catch (error) {
439
+ // no active chat session was found, start a new one
440
+ Logger.logInfo(
441
+ `Init chat [exception] chat_id=${chatId} error=${error}`,
442
+ error
443
+ );
444
+ if (error instanceof SessionRestartRequired) {
445
+ const appLoadedEvent = createAppLoadedEvent();
446
+ const visitEvent = createVisitUserEvent({ variantInfo });
447
+ setMessages([]);
448
+ clearUserEventQueue();
449
+ if (visitEvent) {
450
+ const payload = createResponsePayload({
451
+ userEvents: [appLoadedEvent, visitEvent],
452
+ generationParams: settingsContext.generationParams,
453
+ });
454
+ getResponses(payload);
455
+ }
456
+ }
457
+ } finally {
458
+ setWidgetInitialized(true);
459
+ }
460
+ };
461
+
462
+ hydrateChat();
463
+ }, []);
464
+
465
+ const onFocus = useCallback(async () => {
466
+ try {
467
+ if (!responseStreaming && !suggestionsLoading && orgId) {
468
+ const { messages: existingMessages } =
469
+ await CommerceApiClient.getResponses(orgId, chatId, userId);
470
+
471
+ if (existingMessages.length > messages.length) {
472
+ setMessages([...existingMessages]);
473
+ // TODO: Is this bug hack still necessary?
474
+ // If it is, come up with a better solution for it
475
+ // } else if (existingMessages.length === 0) {
476
+ // // if there was an error during the initialization of a new session, the session would be
477
+ // // created in the backend but without any messages. Retry the next_responses request with
478
+ // // the current set of parameters to "jumpstart" the session
479
+ // triggerGetResponseCall('onFocus');
480
+ }
481
+ }
482
+ } catch (error: unknown) {
483
+ Logger.logError("[spiffy-ai] onFocus error", error);
484
+ }
485
+ }, [
486
+ responseStreaming,
487
+ suggestionsLoading,
488
+ orgId,
489
+ chatId,
490
+ userId,
491
+ messages.length,
492
+ setMessages,
493
+ ]);
494
+
495
+ // listen for page focus to get latest messages from the server
496
+ useEffect(() => {
497
+ window.addEventListener("focus", onFocus);
498
+
499
+ return () => {
500
+ window.removeEventListener("focus", onFocus);
501
+ };
502
+ }, [onFocus]);
503
+
504
+ const chatContext = useMemo(() => ({}), []);
505
+
506
+ return (
507
+ <ChatContext.Provider value={chatContext}>{children}</ChatContext.Provider>
508
+ );
509
+ };
510
+
511
+ export { ChatContext, ChatContextProvider };
512
+ export type { ChatContextParams };
@@ -6,9 +6,20 @@ import {
6
6
  envAtom as enviveEnvAtom,
7
7
  orgShortNameAtom as enviveOrgShortNameAtom,
8
8
  } from 'src/atoms/envive/enviveConfig';
9
- import { chatIdAtom, userIdAtom } from 'src/atoms/app/index';
10
9
  import { useOrgId } from 'src/hooks/GraphQLConfig/useGraphQLConfig';
11
10
  import { AppDetails } from '@envive-ai/types';
11
+ import { chatIdAtom } from "src/atoms/app/index";
12
+ import { useUserIdentity } from "src/contexts/userIdentityContext/userIdentityContext";
13
+
14
+ export interface AppDetails {
15
+ orgId: string;
16
+ orgShortName: string;
17
+ chatId: string;
18
+ userId: string;
19
+ source: ContextSourceEnum;
20
+ env: ContextEnvEnum;
21
+ variantInfo: VariantInfo;
22
+ }
12
23
 
13
24
  export const useAppDetails = (): AppDetails => {
14
25
  const { orgId: fetchedOrgId } = useOrgId(); // Get orgId from useOrgId hook
@@ -16,7 +27,9 @@ export const useAppDetails = (): AppDetails => {
16
27
 
17
28
  const orgShortName = useAtomValue(enviveOrgShortNameAtom) ?? 'spiffy-ai';
18
29
  const chatId = useAtomValue(chatIdAtom);
19
- const userId = useAtomValue(userIdAtom);
30
+
31
+ const { getUserIdOrDefault } = useUserIdentity();
32
+ const userId = getUserIdOrDefault();
20
33
  const source = useAtomValue(contextSourceAtom) ?? ContextSourceEnum.App;
21
34
  const env = (useAtomValue(enviveEnvAtom) as ContextEnvEnum) ?? ContextEnvEnum.Dev; // Cast to ContextEnvEnum
22
35
  const variantInfo = useAtomValue(variantInfoAtom);