@memori.ai/memori-react 9.0.0-alpha.5 → 9.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/dist/components/AgeVerificationModal/AgeVerificationModal.js +8 -3
- package/dist/components/AgeVerificationModal/AgeVerificationModal.js.map +1 -1
- package/dist/components/Auth/Auth.js +3 -1
- package/dist/components/Auth/Auth.js.map +1 -1
- package/dist/components/Avatar/Avatar.js +5 -10
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +8 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +2 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js +14 -5
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -1
- package/dist/components/Chat/Chat.js +3 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.js +21 -15
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/ChatHistoryDrawer/ChatHistory.js +3 -1
- package/dist/components/ChatHistoryDrawer/ChatHistory.js.map +1 -1
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js +6 -3
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
- package/dist/components/ContentPreviewModal/ContentPreviewModal.js +3 -1
- package/dist/components/ContentPreviewModal/ContentPreviewModal.js.map +1 -1
- package/dist/components/DateSelector/DateSelector.d.ts +2 -1
- package/dist/components/DateSelector/DateSelector.js +17 -7
- package/dist/components/DateSelector/DateSelector.js.map +1 -1
- package/dist/components/ExpertsDrawer/ExpertsDrawer.js +3 -1
- package/dist/components/ExpertsDrawer/ExpertsDrawer.js.map +1 -1
- package/dist/components/FilePreview/FilePreview.js +22 -5
- package/dist/components/FilePreview/FilePreview.js.map +1 -1
- package/dist/components/KnownFacts/KnownFacts.js +5 -3
- package/dist/components/KnownFacts/KnownFacts.js.map +1 -1
- package/dist/components/LoginDrawer/LoginDrawer.js +3 -1
- package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
- package/dist/components/MediaWidget/MediaItemWidget.js +14 -12
- package/dist/components/MediaWidget/MediaItemWidget.js.map +1 -1
- package/dist/components/MediaWidget/MediaItemWidget.utils.d.ts +3 -2
- package/dist/components/MediaWidget/MediaItemWidget.utils.js +28 -6
- package/dist/components/MediaWidget/MediaItemWidget.utils.js.map +1 -1
- package/dist/components/MediaWidget/MediaPreviewModal.js +6 -7
- package/dist/components/MediaWidget/MediaPreviewModal.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +19 -5
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +4 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.css +4 -2
- package/dist/components/MemoriWidget/MemoriWidget.js +760 -404
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/SettingsDrawer/SettingsDrawer.js +3 -1
- package/dist/components/SettingsDrawer/SettingsDrawer.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.js +3 -1
- package/dist/components/StartPanel/StartPanel.js.map +1 -1
- package/dist/components/UploadButton/UploadButton.js +21 -5
- package/dist/components/UploadButton/UploadButton.js.map +1 -1
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +126 -60
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/dist/components/UploadButton/UploadImages/UploadImages.js +3 -1
- package/dist/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
- package/dist/components/WhyThisAnswer/WhyThisAnswer.js +3 -1
- package/dist/components/WhyThisAnswer/WhyThisAnswer.js.map +1 -1
- package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js +3 -1
- package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
- package/dist/components/layouts/WebsiteAssistant/website-assistant.css +21 -1
- package/dist/components/layouts/chat.css +2 -1
- package/dist/components/layouts/fullpage.css +31 -8
- package/dist/components/layouts/hidden-chat.css +1 -0
- package/dist/components/layouts/totem.css +2 -1
- package/dist/components/layouts/zoomed-full-body.css +32 -7
- package/dist/context/widgetSurfaceContext.d.ts +3 -0
- package/dist/context/widgetSurfaceContext.js +11 -0
- package/dist/context/widgetSurfaceContext.js.map +1 -0
- package/dist/helpers/constants.d.ts +3 -0
- package/dist/helpers/constants.js +27 -1
- package/dist/helpers/constants.js.map +1 -1
- package/dist/helpers/credits.d.ts +5 -2
- package/dist/helpers/credits.js +5 -1
- package/dist/helpers/credits.js.map +1 -1
- package/dist/helpers/message.d.ts +1 -1
- package/dist/helpers/message.js +4 -4
- package/dist/helpers/message.js.map +1 -1
- package/dist/helpers/nats/getNatsConfig.d.ts +9 -0
- package/dist/helpers/nats/getNatsConfig.js +65 -0
- package/dist/helpers/nats/getNatsConfig.js.map +1 -0
- package/dist/helpers/nats/isSessionExpiredError.d.ts +3 -0
- package/dist/helpers/nats/isSessionExpiredError.js +36 -0
- package/dist/helpers/nats/isSessionExpiredError.js.map +1 -0
- package/dist/helpers/nats/useNats.d.ts +12 -0
- package/dist/helpers/nats/useNats.js +75 -0
- package/dist/helpers/nats/useNats.js.map +1 -0
- package/dist/helpers/nats/useNatsSession.d.ts +28 -0
- package/dist/helpers/nats/useNatsSession.js +212 -0
- package/dist/helpers/nats/useNatsSession.js.map +1 -0
- package/dist/helpers/utils.d.ts +21 -0
- package/dist/helpers/utils.js +75 -4
- package/dist/helpers/utils.js.map +1 -1
- package/dist/locales/de.json +1 -0
- package/dist/locales/en.json +1 -0
- package/dist/locales/es.json +1 -0
- package/dist/locales/fr.json +1 -0
- package/dist/locales/it.json +1 -0
- package/dist/styles.css +1 -1
- package/dist/types/integration.d.ts +3 -0
- package/dist/types/integration.js +16 -0
- package/dist/types/integration.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/esm/components/AgeVerificationModal/AgeVerificationModal.js +8 -3
- package/esm/components/AgeVerificationModal/AgeVerificationModal.js.map +1 -1
- package/esm/components/Auth/Auth.js +3 -1
- package/esm/components/Auth/Auth.js.map +1 -1
- package/esm/components/Avatar/Avatar.js +5 -10
- package/esm/components/Avatar/Avatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +9 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js +2 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +2 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js +13 -4
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -1
- package/esm/components/Chat/Chat.js +3 -1
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.js +21 -15
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/ChatHistoryDrawer/ChatHistory.js +3 -1
- package/esm/components/ChatHistoryDrawer/ChatHistory.js.map +1 -1
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js +6 -3
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
- package/esm/components/ContentPreviewModal/ContentPreviewModal.js +3 -1
- package/esm/components/ContentPreviewModal/ContentPreviewModal.js.map +1 -1
- package/esm/components/DateSelector/DateSelector.d.ts +2 -1
- package/esm/components/DateSelector/DateSelector.js +17 -7
- package/esm/components/DateSelector/DateSelector.js.map +1 -1
- package/esm/components/ExpertsDrawer/ExpertsDrawer.js +3 -1
- package/esm/components/ExpertsDrawer/ExpertsDrawer.js.map +1 -1
- package/esm/components/FilePreview/FilePreview.js +24 -7
- package/esm/components/FilePreview/FilePreview.js.map +1 -1
- package/esm/components/KnownFacts/KnownFacts.js +5 -3
- package/esm/components/KnownFacts/KnownFacts.js.map +1 -1
- package/esm/components/LoginDrawer/LoginDrawer.js +3 -1
- package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
- package/esm/components/MediaWidget/MediaItemWidget.js +16 -14
- package/esm/components/MediaWidget/MediaItemWidget.js.map +1 -1
- package/esm/components/MediaWidget/MediaItemWidget.utils.d.ts +3 -2
- package/esm/components/MediaWidget/MediaItemWidget.utils.js +27 -6
- package/esm/components/MediaWidget/MediaItemWidget.utils.js.map +1 -1
- package/esm/components/MediaWidget/MediaPreviewModal.js +6 -7
- package/esm/components/MediaWidget/MediaPreviewModal.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +19 -5
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +4 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.css +4 -2
- package/esm/components/MemoriWidget/MemoriWidget.js +760 -404
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/SettingsDrawer/SettingsDrawer.js +3 -1
- package/esm/components/SettingsDrawer/SettingsDrawer.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.js +3 -1
- package/esm/components/StartPanel/StartPanel.js.map +1 -1
- package/esm/components/UploadButton/UploadButton.js +21 -5
- package/esm/components/UploadButton/UploadButton.js.map +1 -1
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +126 -60
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/esm/components/UploadButton/UploadImages/UploadImages.js +3 -1
- package/esm/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
- package/esm/components/WhyThisAnswer/WhyThisAnswer.js +3 -1
- package/esm/components/WhyThisAnswer/WhyThisAnswer.js.map +1 -1
- package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js +3 -1
- package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
- package/esm/components/layouts/WebsiteAssistant/website-assistant.css +21 -1
- package/esm/components/layouts/chat.css +2 -1
- package/esm/components/layouts/fullpage.css +31 -8
- package/esm/components/layouts/hidden-chat.css +1 -0
- package/esm/components/layouts/totem.css +2 -1
- package/esm/components/layouts/zoomed-full-body.css +32 -7
- package/esm/context/widgetSurfaceContext.d.ts +3 -0
- package/esm/context/widgetSurfaceContext.js +7 -0
- package/esm/context/widgetSurfaceContext.js.map +1 -0
- package/esm/helpers/constants.d.ts +3 -0
- package/esm/helpers/constants.js +26 -0
- package/esm/helpers/constants.js.map +1 -1
- package/esm/helpers/credits.d.ts +5 -2
- package/esm/helpers/credits.js +5 -1
- package/esm/helpers/credits.js.map +1 -1
- package/esm/helpers/message.d.ts +1 -1
- package/esm/helpers/message.js +2 -2
- package/esm/helpers/message.js.map +1 -1
- package/esm/helpers/nats/getNatsConfig.d.ts +9 -0
- package/esm/helpers/nats/getNatsConfig.js +61 -0
- package/esm/helpers/nats/getNatsConfig.js.map +1 -0
- package/esm/helpers/nats/isSessionExpiredError.d.ts +3 -0
- package/esm/helpers/nats/isSessionExpiredError.js +32 -0
- package/esm/helpers/nats/isSessionExpiredError.js.map +1 -0
- package/esm/helpers/nats/useNats.d.ts +12 -0
- package/esm/helpers/nats/useNats.js +72 -0
- package/esm/helpers/nats/useNats.js.map +1 -0
- package/esm/helpers/nats/useNatsSession.d.ts +28 -0
- package/esm/helpers/nats/useNatsSession.js +208 -0
- package/esm/helpers/nats/useNatsSession.js.map +1 -0
- package/esm/helpers/utils.d.ts +21 -0
- package/esm/helpers/utils.js +68 -3
- package/esm/helpers/utils.js.map +1 -1
- package/esm/locales/de.json +1 -0
- package/esm/locales/en.json +1 -0
- package/esm/locales/es.json +1 -0
- package/esm/locales/fr.json +1 -0
- package/esm/locales/it.json +1 -0
- package/esm/styles.css +1 -1
- package/esm/types/integration.d.ts +3 -0
- package/esm/types/integration.js +11 -0
- package/esm/types/integration.js.map +1 -0
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/package.json +5 -3
- package/src/components/AgeVerificationModal/AgeVerificationModal.tsx +9 -1
- package/src/components/Auth/Auth.tsx +3 -0
- package/src/components/Avatar/Avatar.stories.tsx +45 -28
- package/src/components/Avatar/Avatar.test.tsx +54 -0
- package/src/components/Avatar/Avatar.tsx +8 -12
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +12 -5
- package/src/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.ts +2 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/constants.ts +16 -4
- package/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap +164 -0
- package/src/components/Chat/Chat.tsx +3 -0
- package/src/components/ChatBubble/ChatBubble.tsx +40 -12
- package/src/components/ChatHistoryDrawer/ChatHistory.tsx +3 -0
- package/src/components/CompletionProviderStatus/CompletionProviderStatus.tsx +8 -4
- package/src/components/ContentPreviewModal/ContentPreviewModal.tsx +3 -0
- package/src/components/DateSelector/DateSelector.stories.tsx +11 -2
- package/src/components/DateSelector/DateSelector.tsx +28 -9
- package/src/components/ExpertsDrawer/ExpertsDrawer.tsx +3 -0
- package/src/components/FilePreview/FilePreview.tsx +28 -7
- package/src/components/KnownFacts/KnownFacts.tsx +5 -0
- package/src/components/LoginDrawer/LoginDrawer.tsx +3 -0
- package/src/components/MediaWidget/MediaItemWidget.tsx +26 -13
- package/src/components/MediaWidget/MediaItemWidget.utils.test.ts +45 -2
- package/src/components/MediaWidget/MediaItemWidget.utils.ts +39 -6
- package/src/components/MediaWidget/MediaPreviewModal.tsx +9 -7
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +19 -5
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +4 -0
- package/src/components/MemoriWidget/MemoriWidget.css +4 -2
- package/src/components/MemoriWidget/MemoriWidget.tsx +818 -349
- package/src/components/SettingsDrawer/SettingsDrawer.tsx +3 -0
- package/src/components/StartPanel/StartPanel.stories.tsx +22 -0
- package/src/components/StartPanel/StartPanel.test.tsx +64 -1
- package/src/components/StartPanel/StartPanel.tsx +3 -0
- package/src/components/StartPanel/__snapshots__/StartPanel.test.tsx.snap +261 -0
- package/src/components/UploadButton/UploadButton.tsx +30 -11
- package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +151 -61
- package/src/components/UploadButton/UploadImages/UploadImages.tsx +3 -0
- package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +2 -2
- package/src/components/WhyThisAnswer/WhyThisAnswer.tsx +3 -0
- package/src/components/layouts/WebsiteAssistant/WebsiteAssistant.tsx +4 -0
- package/src/components/layouts/WebsiteAssistant/__snapshots__/WebsiteAssistant.test.tsx.snap +48 -44
- package/src/components/layouts/WebsiteAssistant/website-assistant.css +21 -1
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +533 -529
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +1058 -1050
- package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +443 -439
- package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +584 -580
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +528 -524
- package/src/components/layouts/chat.css +2 -1
- package/src/components/layouts/fullpage.css +31 -8
- package/src/components/layouts/hidden-chat.css +1 -0
- package/src/components/layouts/layouts.stories.tsx +131 -12
- package/src/components/layouts/totem.css +2 -1
- package/src/components/layouts/zoomed-full-body.css +32 -7
- package/src/context/widgetSurfaceContext.tsx +14 -0
- package/src/helpers/constants.ts +32 -1
- package/src/helpers/credits.ts +16 -1
- package/src/helpers/message.test.ts +28 -1
- package/src/helpers/message.ts +4 -4
- package/src/helpers/nats/getNatsConfig.ts +145 -0
- package/src/helpers/nats/isSessionExpiredError.test.ts +38 -0
- package/src/helpers/nats/isSessionExpiredError.ts +51 -0
- package/src/helpers/nats/useNats.ts +124 -0
- package/src/helpers/nats/useNatsSession.ts +394 -0
- package/src/helpers/utils.test.ts +162 -0
- package/src/helpers/utils.ts +108 -3
- package/src/index.stories.tsx +32 -0
- package/src/locales/de.json +1 -0
- package/src/locales/en.json +1 -0
- package/src/locales/es.json +1 -0
- package/src/locales/fr.json +1 -0
- package/src/locales/it.json +1 -0
- package/src/styles.css +61 -1
- package/src/types/integration.test.ts +32 -0
- package/src/types/integration.ts +31 -0
- package/src/version.ts +1 -1
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
createAlertOptions,
|
|
45
45
|
MemoriUIProvider,
|
|
46
46
|
} from '@memori.ai/ui';
|
|
47
|
+
import { WidgetSurfaceProvider } from '../../context/widgetSurfaceContext';
|
|
47
48
|
|
|
48
49
|
// Components
|
|
49
50
|
import MemoriAuth from '../Auth/Auth';
|
|
@@ -92,6 +93,16 @@ import { sanitizeText } from '../../helpers/sanitizer';
|
|
|
92
93
|
import { TTSConfig, useTTS } from '../../helpers/tts/useTTS';
|
|
93
94
|
import ChatHistoryDrawer from '../ChatHistoryDrawer/ChatHistory';
|
|
94
95
|
import { STTConfig, useSTT } from '../../helpers/stt/useSTT';
|
|
96
|
+
import { useNats } from '../../helpers/nats/useNats';
|
|
97
|
+
import {
|
|
98
|
+
NatsProgressEvent,
|
|
99
|
+
NatsDialogResponseEvent,
|
|
100
|
+
NatsErrorEvent,
|
|
101
|
+
} from '../../helpers/nats/useNatsSession';
|
|
102
|
+
import {
|
|
103
|
+
isSessionExpiredNatsError,
|
|
104
|
+
isSessionExpiredNatsResponse,
|
|
105
|
+
} from '../../helpers/nats/isSessionExpiredError';
|
|
95
106
|
|
|
96
107
|
// Widget utilities and helpers
|
|
97
108
|
const getMemoriState = (integrationId?: string): object | null => {
|
|
@@ -122,7 +133,21 @@ const getMemoriState = (integrationId?: string): object | null => {
|
|
|
122
133
|
};
|
|
123
134
|
};
|
|
124
135
|
|
|
125
|
-
/**
|
|
136
|
+
/** Unified login token resolution: React state > ref > call-site override > props. */
|
|
137
|
+
const resolveLoginTokenValue = (
|
|
138
|
+
loginToken: string | undefined,
|
|
139
|
+
userTokenRef: string | undefined,
|
|
140
|
+
callAdditionalInfoLoginToken: string | undefined,
|
|
141
|
+
additionalInfoLoginToken: string | undefined,
|
|
142
|
+
authTokenProp: string | undefined
|
|
143
|
+
): string | undefined =>
|
|
144
|
+
loginToken ??
|
|
145
|
+
userTokenRef ??
|
|
146
|
+
callAdditionalInfoLoginToken ??
|
|
147
|
+
additionalInfoLoginToken ??
|
|
148
|
+
authTokenProp;
|
|
149
|
+
|
|
150
|
+
/** Place spec with all nulls for postEnterTextAsync when position is not set or user chose "I don't want to provide my position". */
|
|
126
151
|
const NULL_PLACE_SPEC = {
|
|
127
152
|
placeName: null,
|
|
128
153
|
latitude: null,
|
|
@@ -130,6 +155,18 @@ const NULL_PLACE_SPEC = {
|
|
|
130
155
|
uncertaintyKm: null,
|
|
131
156
|
} as const;
|
|
132
157
|
|
|
158
|
+
const logWidgetError = (context: string, detail?: unknown) => {
|
|
159
|
+
console.error(`[MemoriWidget] ${context}`, detail ?? '');
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/** Reads correlation id from HTTP async response (supports camelCase / snake_case). */
|
|
163
|
+
function readCorrelationID(response: {
|
|
164
|
+
correlationID?: string;
|
|
165
|
+
}): string | undefined {
|
|
166
|
+
const value = response.correlationID;
|
|
167
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
133
170
|
type MemoriTextEnteredEvent = CustomEvent<{
|
|
134
171
|
text: string;
|
|
135
172
|
waitForPrevious?: boolean;
|
|
@@ -363,7 +400,6 @@ window.typeBatchMessages = typeBatchMessages;
|
|
|
363
400
|
let audioContext: IAudioContext;
|
|
364
401
|
|
|
365
402
|
let memoriPassword: string | undefined;
|
|
366
|
-
let userToken: string | undefined;
|
|
367
403
|
|
|
368
404
|
export interface LayoutProps {
|
|
369
405
|
Header?: typeof Header;
|
|
@@ -580,6 +616,7 @@ const MemoriWidget = ({
|
|
|
580
616
|
const {
|
|
581
617
|
initSession,
|
|
582
618
|
deleteSession,
|
|
619
|
+
postEnterTextAsync,
|
|
583
620
|
postTextEnteredEvent,
|
|
584
621
|
postPlaceChangedEvent,
|
|
585
622
|
postDateChangedEvent,
|
|
@@ -597,6 +634,11 @@ const MemoriWidget = ({
|
|
|
597
634
|
// UI primitives via `MemoriUIProvider`). `useRef` would not trigger a
|
|
598
635
|
// re-render and would leave the value `null` on the first pass.
|
|
599
636
|
const [widgetRootEl, setWidgetRootEl] = useState<HTMLDivElement | null>(null);
|
|
637
|
+
// Inner surface establishes `contain: layout` for Drawers/Modals. Kept separate
|
|
638
|
+
// from widgetRootEl so Floating UI menus can portal outside containment.
|
|
639
|
+
const [widgetSurfaceEl, setWidgetSurfaceEl] = useState<HTMLDivElement | null>(
|
|
640
|
+
null
|
|
641
|
+
);
|
|
600
642
|
const [isDarkTheme, setIsDarkTheme] = useState(false);
|
|
601
643
|
useEffect(() => {
|
|
602
644
|
if (!widgetRootEl) return;
|
|
@@ -617,36 +659,85 @@ const MemoriWidget = ({
|
|
|
617
659
|
const [loginToken, setLoginToken] = useState<string | undefined>(
|
|
618
660
|
additionalInfo?.loginToken ?? authToken
|
|
619
661
|
);
|
|
662
|
+
const userTokenRef = useRef<string | undefined>(
|
|
663
|
+
additionalInfo?.loginToken ?? authToken
|
|
664
|
+
);
|
|
665
|
+
const prevPropsLoginTokenRef = useRef<string | undefined>(
|
|
666
|
+
additionalInfo?.loginToken ?? authToken
|
|
667
|
+
);
|
|
668
|
+
|
|
620
669
|
const [user, setUser] = useState<User | undefined>({
|
|
621
670
|
avatarURL: typeof userAvatar === 'string' ? userAvatar : undefined,
|
|
622
671
|
} as User);
|
|
672
|
+
|
|
673
|
+
const resolveLoginToken = useCallback(
|
|
674
|
+
(callAdditionalInfoLoginToken?: string) =>
|
|
675
|
+
resolveLoginTokenValue(
|
|
676
|
+
loginToken,
|
|
677
|
+
userTokenRef.current,
|
|
678
|
+
callAdditionalInfoLoginToken,
|
|
679
|
+
additionalInfo?.loginToken,
|
|
680
|
+
authToken
|
|
681
|
+
),
|
|
682
|
+
[loginToken, additionalInfo?.loginToken, authToken]
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
// Sync loginToken when props change (including explicit removal from parent)
|
|
623
686
|
useEffect(() => {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
removeLocalConfig('loginToken');
|
|
642
|
-
}
|
|
643
|
-
});
|
|
687
|
+
const incomingToken = additionalInfo?.loginToken ?? authToken;
|
|
688
|
+
const prevPropsToken = prevPropsLoginTokenRef.current;
|
|
689
|
+
prevPropsLoginTokenRef.current = incomingToken;
|
|
690
|
+
|
|
691
|
+
if (incomingToken !== prevPropsToken) {
|
|
692
|
+
setLoginToken(incomingToken);
|
|
693
|
+
userTokenRef.current = incomingToken;
|
|
694
|
+
if (!incomingToken) {
|
|
695
|
+
removeLocalConfig('loginToken');
|
|
696
|
+
setUser(undefined);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}, [additionalInfo?.loginToken, authToken]);
|
|
700
|
+
|
|
701
|
+
useEffect(() => {
|
|
702
|
+
if (!loginToken || !(showLogin || memori.requireLoginToken)) {
|
|
703
|
+
return;
|
|
644
704
|
}
|
|
645
|
-
|
|
705
|
+
|
|
706
|
+
let cancelled = false;
|
|
707
|
+
|
|
708
|
+
client.backend
|
|
709
|
+
.pwlGetCurrentUser(loginToken)
|
|
710
|
+
.then(({ user: fetchedUser, resultCode }) => {
|
|
711
|
+
if (cancelled) return;
|
|
712
|
+
|
|
713
|
+
if (fetchedUser && resultCode === 0) {
|
|
714
|
+
setUser(fetchedUser);
|
|
715
|
+
setLocalConfig('loginToken', loginToken);
|
|
716
|
+
userTokenRef.current = loginToken;
|
|
717
|
+
|
|
718
|
+
if (!birthDate && fetchedUser.birthDate) {
|
|
719
|
+
setBirthDate(fetchedUser.birthDate);
|
|
720
|
+
setLocalConfig('birthDate', fetchedUser.birthDate);
|
|
721
|
+
}
|
|
722
|
+
} else {
|
|
723
|
+
setLoginToken(undefined);
|
|
724
|
+
userTokenRef.current = undefined;
|
|
725
|
+
setUser(undefined);
|
|
726
|
+
removeLocalConfig('loginToken');
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
return () => {
|
|
731
|
+
cancelled = true;
|
|
732
|
+
};
|
|
733
|
+
}, [loginToken, showLogin, memori.requireLoginToken]);
|
|
646
734
|
const [showLoginDrawer, setShowLoginDrawer] = useState(false);
|
|
647
735
|
|
|
648
736
|
const [clickedStart, setClickedStart] = useState(false);
|
|
649
737
|
const [gotErrorInOpening, setGotErrorInOpening] = useState(false);
|
|
738
|
+
const sessionStartingRef = useRef(false);
|
|
739
|
+
const needsCredits = tenant?.billingDelegation;
|
|
740
|
+
const [hasEnoughCredits, setHasEnoughCredits] = useState<boolean>(true);
|
|
650
741
|
|
|
651
742
|
const language =
|
|
652
743
|
memori.culture?.split('-')?.[0]?.toUpperCase()! ||
|
|
@@ -708,7 +799,33 @@ const MemoriWidget = ({
|
|
|
708
799
|
const [memoriTyping, setMemoriTyping] = useState<boolean>(false);
|
|
709
800
|
const [typingText, setTypingText] = useState<string>();
|
|
710
801
|
|
|
711
|
-
|
|
802
|
+
type EnterTextRetryParams = {
|
|
803
|
+
text?: string;
|
|
804
|
+
media?: Medium[];
|
|
805
|
+
translate?: boolean;
|
|
806
|
+
translatedText?: string;
|
|
807
|
+
hidden?: boolean;
|
|
808
|
+
typingText?: string;
|
|
809
|
+
useLoaderTextAsMsg?: boolean;
|
|
810
|
+
hasBatchQueued?: boolean;
|
|
811
|
+
expiredSessionID?: string;
|
|
812
|
+
continueFromChatLogID?: string;
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
type PendingEnterText = EnterTextRetryParams & {
|
|
816
|
+
msg?: string;
|
|
817
|
+
waitForResponse?: {
|
|
818
|
+
resolve: (event: NatsDialogResponseEvent) => void;
|
|
819
|
+
reject: (error: Error) => void;
|
|
820
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
821
|
+
};
|
|
822
|
+
};
|
|
823
|
+
const pendingEnterTextRef = useRef<Map<string, PendingEnterText>>(new Map());
|
|
824
|
+
const bufferedNatsResponsesRef = useRef<Map<string, NatsDialogResponseEvent>>(
|
|
825
|
+
new Map()
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
// Layout: from prop (string only) or integrationConfig. PII detection is only from integrationConfig (customData.layout as object with piiDetection).
|
|
712
829
|
const layoutName =
|
|
713
830
|
typeof layout === 'string'
|
|
714
831
|
? layout
|
|
@@ -825,7 +942,7 @@ const MemoriWidget = ({
|
|
|
825
942
|
|
|
826
943
|
if (!additionalInfo?.loginToken && !authToken) {
|
|
827
944
|
setLoginToken(getLocalConfig<typeof loginToken>('loginToken', undefined));
|
|
828
|
-
|
|
945
|
+
userTokenRef.current = getLocalConfig<typeof loginToken>('loginToken', undefined);
|
|
829
946
|
|
|
830
947
|
setBirthDate(getLocalConfig<string | undefined>('birthDate', undefined));
|
|
831
948
|
}
|
|
@@ -900,7 +1017,7 @@ const MemoriWidget = ({
|
|
|
900
1017
|
return Object.keys(place).length > 0 ? place : undefined;
|
|
901
1018
|
}, []);
|
|
902
1019
|
|
|
903
|
-
/** Place to send with
|
|
1020
|
+
/** Place to send with postEnterTextAsync: real place, nulls when no/declined position, or undefined when position not needed. */
|
|
904
1021
|
const getPlaceSpecForEnterText = useCallback(
|
|
905
1022
|
(venue: Venue | undefined) => {
|
|
906
1023
|
if (!memori.needsPosition) return undefined;
|
|
@@ -974,6 +1091,7 @@ const MemoriWidget = ({
|
|
|
974
1091
|
* @param typingText Optional custom typing indicator text
|
|
975
1092
|
* @param useLoaderTextAsMsg Whether to use the loader text as the message (default false)
|
|
976
1093
|
* @param hasBatchQueued Whether there are more messages queued to be sent (default false)
|
|
1094
|
+
* @param skipHistoryPush Skip adding the user message to history (e.g. session-expired retry)
|
|
977
1095
|
*/
|
|
978
1096
|
const sendMessage = async (
|
|
979
1097
|
text: string,
|
|
@@ -984,7 +1102,8 @@ const MemoriWidget = ({
|
|
|
984
1102
|
hidden: boolean = false,
|
|
985
1103
|
typingText?: string,
|
|
986
1104
|
useLoaderTextAsMsg = false,
|
|
987
|
-
hasBatchQueued = false
|
|
1105
|
+
hasBatchQueued = false,
|
|
1106
|
+
skipHistoryPush = false
|
|
988
1107
|
) => {
|
|
989
1108
|
// Get the session ID from params or global state
|
|
990
1109
|
const sessionID =
|
|
@@ -1051,7 +1170,7 @@ const MemoriWidget = ({
|
|
|
1051
1170
|
}
|
|
1052
1171
|
|
|
1053
1172
|
// Add user message to chat history if not hidden
|
|
1054
|
-
if (!hidden)
|
|
1173
|
+
if (!hidden && !skipHistoryPush)
|
|
1055
1174
|
pushMessage({
|
|
1056
1175
|
text: text,
|
|
1057
1176
|
translatedText,
|
|
@@ -1062,27 +1181,12 @@ const MemoriWidget = ({
|
|
|
1062
1181
|
: !!newSessionId,
|
|
1063
1182
|
});
|
|
1064
1183
|
|
|
1065
|
-
// Show typing indicator
|
|
1066
|
-
setMemoriTyping(true);
|
|
1067
|
-
setTypingText(typingText);
|
|
1068
|
-
|
|
1184
|
+
// Show typing indicator after the async enter-text request is accepted (HTTP 200).
|
|
1069
1185
|
let gotError = false;
|
|
1070
1186
|
|
|
1071
1187
|
try {
|
|
1072
|
-
// Add chat reference link to the message if it exists
|
|
1073
|
-
// if (chatLogID) {
|
|
1074
|
-
// msg =
|
|
1075
|
-
// msg +
|
|
1076
|
-
// ' \n\n' +
|
|
1077
|
-
// '<chat-reference session-id="' +
|
|
1078
|
-
// sessionID +
|
|
1079
|
-
// '" event-log-id="' +
|
|
1080
|
-
// chatLogID +
|
|
1081
|
-
// '"></chat-reference>';
|
|
1082
|
-
// }
|
|
1083
|
-
|
|
1084
1188
|
const placeSpec = getPlaceSpecForEnterText(position);
|
|
1085
|
-
const
|
|
1189
|
+
const response = await postEnterTextAsync({
|
|
1086
1190
|
sessionId: sessionID,
|
|
1087
1191
|
text: msg,
|
|
1088
1192
|
...(memori.needsDateTime && {
|
|
@@ -1090,85 +1194,35 @@ const MemoriWidget = ({
|
|
|
1090
1194
|
}),
|
|
1091
1195
|
...(placeSpec !== undefined && { place: placeSpec }),
|
|
1092
1196
|
});
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
handleSpeak(text);
|
|
1111
|
-
}
|
|
1112
|
-
});
|
|
1113
|
-
} else {
|
|
1114
|
-
setCurrentDialogState({
|
|
1115
|
-
...currentState,
|
|
1116
|
-
emission,
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
if (emission) {
|
|
1120
|
-
pushMessage({
|
|
1121
|
-
text: emission,
|
|
1122
|
-
emitter: currentState.emitter,
|
|
1123
|
-
media: currentState.emittedMedia ?? currentState.media,
|
|
1124
|
-
llmUsage: (currentState as any).llmUsage,
|
|
1125
|
-
fromUser: false,
|
|
1126
|
-
questionAnswered: msg,
|
|
1127
|
-
generatedByAI: !!currentState.completion,
|
|
1128
|
-
contextVars: currentState.contextVars,
|
|
1129
|
-
date: currentState.currentDate,
|
|
1130
|
-
placeName: currentState.currentPlaceName,
|
|
1131
|
-
placeLatitude: currentState.currentLatitude,
|
|
1132
|
-
placeLongitude: currentState.currentLongitude,
|
|
1133
|
-
placeUncertaintyKm: currentState.currentUncertaintyKm,
|
|
1134
|
-
tag: currentState.currentTag,
|
|
1135
|
-
memoryTags: currentState.memoryTags,
|
|
1136
|
-
} as any);
|
|
1137
|
-
if (emission && shouldPlayAudio(emission)) {
|
|
1138
|
-
handleSpeak(emission);
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1197
|
+
const correlationID = readCorrelationID(response);
|
|
1198
|
+
if (response.resultCode === 0 && correlationID) {
|
|
1199
|
+
registerPendingEnterText(correlationID, {
|
|
1200
|
+
msg,
|
|
1201
|
+
text,
|
|
1202
|
+
media,
|
|
1203
|
+
translate,
|
|
1204
|
+
translatedText,
|
|
1205
|
+
hidden,
|
|
1206
|
+
typingText,
|
|
1207
|
+
useLoaderTextAsMsg,
|
|
1208
|
+
hasBatchQueued,
|
|
1209
|
+
});
|
|
1210
|
+
setMemoriTyping(true);
|
|
1211
|
+
setTypingText(typingText);
|
|
1212
|
+
} else if (response.resultCode === 0) {
|
|
1213
|
+
logWidgetError('enter-text missing correlationID', response);
|
|
1142
1214
|
} else if (response.resultCode === 404) {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
LANG: userLang,
|
|
1155
|
-
PATHNAME: window.location.pathname,
|
|
1156
|
-
ROUTE: window.location.pathname?.split('/')?.pop() || '',
|
|
1157
|
-
...(initialContextVars || {}),
|
|
1158
|
-
},
|
|
1159
|
-
initialQuestion,
|
|
1160
|
-
undefined,
|
|
1161
|
-
undefined,
|
|
1162
|
-
undefined,
|
|
1163
|
-
undefined,
|
|
1164
|
-
true // isSessionExpired
|
|
1165
|
-
).then(state => {
|
|
1166
|
-
console.info('session timeout');
|
|
1167
|
-
if (state?.sessionID) {
|
|
1168
|
-
setTimeout(() => {
|
|
1169
|
-
sendMessage(text, media, state?.sessionID);
|
|
1170
|
-
}, 500);
|
|
1171
|
-
}
|
|
1215
|
+
retryAfterExpiredSessionRef.current({
|
|
1216
|
+
text,
|
|
1217
|
+
media,
|
|
1218
|
+
translate,
|
|
1219
|
+
translatedText,
|
|
1220
|
+
hidden,
|
|
1221
|
+
typingText,
|
|
1222
|
+
useLoaderTextAsMsg,
|
|
1223
|
+
hasBatchQueued,
|
|
1224
|
+
expiredSessionID: sessionID,
|
|
1225
|
+
continueFromChatLogID: chatLogID,
|
|
1172
1226
|
});
|
|
1173
1227
|
} else if (response.resultCode === 500 && response.resultMessage) {
|
|
1174
1228
|
setHistory(h => [
|
|
@@ -1183,22 +1237,15 @@ const MemoriWidget = ({
|
|
|
1183
1237
|
},
|
|
1184
1238
|
]);
|
|
1185
1239
|
} else {
|
|
1186
|
-
console.warn('[SEND_MESSAGE]', response);
|
|
1187
1240
|
return Promise.reject(response);
|
|
1188
1241
|
}
|
|
1189
1242
|
} catch (error) {
|
|
1190
|
-
console.log('error', error);
|
|
1191
|
-
console.error(error);
|
|
1192
1243
|
gotError = true;
|
|
1244
|
+
logWidgetError('sendMessage failed', error);
|
|
1193
1245
|
|
|
1194
1246
|
setTypingText(undefined);
|
|
1195
1247
|
setMemoriTyping(false);
|
|
1196
1248
|
}
|
|
1197
|
-
|
|
1198
|
-
if (!hasBatchQueued) {
|
|
1199
|
-
setTypingText(undefined);
|
|
1200
|
-
setMemoriTyping(false);
|
|
1201
|
-
}
|
|
1202
1249
|
};
|
|
1203
1250
|
|
|
1204
1251
|
/**
|
|
@@ -1211,12 +1258,6 @@ const MemoriWidget = ({
|
|
|
1211
1258
|
msg?: string,
|
|
1212
1259
|
avoidPushingMessage: boolean = false
|
|
1213
1260
|
) => {
|
|
1214
|
-
// console.log('[TRANSLATE] Starting translation with params:', {
|
|
1215
|
-
// state,
|
|
1216
|
-
// userLang,
|
|
1217
|
-
// msg
|
|
1218
|
-
// });
|
|
1219
|
-
|
|
1220
1261
|
const emission = state?.emission ?? currentDialogState?.emission;
|
|
1221
1262
|
|
|
1222
1263
|
let translatedState = { ...state };
|
|
@@ -1229,7 +1270,6 @@ const MemoriWidget = ({
|
|
|
1229
1270
|
!isMultilanguageEnabled ||
|
|
1230
1271
|
avoidPushingMessage
|
|
1231
1272
|
) {
|
|
1232
|
-
// console.log('[TRANSLATE] Skipping translation - using original emission');
|
|
1233
1273
|
translatedState = { ...state, emission };
|
|
1234
1274
|
if (emission) {
|
|
1235
1275
|
translatedMsg = {
|
|
@@ -1251,12 +1291,10 @@ const MemoriWidget = ({
|
|
|
1251
1291
|
}
|
|
1252
1292
|
} else {
|
|
1253
1293
|
try {
|
|
1254
|
-
// console.log('[TRANSLATE] Translating emission');
|
|
1255
1294
|
const t = await getTranslation(emission, userLang, language, baseUrl);
|
|
1256
1295
|
|
|
1257
1296
|
// Handle hints translation if present
|
|
1258
1297
|
if (state.hints && state.hints.length > 0) {
|
|
1259
|
-
// console.log('[TRANSLATE] Translating hints');
|
|
1260
1298
|
const translatedHints = await Promise.all(
|
|
1261
1299
|
(state.hints ?? []).map(async hint => {
|
|
1262
1300
|
const tHint = await getTranslation(
|
|
@@ -1288,7 +1326,6 @@ const MemoriWidget = ({
|
|
|
1288
1326
|
}
|
|
1289
1327
|
|
|
1290
1328
|
if (t.text.length > 0) {
|
|
1291
|
-
// console.log('[TRANSLATE] Creating translated message');
|
|
1292
1329
|
translatedMsg = {
|
|
1293
1330
|
text: emission,
|
|
1294
1331
|
translatedText: t.text,
|
|
@@ -1309,7 +1346,6 @@ const MemoriWidget = ({
|
|
|
1309
1346
|
};
|
|
1310
1347
|
}
|
|
1311
1348
|
} catch (error) {
|
|
1312
|
-
console.error('[TRANSLATE] Error during translation:', error);
|
|
1313
1349
|
translatedState = { ...state, emission };
|
|
1314
1350
|
translatedMsg = {
|
|
1315
1351
|
text: emission,
|
|
@@ -1330,10 +1366,8 @@ const MemoriWidget = ({
|
|
|
1330
1366
|
}
|
|
1331
1367
|
}
|
|
1332
1368
|
|
|
1333
|
-
// console.log('[TRANSLATE] Setting translated state and message');
|
|
1334
1369
|
setCurrentDialogState(translatedState);
|
|
1335
1370
|
if (!avoidPushingMessage && translatedMsg) {
|
|
1336
|
-
// console.log('[TRANSLATE] Pushing translated message', translatedMsg);
|
|
1337
1371
|
pushMessage(translatedMsg);
|
|
1338
1372
|
}
|
|
1339
1373
|
|
|
@@ -1439,7 +1473,6 @@ const MemoriWidget = ({
|
|
|
1439
1473
|
executableSnippets?.forEach(s => {
|
|
1440
1474
|
try {
|
|
1441
1475
|
setTimeout(() => {
|
|
1442
|
-
console.log('snippet', s);
|
|
1443
1476
|
// eslint-disable-next-line no-new-func
|
|
1444
1477
|
new Function(s.content ?? '')();
|
|
1445
1478
|
|
|
@@ -1453,8 +1486,8 @@ const MemoriWidget = ({
|
|
|
1453
1486
|
);
|
|
1454
1487
|
}, 400);
|
|
1455
1488
|
}, 1000);
|
|
1456
|
-
} catch
|
|
1457
|
-
|
|
1489
|
+
} catch {
|
|
1490
|
+
// ignore snippet execution errors
|
|
1458
1491
|
}
|
|
1459
1492
|
});
|
|
1460
1493
|
};
|
|
@@ -1505,6 +1538,10 @@ const MemoriWidget = ({
|
|
|
1505
1538
|
return;
|
|
1506
1539
|
}
|
|
1507
1540
|
|
|
1541
|
+
if (!(await checkCredits({ notify: true }))) {
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1508
1545
|
setLoading(true);
|
|
1509
1546
|
|
|
1510
1547
|
try {
|
|
@@ -1526,8 +1563,8 @@ const MemoriWidget = ({
|
|
|
1526
1563
|
referral = (() => {
|
|
1527
1564
|
return window.location.href;
|
|
1528
1565
|
})();
|
|
1529
|
-
} catch
|
|
1530
|
-
|
|
1566
|
+
} catch {
|
|
1567
|
+
// ignore referral URL errors
|
|
1531
1568
|
}
|
|
1532
1569
|
|
|
1533
1570
|
// Initialize session with parameters
|
|
@@ -1538,12 +1575,7 @@ const MemoriWidget = ({
|
|
|
1538
1575
|
pin: params.pin ?? personification?.pin,
|
|
1539
1576
|
additionalInfo: {
|
|
1540
1577
|
...(params.additionalInfo || additionalInfo || {}),
|
|
1541
|
-
loginToken:
|
|
1542
|
-
userToken ??
|
|
1543
|
-
loginToken ??
|
|
1544
|
-
params.additionalInfo?.loginToken ??
|
|
1545
|
-
additionalInfo?.loginToken ??
|
|
1546
|
-
authToken,
|
|
1578
|
+
loginToken: resolveLoginToken(params.additionalInfo?.loginToken),
|
|
1547
1579
|
language: (
|
|
1548
1580
|
userLang ??
|
|
1549
1581
|
memori.culture?.split('-')?.[0] ??
|
|
@@ -1589,7 +1621,7 @@ const MemoriWidget = ({
|
|
|
1589
1621
|
setGotErrorInOpening(true);
|
|
1590
1622
|
}
|
|
1591
1623
|
// Handle authentication error
|
|
1592
|
-
else if (session?.resultCode === 403) {
|
|
1624
|
+
else if (session?.resultCode === 403 && memori.privacyType !== 'PUBLIC') {
|
|
1593
1625
|
setMemoriPwd(undefined);
|
|
1594
1626
|
setAuthModalState('password');
|
|
1595
1627
|
return session;
|
|
@@ -1614,11 +1646,10 @@ const MemoriWidget = ({
|
|
|
1614
1646
|
duration: 0,
|
|
1615
1647
|
})
|
|
1616
1648
|
);
|
|
1617
|
-
setGotErrorInOpening(true);
|
|
1618
1649
|
return session;
|
|
1619
1650
|
}
|
|
1620
1651
|
} catch (err) {
|
|
1621
|
-
|
|
1652
|
+
logWidgetError('fetchSession failed', err);
|
|
1622
1653
|
}
|
|
1623
1654
|
};
|
|
1624
1655
|
|
|
@@ -1646,7 +1677,8 @@ const MemoriWidget = ({
|
|
|
1646
1677
|
additionalInfoProp?: { [key: string]: string | undefined },
|
|
1647
1678
|
continueFromChatLogID?: string,
|
|
1648
1679
|
continueFromSessionID?: string,
|
|
1649
|
-
isSessionExpired?: boolean
|
|
1680
|
+
isSessionExpired?: boolean,
|
|
1681
|
+
suppressHistoryUpdate?: boolean
|
|
1650
1682
|
) => {
|
|
1651
1683
|
// Set loading state while reopening session
|
|
1652
1684
|
setLoading(true);
|
|
@@ -1657,12 +1689,10 @@ const MemoriWidget = ({
|
|
|
1657
1689
|
undefined
|
|
1658
1690
|
);
|
|
1659
1691
|
let userBirthDate = birthDate ?? storageBirthDate;
|
|
1660
|
-
// console.log('[REOPEN_SESSION] Using birth date:', userBirthDate);
|
|
1661
1692
|
|
|
1662
1693
|
try {
|
|
1663
1694
|
// Show age verification if required and birth date not provided
|
|
1664
1695
|
if (!userBirthDate && !!minAge) {
|
|
1665
|
-
// console.log('[REOPEN_SESSION] Age verification required, showing modal');
|
|
1666
1696
|
setShowAgeVerification(true);
|
|
1667
1697
|
return;
|
|
1668
1698
|
}
|
|
@@ -1676,24 +1706,26 @@ const MemoriWidget = ({
|
|
|
1676
1706
|
!recoveryTokens &&
|
|
1677
1707
|
!memoriTokens
|
|
1678
1708
|
) {
|
|
1679
|
-
// console.log('[REOPEN_SESSION] Authentication required, showing modal');
|
|
1680
1709
|
setAuthModalState('password');
|
|
1681
1710
|
return;
|
|
1682
1711
|
}
|
|
1683
1712
|
|
|
1713
|
+
if (!(await checkCredits({ notify: true }))) {
|
|
1714
|
+
setLoading(false);
|
|
1715
|
+
return null;
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1684
1718
|
// Get current URL as referral
|
|
1685
1719
|
let referral;
|
|
1686
1720
|
try {
|
|
1687
1721
|
referral = (() => {
|
|
1688
1722
|
return window.location.href;
|
|
1689
1723
|
})();
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
console.debug('[REOPEN_SESSION] Error getting referral:', err);
|
|
1724
|
+
} catch {
|
|
1725
|
+
// ignore referral URL errors
|
|
1693
1726
|
}
|
|
1694
1727
|
|
|
1695
1728
|
// Initialize session with provided parameters
|
|
1696
|
-
// console.log('[REOPEN_SESSION] Initializing session...');
|
|
1697
1729
|
const { sessionID, currentState, ...response } = await initSession({
|
|
1698
1730
|
memoriID: memori.engineMemoriID ?? '',
|
|
1699
1731
|
password: password || memoriPwd || memori.secretToken,
|
|
@@ -1712,12 +1744,7 @@ const MemoriWidget = ({
|
|
|
1712
1744
|
birthDate: userBirthDate,
|
|
1713
1745
|
additionalInfo: {
|
|
1714
1746
|
...(additionalInfoProp || additionalInfo || {}),
|
|
1715
|
-
loginToken:
|
|
1716
|
-
userToken ??
|
|
1717
|
-
loginToken ??
|
|
1718
|
-
additionalInfoProp?.loginToken ??
|
|
1719
|
-
additionalInfo?.loginToken ??
|
|
1720
|
-
authToken,
|
|
1747
|
+
loginToken: resolveLoginToken(additionalInfoProp?.loginToken),
|
|
1721
1748
|
language: (
|
|
1722
1749
|
userLang ??
|
|
1723
1750
|
memori.culture?.split('-')?.[0] ??
|
|
@@ -1730,27 +1757,34 @@ const MemoriWidget = ({
|
|
|
1730
1757
|
|
|
1731
1758
|
// Handle successful session initialization
|
|
1732
1759
|
if (sessionID && currentState && response.resultCode === 0) {
|
|
1733
|
-
console.log(
|
|
1734
|
-
'[REOPEN_SESSION] Session initialized successfully:',
|
|
1735
|
-
sessionID
|
|
1736
|
-
);
|
|
1737
1760
|
setSessionId(sessionID);
|
|
1738
1761
|
|
|
1739
1762
|
// Update dialog state and history if requested
|
|
1740
1763
|
if (updateDialogState) {
|
|
1741
|
-
// console.log('[REOPEN_SESSION] Updating dialog state');
|
|
1742
1764
|
setCurrentDialogState(currentState);
|
|
1743
1765
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1766
|
+
const sessionExpiredStatus =
|
|
1767
|
+
isSessionExpired && history.length > 1
|
|
1768
|
+
? t('sessionExpiredReopening')
|
|
1769
|
+
: null;
|
|
1770
|
+
|
|
1771
|
+
if (sessionExpiredStatus && suppressHistoryUpdate) {
|
|
1772
|
+
pushMessage({
|
|
1773
|
+
text: '',
|
|
1774
|
+
emitter: 'system',
|
|
1775
|
+
fromUser: false,
|
|
1776
|
+
initial: sessionExpiredStatus as any,
|
|
1777
|
+
contextVars: {},
|
|
1778
|
+
date: new Date().toISOString(),
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
if (currentState.emission && !suppressHistoryUpdate) {
|
|
1749
1783
|
// Determine initial status message based on context
|
|
1750
1784
|
// Show status message only if session expired and there's existing history
|
|
1751
1785
|
const initialStatus =
|
|
1752
|
-
|
|
1753
|
-
?
|
|
1786
|
+
sessionExpiredStatus
|
|
1787
|
+
? sessionExpiredStatus
|
|
1754
1788
|
: history.length <= 1
|
|
1755
1789
|
? true
|
|
1756
1790
|
: undefined;
|
|
@@ -1816,8 +1850,10 @@ const MemoriWidget = ({
|
|
|
1816
1850
|
setGotErrorInOpening(true);
|
|
1817
1851
|
}
|
|
1818
1852
|
// Handle authentication error
|
|
1819
|
-
else if (
|
|
1820
|
-
|
|
1853
|
+
else if (
|
|
1854
|
+
response?.resultCode === 403 &&
|
|
1855
|
+
memori.privacyType !== 'PUBLIC'
|
|
1856
|
+
) {
|
|
1821
1857
|
setMemoriPwd(undefined);
|
|
1822
1858
|
setAuthModalState('password');
|
|
1823
1859
|
}
|
|
@@ -1833,7 +1869,7 @@ const MemoriWidget = ({
|
|
|
1833
1869
|
setGotErrorInOpening(true);
|
|
1834
1870
|
}
|
|
1835
1871
|
} catch (err) {
|
|
1836
|
-
|
|
1872
|
+
logWidgetError('reopenSession failed', err);
|
|
1837
1873
|
}
|
|
1838
1874
|
// Reset loading state
|
|
1839
1875
|
setLoading(false);
|
|
@@ -1841,6 +1877,99 @@ const MemoriWidget = ({
|
|
|
1841
1877
|
return null;
|
|
1842
1878
|
};
|
|
1843
1879
|
|
|
1880
|
+
const retryAfterExpiredSessionRef = useRef<
|
|
1881
|
+
(params: EnterTextRetryParams) => ReturnType<typeof reopenSession>
|
|
1882
|
+
>(() => Promise.resolve(null));
|
|
1883
|
+
|
|
1884
|
+
retryAfterExpiredSessionRef.current = (params: EnterTextRetryParams) => {
|
|
1885
|
+
const {
|
|
1886
|
+
text,
|
|
1887
|
+
media,
|
|
1888
|
+
translate = true,
|
|
1889
|
+
translatedText,
|
|
1890
|
+
hidden = false,
|
|
1891
|
+
typingText,
|
|
1892
|
+
useLoaderTextAsMsg = false,
|
|
1893
|
+
hasBatchQueued = false,
|
|
1894
|
+
expiredSessionID,
|
|
1895
|
+
continueFromChatLogID: continueFromChatLogIDParam,
|
|
1896
|
+
} = params;
|
|
1897
|
+
|
|
1898
|
+
const continueFromSessionID = expiredSessionID ?? sessionId;
|
|
1899
|
+
const continueFromChatLogID = continueFromChatLogIDParam ?? chatLogID;
|
|
1900
|
+
|
|
1901
|
+
const reopenAfterExpiry = () =>
|
|
1902
|
+
reopenSession(
|
|
1903
|
+
true,
|
|
1904
|
+
memoriPwd || memori.secretToken,
|
|
1905
|
+
memoriTokens,
|
|
1906
|
+
undefined,
|
|
1907
|
+
undefined,
|
|
1908
|
+
{
|
|
1909
|
+
LANG: userLang,
|
|
1910
|
+
PATHNAME: window.location.pathname,
|
|
1911
|
+
ROUTE: window.location.pathname?.split('/')?.pop() || '',
|
|
1912
|
+
...(initialContextVars || {}),
|
|
1913
|
+
},
|
|
1914
|
+
initialQuestion,
|
|
1915
|
+
undefined,
|
|
1916
|
+
undefined,
|
|
1917
|
+
continueFromChatLogID,
|
|
1918
|
+
continueFromSessionID,
|
|
1919
|
+
true,
|
|
1920
|
+
true
|
|
1921
|
+
);
|
|
1922
|
+
|
|
1923
|
+
const scheduleRetry = (newSessionID: string) => {
|
|
1924
|
+
setTimeout(() => {
|
|
1925
|
+
sendMessage(
|
|
1926
|
+
text!,
|
|
1927
|
+
media,
|
|
1928
|
+
newSessionID,
|
|
1929
|
+
translate,
|
|
1930
|
+
translatedText,
|
|
1931
|
+
hidden,
|
|
1932
|
+
typingText,
|
|
1933
|
+
useLoaderTextAsMsg,
|
|
1934
|
+
hasBatchQueued,
|
|
1935
|
+
true
|
|
1936
|
+
);
|
|
1937
|
+
}, 500);
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
const handleReopenFailure = (state: Awaited<ReturnType<typeof reopenSession>>) => {
|
|
1941
|
+
setMemoriTyping(false);
|
|
1942
|
+
setTypingText(undefined);
|
|
1943
|
+
// `null` = explicit failure; `undefined` = auth/age modal opened (message kept in history)
|
|
1944
|
+
if (state === null && text && !hidden) {
|
|
1945
|
+
add(
|
|
1946
|
+
createAlertOptions({
|
|
1947
|
+
description: t('errors.SESSION_EXPIRED'),
|
|
1948
|
+
severity: 'error',
|
|
1949
|
+
})
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
|
|
1954
|
+
if (!text) {
|
|
1955
|
+
return reopenAfterExpiry().then(state => {
|
|
1956
|
+
if (!state?.sessionID) {
|
|
1957
|
+
handleReopenFailure(state);
|
|
1958
|
+
}
|
|
1959
|
+
return state;
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
return reopenAfterExpiry().then(state => {
|
|
1964
|
+
if (state?.sessionID) {
|
|
1965
|
+
scheduleRetry(state.sessionID);
|
|
1966
|
+
} else {
|
|
1967
|
+
handleReopenFailure(state);
|
|
1968
|
+
}
|
|
1969
|
+
return state;
|
|
1970
|
+
});
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1844
1973
|
const changeTag = async (
|
|
1845
1974
|
memoriId: string,
|
|
1846
1975
|
sessionId: string,
|
|
@@ -1848,7 +1977,6 @@ const MemoriWidget = ({
|
|
|
1848
1977
|
pin?: string
|
|
1849
1978
|
) => {
|
|
1850
1979
|
if (!memoriId || !sessionId) {
|
|
1851
|
-
console.error('CHANGETAG/Session not found');
|
|
1852
1980
|
return Promise.reject('Session not found');
|
|
1853
1981
|
}
|
|
1854
1982
|
|
|
@@ -1888,7 +2016,6 @@ const MemoriWidget = ({
|
|
|
1888
2016
|
};
|
|
1889
2017
|
}
|
|
1890
2018
|
} else if ([400, 401, 403, 404, 500].includes(resultCode)) {
|
|
1891
|
-
console.warn('[APPCONTEXT/CHANGETAG]', resultCode);
|
|
1892
2019
|
let storageBirthDate = getLocalConfig<string | undefined>(
|
|
1893
2020
|
'birthDate',
|
|
1894
2021
|
undefined
|
|
@@ -1899,8 +2026,8 @@ const MemoriWidget = ({
|
|
|
1899
2026
|
referral = (() => {
|
|
1900
2027
|
return window.location.href;
|
|
1901
2028
|
})();
|
|
1902
|
-
} catch
|
|
1903
|
-
|
|
2029
|
+
} catch {
|
|
2030
|
+
// ignore referral URL errors
|
|
1904
2031
|
}
|
|
1905
2032
|
|
|
1906
2033
|
fetchSession({
|
|
@@ -1918,11 +2045,7 @@ const MemoriWidget = ({
|
|
|
1918
2045
|
birthDate: birthDate || storageBirthDate || undefined,
|
|
1919
2046
|
additionalInfo: {
|
|
1920
2047
|
...(additionalInfo || {}),
|
|
1921
|
-
loginToken:
|
|
1922
|
-
userToken ??
|
|
1923
|
-
loginToken ??
|
|
1924
|
-
additionalInfo?.loginToken ??
|
|
1925
|
-
authToken,
|
|
2048
|
+
loginToken: resolveLoginToken(),
|
|
1926
2049
|
language: (
|
|
1927
2050
|
userLang ??
|
|
1928
2051
|
memori.culture?.split('-')?.[0] ??
|
|
@@ -1942,7 +2065,6 @@ const MemoriWidget = ({
|
|
|
1942
2065
|
}
|
|
1943
2066
|
} catch (_e) {
|
|
1944
2067
|
let err = _e as Error;
|
|
1945
|
-
console.warn('[APPCONTEXT/CHANGETAG]', err);
|
|
1946
2068
|
return Promise.reject(err);
|
|
1947
2069
|
}
|
|
1948
2070
|
|
|
@@ -1969,6 +2091,7 @@ const MemoriWidget = ({
|
|
|
1969
2091
|
return () => {
|
|
1970
2092
|
setHasUserActivatedSpeak(false);
|
|
1971
2093
|
setClickedStart(false);
|
|
2094
|
+
sessionStartingRef.current = false;
|
|
1972
2095
|
clearInteractionTimeout();
|
|
1973
2096
|
timeoutRef.current = undefined;
|
|
1974
2097
|
};
|
|
@@ -1981,8 +2104,6 @@ const MemoriWidget = ({
|
|
|
1981
2104
|
const [requestedListening, setRequestedListening] = useState(false);
|
|
1982
2105
|
const startListeningRef = useRef<(() => Promise<void>) | null>(null);
|
|
1983
2106
|
|
|
1984
|
-
// console.log('tenantID', tenantID);
|
|
1985
|
-
|
|
1986
2107
|
// Define TTS configuration
|
|
1987
2108
|
const ttsConfig = useMemo(
|
|
1988
2109
|
() => ({
|
|
@@ -2037,7 +2158,6 @@ const MemoriWidget = ({
|
|
|
2037
2158
|
'muteSpeaker',
|
|
2038
2159
|
!defaultEnableAudio
|
|
2039
2160
|
);
|
|
2040
|
-
console.log('[MemoriWidget] shouldPlayAudio', currentSpeakerMuted);
|
|
2041
2161
|
return (
|
|
2042
2162
|
text &&
|
|
2043
2163
|
text.trim() &&
|
|
@@ -2049,7 +2169,6 @@ const MemoriWidget = ({
|
|
|
2049
2169
|
|
|
2050
2170
|
// Create a single, centralized function to process and send messages
|
|
2051
2171
|
const processSpeechAndSendMessage = (text: string) => {
|
|
2052
|
-
// console.log('processSpeechAndSendMessage', text);
|
|
2053
2172
|
// Skip if already processing or no text
|
|
2054
2173
|
if (!text || text.trim().length === 0) {
|
|
2055
2174
|
return;
|
|
@@ -2058,17 +2177,15 @@ const MemoriWidget = ({
|
|
|
2058
2177
|
try {
|
|
2059
2178
|
// Process the text
|
|
2060
2179
|
const message = stripDuplicates(text);
|
|
2061
|
-
console.debug('Processing speech message:', message);
|
|
2062
2180
|
|
|
2063
2181
|
if (message.length > 0) {
|
|
2064
2182
|
setUserMessage('');
|
|
2065
2183
|
|
|
2066
2184
|
// Send the message
|
|
2067
|
-
console.debug('Sending message:', message);
|
|
2068
2185
|
sendMessage(message);
|
|
2069
2186
|
}
|
|
2070
|
-
} catch
|
|
2071
|
-
|
|
2187
|
+
} catch {
|
|
2188
|
+
// ignore speech processing errors
|
|
2072
2189
|
}
|
|
2073
2190
|
};
|
|
2074
2191
|
|
|
@@ -2148,8 +2265,7 @@ const MemoriWidget = ({
|
|
|
2148
2265
|
}
|
|
2149
2266
|
|
|
2150
2267
|
return translatedState;
|
|
2151
|
-
} catch
|
|
2152
|
-
console.error('Error in translateAndSpeak:', error);
|
|
2268
|
+
} catch {
|
|
2153
2269
|
// Still update activation state even if there's an error
|
|
2154
2270
|
if (!hasUserActivatedSpeak) {
|
|
2155
2271
|
setHasUserActivatedSpeak(true);
|
|
@@ -2166,6 +2282,277 @@ const MemoriWidget = ({
|
|
|
2166
2282
|
]
|
|
2167
2283
|
);
|
|
2168
2284
|
|
|
2285
|
+
const processEnterTextDialogResponse = useCallback(
|
|
2286
|
+
(event: NatsDialogResponseEvent, pending: PendingEnterText) => {
|
|
2287
|
+
const {
|
|
2288
|
+
msg,
|
|
2289
|
+
typingText: pendingTypingText,
|
|
2290
|
+
useLoaderTextAsMsg,
|
|
2291
|
+
} = pending;
|
|
2292
|
+
const currentState = event.currentState;
|
|
2293
|
+
|
|
2294
|
+
if (event.resultCode !== 0 || !currentState) {
|
|
2295
|
+
if (isSessionExpiredNatsResponse(event) && pending.text) {
|
|
2296
|
+
setMemoriTyping(false);
|
|
2297
|
+
setTypingText(undefined);
|
|
2298
|
+
retryAfterExpiredSessionRef.current({
|
|
2299
|
+
text: pending.text,
|
|
2300
|
+
media: pending.media,
|
|
2301
|
+
translate: pending.translate,
|
|
2302
|
+
translatedText: pending.translatedText,
|
|
2303
|
+
hidden: pending.hidden,
|
|
2304
|
+
typingText: pending.typingText,
|
|
2305
|
+
useLoaderTextAsMsg: pending.useLoaderTextAsMsg,
|
|
2306
|
+
hasBatchQueued: pending.hasBatchQueued,
|
|
2307
|
+
expiredSessionID: sessionId,
|
|
2308
|
+
continueFromChatLogID: chatLogID,
|
|
2309
|
+
});
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
if (event.resultCode === 500 && event.resultMessage) {
|
|
2314
|
+
setHistory(h => [
|
|
2315
|
+
...h,
|
|
2316
|
+
{
|
|
2317
|
+
text: 'Error: ' + event.resultMessage,
|
|
2318
|
+
emitter: 'system',
|
|
2319
|
+
fromUser: false,
|
|
2320
|
+
initial: false,
|
|
2321
|
+
contextVars: {},
|
|
2322
|
+
date: new Date().toISOString(),
|
|
2323
|
+
},
|
|
2324
|
+
]);
|
|
2325
|
+
}
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
if (!msg) {
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
setChatLogID(undefined);
|
|
2334
|
+
const emission =
|
|
2335
|
+
useLoaderTextAsMsg && pendingTypingText
|
|
2336
|
+
? pendingTypingText
|
|
2337
|
+
: currentState.emission ?? currentDialogState?.emission;
|
|
2338
|
+
|
|
2339
|
+
if (
|
|
2340
|
+
userLang.toLowerCase() !== language.toLowerCase() &&
|
|
2341
|
+
emission &&
|
|
2342
|
+
isMultilanguageEnabled
|
|
2343
|
+
) {
|
|
2344
|
+
currentState.emission = emission;
|
|
2345
|
+
|
|
2346
|
+
translateDialogState(currentState, userLang, msg).then(ts => {
|
|
2347
|
+
const text = ts.translatedEmission || ts.emission;
|
|
2348
|
+
if (text && shouldPlayAudio(text)) {
|
|
2349
|
+
handleSpeak(text);
|
|
2350
|
+
}
|
|
2351
|
+
});
|
|
2352
|
+
} else {
|
|
2353
|
+
setCurrentDialogState({
|
|
2354
|
+
...currentState,
|
|
2355
|
+
emission,
|
|
2356
|
+
});
|
|
2357
|
+
|
|
2358
|
+
if (emission) {
|
|
2359
|
+
pushMessage({
|
|
2360
|
+
text: emission,
|
|
2361
|
+
emitter: currentState.emitter,
|
|
2362
|
+
media: currentState.emittedMedia ?? currentState.media,
|
|
2363
|
+
llmUsage: (currentState as any).llmUsage,
|
|
2364
|
+
fromUser: false,
|
|
2365
|
+
questionAnswered: msg,
|
|
2366
|
+
generatedByAI: !!currentState.completion,
|
|
2367
|
+
contextVars: currentState.contextVars,
|
|
2368
|
+
date: currentState.currentDate,
|
|
2369
|
+
placeName: currentState.currentPlaceName,
|
|
2370
|
+
placeLatitude: currentState.currentLatitude,
|
|
2371
|
+
placeLongitude: currentState.currentLongitude,
|
|
2372
|
+
placeUncertaintyKm: currentState.currentUncertaintyKm,
|
|
2373
|
+
tag: currentState.currentTag,
|
|
2374
|
+
memoryTags: currentState.memoryTags,
|
|
2375
|
+
} as any);
|
|
2376
|
+
if (emission && shouldPlayAudio(emission)) {
|
|
2377
|
+
handleSpeak(emission);
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
},
|
|
2382
|
+
[
|
|
2383
|
+
userLang,
|
|
2384
|
+
language,
|
|
2385
|
+
isMultilanguageEnabled,
|
|
2386
|
+
currentDialogState?.emission,
|
|
2387
|
+
translateDialogState,
|
|
2388
|
+
handleSpeak,
|
|
2389
|
+
shouldPlayAudio,
|
|
2390
|
+
]
|
|
2391
|
+
);
|
|
2392
|
+
|
|
2393
|
+
const clearEnterTextPending = useCallback(
|
|
2394
|
+
(correlationID: string, pending: PendingEnterText) => {
|
|
2395
|
+
if (pending.waitForResponse?.timeoutId) {
|
|
2396
|
+
clearTimeout(pending.waitForResponse.timeoutId);
|
|
2397
|
+
}
|
|
2398
|
+
pendingEnterTextRef.current.delete(correlationID);
|
|
2399
|
+
},
|
|
2400
|
+
[]
|
|
2401
|
+
);
|
|
2402
|
+
|
|
2403
|
+
const deliverEnterTextNatsError = useCallback(
|
|
2404
|
+
(event: NatsErrorEvent) => {
|
|
2405
|
+
const correlationID = event.correlationID;
|
|
2406
|
+
let pending: PendingEnterText | undefined;
|
|
2407
|
+
|
|
2408
|
+
if (correlationID) {
|
|
2409
|
+
pending = pendingEnterTextRef.current.get(correlationID);
|
|
2410
|
+
if (pending) {
|
|
2411
|
+
clearEnterTextPending(correlationID, pending);
|
|
2412
|
+
pending.waitForResponse?.reject(
|
|
2413
|
+
new Error(
|
|
2414
|
+
event.errorMessage ?? String(event.errorCode ?? 'NATS error')
|
|
2415
|
+
)
|
|
2416
|
+
);
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
if (isSessionExpiredNatsError(event) && pending?.text) {
|
|
2421
|
+
setMemoriTyping(false);
|
|
2422
|
+
setTypingText(undefined);
|
|
2423
|
+
retryAfterExpiredSessionRef.current({
|
|
2424
|
+
text: pending.text,
|
|
2425
|
+
media: pending.media,
|
|
2426
|
+
translate: pending.translate,
|
|
2427
|
+
translatedText: pending.translatedText,
|
|
2428
|
+
hidden: pending.hidden,
|
|
2429
|
+
typingText: pending.typingText,
|
|
2430
|
+
useLoaderTextAsMsg: pending.useLoaderTextAsMsg,
|
|
2431
|
+
hasBatchQueued: pending.hasBatchQueued,
|
|
2432
|
+
expiredSessionID: sessionId,
|
|
2433
|
+
continueFromChatLogID: chatLogID,
|
|
2434
|
+
});
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
const errorText = event.errorMessage
|
|
2439
|
+
? `Error: ${event.errorMessage}`
|
|
2440
|
+
: event.errorCode
|
|
2441
|
+
? `Error: ${event.errorCode}`
|
|
2442
|
+
: 'Error: An unexpected error occurred';
|
|
2443
|
+
|
|
2444
|
+
pushMessage({
|
|
2445
|
+
text: errorText,
|
|
2446
|
+
emitter: 'system',
|
|
2447
|
+
fromUser: false,
|
|
2448
|
+
initial: false,
|
|
2449
|
+
contextVars: {},
|
|
2450
|
+
date: new Date().toISOString(),
|
|
2451
|
+
});
|
|
2452
|
+
|
|
2453
|
+
setMemoriTyping(false);
|
|
2454
|
+
setTypingText(undefined);
|
|
2455
|
+
},
|
|
2456
|
+
[clearEnterTextPending]
|
|
2457
|
+
);
|
|
2458
|
+
|
|
2459
|
+
const deliverEnterTextNatsResponse = useCallback(
|
|
2460
|
+
(correlationID: string, event: NatsDialogResponseEvent) => {
|
|
2461
|
+
const pending = pendingEnterTextRef.current.get(correlationID);
|
|
2462
|
+
if (!pending) {
|
|
2463
|
+
bufferedNatsResponsesRef.current.set(correlationID, event);
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
clearEnterTextPending(correlationID, pending);
|
|
2468
|
+
|
|
2469
|
+
if (pending.waitForResponse) {
|
|
2470
|
+
pending.waitForResponse.resolve(event);
|
|
2471
|
+
setMemoriTyping(false);
|
|
2472
|
+
setTypingText(undefined);
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
processEnterTextDialogResponse(event, pending);
|
|
2477
|
+
|
|
2478
|
+
if (!pending.hasBatchQueued) {
|
|
2479
|
+
setMemoriTyping(false);
|
|
2480
|
+
setTypingText(undefined);
|
|
2481
|
+
}
|
|
2482
|
+
},
|
|
2483
|
+
[processEnterTextDialogResponse, clearEnterTextPending]
|
|
2484
|
+
);
|
|
2485
|
+
|
|
2486
|
+
const registerPendingEnterText = useCallback(
|
|
2487
|
+
(correlationID: string, pending: PendingEnterText) => {
|
|
2488
|
+
const buffered = bufferedNatsResponsesRef.current.get(correlationID);
|
|
2489
|
+
if (buffered) {
|
|
2490
|
+
bufferedNatsResponsesRef.current.delete(correlationID);
|
|
2491
|
+
pendingEnterTextRef.current.set(correlationID, pending);
|
|
2492
|
+
deliverEnterTextNatsResponse(correlationID, buffered);
|
|
2493
|
+
return;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
pendingEnterTextRef.current.set(correlationID, pending);
|
|
2497
|
+
},
|
|
2498
|
+
[deliverEnterTextNatsResponse]
|
|
2499
|
+
);
|
|
2500
|
+
|
|
2501
|
+
const waitForEnterTextNatsResponse = useCallback(
|
|
2502
|
+
(correlationID: string, timeoutMs = 120000) =>
|
|
2503
|
+
new Promise<NatsDialogResponseEvent>((resolve, reject) => {
|
|
2504
|
+
const timeoutId = setTimeout(() => {
|
|
2505
|
+
const current = pendingEnterTextRef.current.get(correlationID);
|
|
2506
|
+
if (current) {
|
|
2507
|
+
clearEnterTextPending(correlationID, current);
|
|
2508
|
+
}
|
|
2509
|
+
logWidgetError('NATS timeout', { correlationID, timeoutMs });
|
|
2510
|
+
reject(new Error('NATS enter-text response timeout'));
|
|
2511
|
+
}, timeoutMs);
|
|
2512
|
+
|
|
2513
|
+
registerPendingEnterText(correlationID, {
|
|
2514
|
+
waitForResponse: {
|
|
2515
|
+
resolve: event => {
|
|
2516
|
+
clearTimeout(timeoutId);
|
|
2517
|
+
resolve(event);
|
|
2518
|
+
},
|
|
2519
|
+
reject: error => {
|
|
2520
|
+
clearTimeout(timeoutId);
|
|
2521
|
+
reject(error);
|
|
2522
|
+
},
|
|
2523
|
+
timeoutId,
|
|
2524
|
+
},
|
|
2525
|
+
});
|
|
2526
|
+
}),
|
|
2527
|
+
[registerPendingEnterText, clearEnterTextPending]
|
|
2528
|
+
);
|
|
2529
|
+
|
|
2530
|
+
// NATS subscription: receives progress updates and the async enter-text response.
|
|
2531
|
+
useNats({
|
|
2532
|
+
baseUrl,
|
|
2533
|
+
sessionId,
|
|
2534
|
+
onProgress: useCallback((event: NatsProgressEvent) => {
|
|
2535
|
+
if (event.message) {
|
|
2536
|
+
setTypingText(event.message);
|
|
2537
|
+
}
|
|
2538
|
+
}, []),
|
|
2539
|
+
onDialogResponse: useCallback(
|
|
2540
|
+
(event: NatsDialogResponseEvent) => {
|
|
2541
|
+
const correlationID = event.correlationID;
|
|
2542
|
+
if (!correlationID) {
|
|
2543
|
+
logWidgetError('NATS dialog response missing correlationID', event);
|
|
2544
|
+
setMemoriTyping(false);
|
|
2545
|
+
setTypingText(undefined);
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
deliverEnterTextNatsResponse(correlationID, event);
|
|
2550
|
+
},
|
|
2551
|
+
[deliverEnterTextNatsResponse]
|
|
2552
|
+
),
|
|
2553
|
+
onError: deliverEnterTextNatsError,
|
|
2554
|
+
});
|
|
2555
|
+
|
|
2169
2556
|
const focusChatInput = () => {
|
|
2170
2557
|
let textarea = document.querySelector(
|
|
2171
2558
|
'#chat-fieldset textarea'
|
|
@@ -2194,8 +2581,8 @@ const MemoriWidget = ({
|
|
|
2194
2581
|
setClickedStart(false);
|
|
2195
2582
|
timeoutRef.current = undefined;
|
|
2196
2583
|
ttsStop();
|
|
2197
|
-
} catch
|
|
2198
|
-
//
|
|
2584
|
+
} catch {
|
|
2585
|
+
// ignore reset errors
|
|
2199
2586
|
}
|
|
2200
2587
|
};
|
|
2201
2588
|
useEffect(() => {
|
|
@@ -2451,12 +2838,6 @@ const MemoriWidget = ({
|
|
|
2451
2838
|
chatLog?: ChatLog,
|
|
2452
2839
|
targetSessionID?: string
|
|
2453
2840
|
) => {
|
|
2454
|
-
// console.log('[onClickStart] Starting with params:', {
|
|
2455
|
-
// session,
|
|
2456
|
-
// initialSessionExpired,
|
|
2457
|
-
// chatLog
|
|
2458
|
-
// });
|
|
2459
|
-
|
|
2460
2841
|
const sessionID = chatLog ? undefined : session?.sessionID || sessionId;
|
|
2461
2842
|
const dialogState = chatLog
|
|
2462
2843
|
? undefined
|
|
@@ -2485,10 +2866,17 @@ const MemoriWidget = ({
|
|
|
2485
2866
|
return;
|
|
2486
2867
|
}
|
|
2487
2868
|
|
|
2869
|
+
if (!(await checkCredits({ notify: true }))) {
|
|
2870
|
+
setClickedStart(false);
|
|
2871
|
+
setLoading(false);
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2488
2875
|
// Handle age verification
|
|
2489
2876
|
if (!sessionID && !!minAge && !birth) {
|
|
2490
2877
|
setShowAgeVerification(true);
|
|
2491
2878
|
setClickedStart(false);
|
|
2879
|
+
return;
|
|
2492
2880
|
}
|
|
2493
2881
|
// Handle authentication
|
|
2494
2882
|
else if (
|
|
@@ -2505,42 +2893,43 @@ const MemoriWidget = ({
|
|
|
2505
2893
|
}
|
|
2506
2894
|
// Create new session if needed
|
|
2507
2895
|
else if (!sessionID || initialSessionExpired) {
|
|
2508
|
-
setClickedStart(false);
|
|
2509
2896
|
setGotErrorInOpening(false);
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
:
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2897
|
+
if (sessionStartingRef.current) {
|
|
2898
|
+
return;
|
|
2899
|
+
}
|
|
2900
|
+
sessionStartingRef.current = true;
|
|
2901
|
+
try {
|
|
2902
|
+
const session = await fetchSession({
|
|
2903
|
+
memoriID: memori.engineMemoriID!,
|
|
2904
|
+
password: secret || memoriPwd || memori.secretToken,
|
|
2905
|
+
tag: personification?.tag,
|
|
2906
|
+
pin: personification?.pin,
|
|
2907
|
+
continueFromChatLogID: chatLog?.chatLogID,
|
|
2908
|
+
initialContextVars: {
|
|
2909
|
+
LANG: userLang,
|
|
2910
|
+
PATHNAME: window.location.pathname?.toUpperCase(),
|
|
2911
|
+
ROUTE:
|
|
2912
|
+
window.location.pathname?.split('/')?.pop()?.toUpperCase() ||
|
|
2913
|
+
'',
|
|
2914
|
+
...((!chatLog
|
|
2915
|
+
? initialContextVars
|
|
2916
|
+
: chatLog.lines[chatLog.lines.length - 1].contextVars) || {}),
|
|
2917
|
+
},
|
|
2918
|
+
initialQuestion: chatLog ? undefined : initialQuestion,
|
|
2919
|
+
birthDate: birth,
|
|
2920
|
+
additionalInfo: {
|
|
2921
|
+
...(additionalInfo || {}),
|
|
2922
|
+
loginToken: resolveLoginToken(),
|
|
2923
|
+
language: (
|
|
2924
|
+
userLang ??
|
|
2925
|
+
memori.culture?.split('-')?.[0] ??
|
|
2926
|
+
'IT'
|
|
2927
|
+
).toLowerCase(),
|
|
2928
|
+
timeZoneOffset: new Date().getTimezoneOffset().toString(),
|
|
2929
|
+
},
|
|
2930
|
+
});
|
|
2542
2931
|
|
|
2543
|
-
|
|
2932
|
+
if (session?.dialogState) {
|
|
2544
2933
|
// reset history
|
|
2545
2934
|
if (!chatLog) {
|
|
2546
2935
|
setHistory([]);
|
|
@@ -2549,6 +2938,7 @@ const MemoriWidget = ({
|
|
|
2549
2938
|
await translateAndSpeak(session.dialogState, userLang);
|
|
2550
2939
|
// No need for additional handleSpeak call since translateAndSpeak already handles it
|
|
2551
2940
|
setHasUserActivatedSpeak(true);
|
|
2941
|
+
setClickedStart(false);
|
|
2552
2942
|
} else {
|
|
2553
2943
|
const messages = chatLog.lines.map(
|
|
2554
2944
|
(l, i) =>
|
|
@@ -2596,8 +2986,8 @@ const MemoriWidget = ({
|
|
|
2596
2986
|
};
|
|
2597
2987
|
})
|
|
2598
2988
|
);
|
|
2599
|
-
} catch
|
|
2600
|
-
|
|
2989
|
+
} catch {
|
|
2990
|
+
// ignore translation errors
|
|
2601
2991
|
}
|
|
2602
2992
|
}
|
|
2603
2993
|
|
|
@@ -2610,12 +3000,18 @@ const MemoriWidget = ({
|
|
|
2610
3000
|
true
|
|
2611
3001
|
).finally(() => {
|
|
2612
3002
|
setHasUserActivatedSpeak(true);
|
|
3003
|
+
setClickedStart(false);
|
|
2613
3004
|
});
|
|
2614
3005
|
}
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
3006
|
+
} else if (session?.resultCode === 0) {
|
|
3007
|
+
sessionStartingRef.current = false;
|
|
3008
|
+
await onClickStart((session as any) || undefined);
|
|
3009
|
+
} else {
|
|
3010
|
+
setLoading(false);
|
|
3011
|
+
setClickedStart(false);
|
|
3012
|
+
}
|
|
3013
|
+
} finally {
|
|
3014
|
+
sessionStartingRef.current = false;
|
|
2619
3015
|
}
|
|
2620
3016
|
|
|
2621
3017
|
return;
|
|
@@ -2628,9 +3024,7 @@ const MemoriWidget = ({
|
|
|
2628
3024
|
|
|
2629
3025
|
if (response.resultCode !== 0 || !currentState) {
|
|
2630
3026
|
const { chatLogs } = await getSessionChatLogs(sessionID!, sessionID!);
|
|
2631
|
-
setGotErrorInOpening(true);
|
|
2632
3027
|
setSessionId(undefined);
|
|
2633
|
-
setClickedStart(false);
|
|
2634
3028
|
await onClickStart(undefined, true, chatLogs?.[0]);
|
|
2635
3029
|
return;
|
|
2636
3030
|
}
|
|
@@ -2656,11 +3050,11 @@ const MemoriWidget = ({
|
|
|
2656
3050
|
|
|
2657
3051
|
if (session && session.resultCode === 0) {
|
|
2658
3052
|
await translateAndSpeak(session.currentState, userLang);
|
|
3053
|
+
setClickedStart(false);
|
|
2659
3054
|
} else {
|
|
2660
3055
|
throw new Error('No session');
|
|
2661
3056
|
}
|
|
2662
|
-
} catch
|
|
2663
|
-
console.error('[onClickStart] Error changing tag:', e);
|
|
3057
|
+
} catch {
|
|
2664
3058
|
reopenSession(
|
|
2665
3059
|
true,
|
|
2666
3060
|
memori?.secretToken,
|
|
@@ -2679,6 +3073,7 @@ const MemoriWidget = ({
|
|
|
2679
3073
|
birth
|
|
2680
3074
|
).then(() => {
|
|
2681
3075
|
setHasUserActivatedSpeak(true);
|
|
3076
|
+
setClickedStart(false);
|
|
2682
3077
|
});
|
|
2683
3078
|
}
|
|
2684
3079
|
}
|
|
@@ -2701,6 +3096,7 @@ const MemoriWidget = ({
|
|
|
2701
3096
|
|
|
2702
3097
|
if (session && session.resultCode === 0) {
|
|
2703
3098
|
await translateAndSpeak(session.currentState, userLang);
|
|
3099
|
+
setClickedStart(false);
|
|
2704
3100
|
} else {
|
|
2705
3101
|
throw new Error('No session');
|
|
2706
3102
|
}
|
|
@@ -2723,6 +3119,7 @@ const MemoriWidget = ({
|
|
|
2723
3119
|
birth
|
|
2724
3120
|
).then(() => {
|
|
2725
3121
|
setHasUserActivatedSpeak(true);
|
|
3122
|
+
setClickedStart(false);
|
|
2726
3123
|
});
|
|
2727
3124
|
}
|
|
2728
3125
|
}
|
|
@@ -2769,14 +3166,14 @@ const MemoriWidget = ({
|
|
|
2769
3166
|
).text,
|
|
2770
3167
|
}))
|
|
2771
3168
|
);
|
|
2772
|
-
} catch
|
|
2773
|
-
|
|
3169
|
+
} catch {
|
|
3170
|
+
// ignore translation errors
|
|
2774
3171
|
}
|
|
2775
3172
|
}
|
|
2776
3173
|
|
|
2777
3174
|
setHistory(translatedMessages);
|
|
2778
|
-
} catch
|
|
2779
|
-
|
|
3175
|
+
} catch {
|
|
3176
|
+
// ignore chat log retrieval errors
|
|
2780
3177
|
}
|
|
2781
3178
|
|
|
2782
3179
|
if (
|
|
@@ -2785,6 +3182,7 @@ const MemoriWidget = ({
|
|
|
2785
3182
|
) {
|
|
2786
3183
|
// we have a history, don't push message
|
|
2787
3184
|
setHasUserActivatedSpeak(true);
|
|
3185
|
+
setClickedStart(false);
|
|
2788
3186
|
await translateAndSpeak(
|
|
2789
3187
|
currentState,
|
|
2790
3188
|
userLang,
|
|
@@ -2794,16 +3192,13 @@ const MemoriWidget = ({
|
|
|
2794
3192
|
!!translatedMessages?.length
|
|
2795
3193
|
);
|
|
2796
3194
|
} else {
|
|
2797
|
-
console.log('[onClickStart] Starting with initial question');
|
|
2798
3195
|
// remove default initial message
|
|
2799
3196
|
translatedMessages = [];
|
|
2800
3197
|
setHistory([]);
|
|
2801
3198
|
|
|
2802
|
-
setMemoriTyping(true);
|
|
2803
|
-
|
|
2804
3199
|
// we have no chat history, we start by initial question
|
|
2805
3200
|
const placeSpec = getPlaceSpecForEnterText(position);
|
|
2806
|
-
const response = await
|
|
3201
|
+
const response = await postEnterTextAsync({
|
|
2807
3202
|
sessionId: sessionID!,
|
|
2808
3203
|
text: initialQuestion,
|
|
2809
3204
|
...(memori.needsDateTime && {
|
|
@@ -2811,8 +3206,7 @@ const MemoriWidget = ({
|
|
|
2811
3206
|
}),
|
|
2812
3207
|
...(placeSpec !== undefined && { place: placeSpec }),
|
|
2813
3208
|
});
|
|
2814
|
-
|
|
2815
|
-
// Handle 500 error from TextEnteredEvent
|
|
3209
|
+
// Handle 500 error from EnterTextAsync
|
|
2816
3210
|
if (response.resultCode === 500 && response.resultMessage) {
|
|
2817
3211
|
setHistory(h => [
|
|
2818
3212
|
...h,
|
|
@@ -2825,16 +3219,33 @@ const MemoriWidget = ({
|
|
|
2825
3219
|
date: new Date().toISOString(),
|
|
2826
3220
|
},
|
|
2827
3221
|
]);
|
|
2828
|
-
setMemoriTyping(false);
|
|
2829
3222
|
return;
|
|
2830
3223
|
}
|
|
2831
3224
|
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
3225
|
+
const onClickStartCorrelationID = readCorrelationID(response);
|
|
3226
|
+
if (response.resultCode === 0 && onClickStartCorrelationID) {
|
|
3227
|
+
setMemoriTyping(true);
|
|
3228
|
+
try {
|
|
3229
|
+
const natsEvent = await waitForEnterTextNatsResponse(
|
|
3230
|
+
onClickStartCorrelationID
|
|
3231
|
+
);
|
|
3232
|
+
if (natsEvent.resultCode === 0 && natsEvent.currentState) {
|
|
3233
|
+
await translateAndSpeak(
|
|
3234
|
+
natsEvent.currentState,
|
|
3235
|
+
userLang,
|
|
3236
|
+
undefined,
|
|
3237
|
+
false
|
|
3238
|
+
);
|
|
3239
|
+
setClickedStart(false);
|
|
3240
|
+
}
|
|
3241
|
+
} catch (err) {
|
|
3242
|
+
logWidgetError('onClickStart NATS wait failed', err);
|
|
3243
|
+
setMemoriTyping(false);
|
|
3244
|
+
setTypingText(undefined);
|
|
3245
|
+
}
|
|
3246
|
+
} else if (response.resultCode === 0) {
|
|
3247
|
+
logWidgetError('onClickStart enter-text missing correlationID', response);
|
|
3248
|
+
}
|
|
2838
3249
|
}
|
|
2839
3250
|
}
|
|
2840
3251
|
}
|
|
@@ -2845,6 +3256,7 @@ const MemoriWidget = ({
|
|
|
2845
3256
|
|
|
2846
3257
|
// everything is fine, just translate dialog state and activate chat
|
|
2847
3258
|
await translateAndSpeak(dialogState!, userLang);
|
|
3259
|
+
setClickedStart(false);
|
|
2848
3260
|
}
|
|
2849
3261
|
},
|
|
2850
3262
|
[memoriPwd, memori, memoriTokens, birthDate, sessionId, userLang, position]
|
|
@@ -2861,10 +3273,24 @@ const MemoriWidget = ({
|
|
|
2861
3273
|
);
|
|
2862
3274
|
|
|
2863
3275
|
useEffect(() => {
|
|
2864
|
-
if (
|
|
3276
|
+
if (
|
|
3277
|
+
!clickedStart &&
|
|
3278
|
+
!sessionStartingRef.current &&
|
|
3279
|
+
!sessionId &&
|
|
3280
|
+
autoStart &&
|
|
3281
|
+
selectedLayout !== 'HIDDEN_CHAT' &&
|
|
3282
|
+
(!needsCredits || hasEnoughCredits)
|
|
3283
|
+
) {
|
|
2865
3284
|
onClickStart();
|
|
2866
3285
|
}
|
|
2867
|
-
}, [
|
|
3286
|
+
}, [
|
|
3287
|
+
clickedStart,
|
|
3288
|
+
autoStart,
|
|
3289
|
+
selectedLayout,
|
|
3290
|
+
sessionId,
|
|
3291
|
+
needsCredits,
|
|
3292
|
+
hasEnoughCredits,
|
|
3293
|
+
]);
|
|
2868
3294
|
|
|
2869
3295
|
useEffect(() => {
|
|
2870
3296
|
const targetNode =
|
|
@@ -2875,29 +3301,31 @@ const MemoriWidget = ({
|
|
|
2875
3301
|
return;
|
|
2876
3302
|
}
|
|
2877
3303
|
|
|
3304
|
+
const propsToken = additionalInfo?.loginToken ?? authToken;
|
|
3305
|
+
const initialDomToken = targetNode.getAttribute('authtoken') || undefined;
|
|
3306
|
+
if (initialDomToken && !propsToken) {
|
|
3307
|
+
setLoginToken(initialDomToken);
|
|
3308
|
+
userTokenRef.current = initialDomToken;
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
const applyAuthTokenFromElement = (element: Element) => {
|
|
3312
|
+
const clientNode =
|
|
3313
|
+
element.nodeName === 'MEMORI-CLIENT'
|
|
3314
|
+
? element
|
|
3315
|
+
: element.closest('memori-client') ?? element.parentElement;
|
|
3316
|
+
const token = clientNode?.getAttribute('authtoken') || undefined;
|
|
3317
|
+
setLoginToken(token);
|
|
3318
|
+
userTokenRef.current = token;
|
|
3319
|
+
};
|
|
3320
|
+
|
|
2878
3321
|
const config = { attributes: true, childList: false, subtree: false };
|
|
2879
|
-
const callback: MutationCallback =
|
|
3322
|
+
const callback: MutationCallback = mutationList => {
|
|
2880
3323
|
for (const mutation of mutationList) {
|
|
2881
3324
|
if (
|
|
2882
3325
|
mutation.type === 'attributes' &&
|
|
2883
3326
|
mutation.attributeName?.toLowerCase() === 'authtoken'
|
|
2884
3327
|
) {
|
|
2885
|
-
|
|
2886
|
-
setLoginToken(
|
|
2887
|
-
// @ts-ignore
|
|
2888
|
-
mutation.target.getAttribute('authtoken') || undefined
|
|
2889
|
-
);
|
|
2890
|
-
// @ts-ignore
|
|
2891
|
-
userToken = mutation.target.getAttribute('authtoken') || undefined;
|
|
2892
|
-
} else {
|
|
2893
|
-
// @ts-ignore
|
|
2894
|
-
setLoginToken(
|
|
2895
|
-
mutation.target?.parentElement?.getAttribute('authtoken') ||
|
|
2896
|
-
undefined
|
|
2897
|
-
);
|
|
2898
|
-
// @ts-ignore
|
|
2899
|
-
userToken = mutation.target.getAttribute('authtoken') || undefined;
|
|
2900
|
-
}
|
|
3328
|
+
applyAuthTokenFromElement(mutation.target as Element);
|
|
2901
3329
|
}
|
|
2902
3330
|
}
|
|
2903
3331
|
};
|
|
@@ -2907,7 +3335,7 @@ const MemoriWidget = ({
|
|
|
2907
3335
|
return () => {
|
|
2908
3336
|
observer.disconnect();
|
|
2909
3337
|
};
|
|
2910
|
-
}, []);
|
|
3338
|
+
}, [memori.name, memori.memoriID, additionalInfo?.loginToken, authToken]);
|
|
2911
3339
|
|
|
2912
3340
|
/**
|
|
2913
3341
|
* Experts references
|
|
@@ -2921,11 +3349,9 @@ const MemoriWidget = ({
|
|
|
2921
3349
|
|
|
2922
3350
|
if (resp.resultCode === 0) {
|
|
2923
3351
|
setExperts(experts);
|
|
2924
|
-
} else {
|
|
2925
|
-
console.warn('Error fetching experts', resp);
|
|
2926
3352
|
}
|
|
2927
|
-
} catch
|
|
2928
|
-
|
|
3353
|
+
} catch {
|
|
3354
|
+
// ignore expert fetch errors
|
|
2929
3355
|
}
|
|
2930
3356
|
}, [sessionId, memori?.enableBoardOfExperts]);
|
|
2931
3357
|
useEffect(() => {
|
|
@@ -2938,39 +3364,74 @@ const MemoriWidget = ({
|
|
|
2938
3364
|
!!user?.userID &&
|
|
2939
3365
|
user?.pAndCUAccepted;
|
|
2940
3366
|
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
3367
|
+
const handleNotEnoughCredits = useCallback(() => {
|
|
3368
|
+
setHasEnoughCredits(false);
|
|
3369
|
+
setAuthModalState(null);
|
|
3370
|
+
add(
|
|
3371
|
+
createAlertOptions({
|
|
3372
|
+
description: t('notEnoughCredits'),
|
|
3373
|
+
severity: 'error',
|
|
3374
|
+
})
|
|
3375
|
+
);
|
|
3376
|
+
}, [add, t]);
|
|
3377
|
+
const checkCredits = useCallback(
|
|
3378
|
+
async (options?: { notify?: boolean }) => {
|
|
3379
|
+
if (!tenant?.billingDelegation) return true;
|
|
3380
|
+
|
|
3381
|
+
// Billing delegation is active: credits MUST be verified.
|
|
3382
|
+
// Without either owner identifier we cannot call the API, so we fail closed
|
|
3383
|
+
// instead of silently letting the session start unverified.
|
|
3384
|
+
if (!ownerUserID && !ownerUserName) {
|
|
3385
|
+
if (options?.notify) {
|
|
3386
|
+
handleNotEnoughCredits();
|
|
3387
|
+
} else {
|
|
3388
|
+
setHasEnoughCredits(false);
|
|
3389
|
+
}
|
|
3390
|
+
return false;
|
|
3391
|
+
}
|
|
2946
3392
|
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
3393
|
+
try {
|
|
3394
|
+
const resp = await getCredits({
|
|
3395
|
+
operation: deepThoughtEnabled
|
|
3396
|
+
? 'dt_session_creation'
|
|
3397
|
+
: 'session_creation',
|
|
3398
|
+
baseUrl: baseUrl,
|
|
3399
|
+
userID: ownerUserID,
|
|
3400
|
+
userName: ownerUserName,
|
|
3401
|
+
tenant: tenantID,
|
|
3402
|
+
});
|
|
2957
3403
|
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3404
|
+
if (resp.enough) {
|
|
3405
|
+
setHasEnoughCredits(true);
|
|
3406
|
+
return true;
|
|
3407
|
+
} else {
|
|
3408
|
+
if (options?.notify) {
|
|
3409
|
+
handleNotEnoughCredits();
|
|
3410
|
+
} else {
|
|
3411
|
+
setHasEnoughCredits(false);
|
|
3412
|
+
}
|
|
3413
|
+
return false;
|
|
3414
|
+
}
|
|
3415
|
+
} catch (err) {
|
|
3416
|
+
logWidgetError('checkCredits failed', err);
|
|
3417
|
+
return true;
|
|
2963
3418
|
}
|
|
2964
|
-
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
3419
|
+
},
|
|
3420
|
+
[
|
|
3421
|
+
baseUrl,
|
|
3422
|
+
deepThoughtEnabled,
|
|
3423
|
+
handleNotEnoughCredits,
|
|
3424
|
+
ownerUserID,
|
|
3425
|
+
ownerUserName,
|
|
3426
|
+
tenant?.billingDelegation,
|
|
3427
|
+
tenantID,
|
|
3428
|
+
]
|
|
3429
|
+
);
|
|
2969
3430
|
useEffect(() => {
|
|
2970
3431
|
if (tenant?.billingDelegation) {
|
|
2971
3432
|
checkCredits();
|
|
2972
3433
|
}
|
|
2973
|
-
}, [tenant?.billingDelegation, deepThoughtEnabled]);
|
|
3434
|
+
}, [tenant?.billingDelegation, deepThoughtEnabled, checkCredits]);
|
|
2974
3435
|
|
|
2975
3436
|
useEffect(() => {
|
|
2976
3437
|
if (__WEBCOMPONENT__) return;
|
|
@@ -3043,7 +3504,7 @@ const MemoriWidget = ({
|
|
|
3043
3504
|
setShowLoginDrawer(false);
|
|
3044
3505
|
setUser(undefined);
|
|
3045
3506
|
setLoginToken(undefined);
|
|
3046
|
-
|
|
3507
|
+
userTokenRef.current = undefined;
|
|
3047
3508
|
removeLocalConfig('loginToken');
|
|
3048
3509
|
});
|
|
3049
3510
|
},
|
|
@@ -3120,8 +3581,7 @@ const MemoriWidget = ({
|
|
|
3120
3581
|
showTypingText:
|
|
3121
3582
|
showTypingText ?? integrationConfig?.showTypingText ?? false,
|
|
3122
3583
|
history: showFullHistory ? history : history.slice(-2),
|
|
3123
|
-
authToken:
|
|
3124
|
-
loginToken ?? userToken ?? additionalInfo?.loginToken ?? authToken,
|
|
3584
|
+
authToken: resolveLoginToken(),
|
|
3125
3585
|
dialogState: currentDialogState,
|
|
3126
3586
|
pushMessage,
|
|
3127
3587
|
simulateUserPrompt,
|
|
@@ -3225,9 +3685,12 @@ const MemoriWidget = ({
|
|
|
3225
3685
|
|
|
3226
3686
|
// Resolve the widget theme once so both `data-theme` on the root and the
|
|
3227
3687
|
// `MemoriUIProvider` (which stamps portaled popups) stay in sync.
|
|
3688
|
+
// Prefer integration config; fall back to host dark mode when unset.
|
|
3228
3689
|
const widgetTheme: 'light' | 'dark' | undefined =
|
|
3229
3690
|
integrationConfig?.theme === 'light' || integrationConfig?.theme === 'dark'
|
|
3230
3691
|
? integrationConfig.theme
|
|
3692
|
+
: isDarkTheme
|
|
3693
|
+
? 'dark'
|
|
3231
3694
|
: undefined;
|
|
3232
3695
|
|
|
3233
3696
|
return (
|
|
@@ -3263,24 +3726,28 @@ const MemoriWidget = ({
|
|
|
3263
3726
|
style={{ height }}
|
|
3264
3727
|
>
|
|
3265
3728
|
<MemoriUIProvider container={widgetRootEl} theme={widgetTheme}>
|
|
3266
|
-
<
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3729
|
+
<WidgetSurfaceProvider value={widgetSurfaceEl}>
|
|
3730
|
+
<div ref={setWidgetSurfaceEl} className="memori-widget__surface">
|
|
3731
|
+
<Layout
|
|
3732
|
+
Header={Header}
|
|
3733
|
+
headerProps={headerProps}
|
|
3734
|
+
Avatar={Avatar}
|
|
3735
|
+
avatarProps={avatarProps}
|
|
3736
|
+
Chat={Chat}
|
|
3737
|
+
chatProps={chatProps}
|
|
3738
|
+
StartPanel={StartPanel}
|
|
3739
|
+
startPanelProps={startPanelProps}
|
|
3740
|
+
integrationStyle={integrationStyle}
|
|
3741
|
+
integrationBackground={integrationBackground}
|
|
3742
|
+
poweredBy={poweredBy}
|
|
3743
|
+
autoStart={autoStart}
|
|
3744
|
+
sessionId={sessionId}
|
|
3745
|
+
hasUserActivatedSpeak={hasUserActivatedSpeak}
|
|
3746
|
+
loading={loading}
|
|
3747
|
+
avatar3dHidden={
|
|
3748
|
+
avatar3dHidden ?? integrationConfig?.avatar_3d_hidden
|
|
3749
|
+
}
|
|
3750
|
+
/>
|
|
3284
3751
|
|
|
3285
3752
|
<ArtifactAPIBridge
|
|
3286
3753
|
pushMessage={(message: Message) => {
|
|
@@ -3520,7 +3987,7 @@ const MemoriWidget = ({
|
|
|
3520
3987
|
setShowLoginDrawer(false);
|
|
3521
3988
|
setUser(user);
|
|
3522
3989
|
setLoginToken(token);
|
|
3523
|
-
|
|
3990
|
+
userTokenRef.current = token;
|
|
3524
3991
|
setLocalConfig('loginToken', token);
|
|
3525
3992
|
// Push a message with initial status to show status message when a new session is created after login
|
|
3526
3993
|
if (
|
|
@@ -3563,12 +4030,14 @@ const MemoriWidget = ({
|
|
|
3563
4030
|
setShowLoginDrawer(false);
|
|
3564
4031
|
setUser(undefined);
|
|
3565
4032
|
setLoginToken(undefined);
|
|
3566
|
-
|
|
4033
|
+
userTokenRef.current = undefined;
|
|
3567
4034
|
removeLocalConfig('loginToken');
|
|
3568
4035
|
});
|
|
3569
4036
|
}}
|
|
3570
4037
|
/>
|
|
3571
4038
|
)}
|
|
4039
|
+
</div>
|
|
4040
|
+
</WidgetSurfaceProvider>
|
|
3572
4041
|
</MemoriUIProvider>
|
|
3573
4042
|
</div>
|
|
3574
4043
|
);
|