@memori.ai/memori-react 9.0.0-alpha.4 → 9.0.0-alpha.6
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 +62 -0
- package/dist/components/AgeVerificationModal/AgeVerificationModal.js +5 -2
- package/dist/components/AgeVerificationModal/AgeVerificationModal.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/ChatBubble/ChatBubble.js +22 -16
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js +6 -3
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.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/FilePreview/FilePreview.js +22 -5
- package/dist/components/FilePreview/FilePreview.js.map +1 -1
- package/dist/components/Header/ChatConsumptionDropdown.js +1 -1
- package/dist/components/Header/ChatConsumptionDropdown.js.map +1 -1
- package/dist/components/Header/Header.css +2 -1
- package/dist/components/Header/Header.js +1 -1
- package/dist/components/Header/Header.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/ArtifactActions/styles.css +5 -4
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +90 -38
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.d.ts +1 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +14 -9
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +2 -2
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +632 -280
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.js +10 -5
- 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 +123 -59
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/dist/components/layouts/Chat.js +25 -30
- package/dist/components/layouts/Chat.js.map +1 -1
- package/dist/components/layouts/FullPage.js +5 -8
- package/dist/components/layouts/FullPage.js.map +1 -1
- package/dist/components/layouts/HiddenChat.js +2 -1
- package/dist/components/layouts/HiddenChat.js.map +1 -1
- package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js +5 -1
- package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
- package/dist/components/layouts/WebsiteAssistant/website-assistant.css +3 -4
- package/dist/components/layouts/ZoomedFullBody.js +4 -7
- package/dist/components/layouts/ZoomedFullBody.js.map +1 -1
- package/dist/components/layouts/chat.css +19 -31
- package/dist/components/layouts/fullpage.css +52 -19
- package/dist/components/layouts/zoomed-full-body.css +40 -1
- 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/usePressTooltip.d.ts +13 -0
- package/dist/helpers/usePressTooltip.js +23 -0
- package/dist/helpers/usePressTooltip.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 +5 -2
- package/esm/components/AgeVerificationModal/AgeVerificationModal.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/ChatBubble/ChatBubble.js +22 -16
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js +6 -3
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.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/FilePreview/FilePreview.js +24 -7
- package/esm/components/FilePreview/FilePreview.js.map +1 -1
- package/esm/components/Header/ChatConsumptionDropdown.js +1 -1
- package/esm/components/Header/ChatConsumptionDropdown.js.map +1 -1
- package/esm/components/Header/Header.css +2 -1
- package/esm/components/Header/Header.js +1 -1
- package/esm/components/Header/Header.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/ArtifactActions/styles.css +5 -4
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +90 -38
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.d.ts +1 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +14 -9
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +2 -2
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +632 -280
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.js +10 -5
- 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 +123 -59
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/esm/components/layouts/Chat.js +25 -30
- package/esm/components/layouts/Chat.js.map +1 -1
- package/esm/components/layouts/FullPage.js +5 -8
- package/esm/components/layouts/FullPage.js.map +1 -1
- package/esm/components/layouts/HiddenChat.js +2 -1
- package/esm/components/layouts/HiddenChat.js.map +1 -1
- package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js +5 -1
- package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
- package/esm/components/layouts/WebsiteAssistant/website-assistant.css +3 -4
- package/esm/components/layouts/ZoomedFullBody.js +4 -7
- package/esm/components/layouts/ZoomedFullBody.js.map +1 -1
- package/esm/components/layouts/chat.css +19 -31
- package/esm/components/layouts/fullpage.css +52 -19
- package/esm/components/layouts/zoomed-full-body.css +40 -1
- 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/usePressTooltip.d.ts +13 -0
- package/esm/helpers/usePressTooltip.js +20 -0
- package/esm/helpers/usePressTooltip.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 +6 -4
- package/src/components/AgeVerificationModal/AgeVerificationModal.tsx +6 -1
- 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/ChatBubble/ChatBubble.tsx +41 -12
- package/src/components/CompletionProviderStatus/CompletionProviderStatus.tsx +8 -4
- package/src/components/DateSelector/DateSelector.stories.tsx +11 -2
- package/src/components/DateSelector/DateSelector.tsx +28 -9
- package/src/components/FilePreview/FilePreview.tsx +28 -7
- package/src/components/Header/ChatConsumptionDropdown.tsx +5 -1
- package/src/components/Header/Header.css +2 -1
- package/src/components/Header/Header.tsx +1 -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/ArtifactDrawer.stories.tsx +218 -2252
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +5 -4
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +90 -38
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +31 -14
- package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +4 -3
- package/src/components/MemoriWidget/MemoriWidget.tsx +785 -331
- package/src/components/StartPanel/StartPanel.stories.tsx +22 -0
- package/src/components/StartPanel/StartPanel.test.tsx +64 -1
- package/src/components/StartPanel/StartPanel.tsx +26 -3
- 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 +148 -61
- package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +2 -2
- package/src/components/layouts/Chat.tsx +16 -19
- package/src/components/layouts/FullPage.tsx +32 -25
- package/src/components/layouts/HiddenChat.tsx +4 -0
- package/src/components/layouts/WebsiteAssistant/WebsiteAssistant.tsx +8 -0
- package/src/components/layouts/WebsiteAssistant/website-assistant.css +3 -4
- package/src/components/layouts/ZoomedFullBody.tsx +30 -24
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +6 -3
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +824 -810
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +280 -273
- package/src/components/layouts/chat.css +19 -31
- package/src/components/layouts/fullpage.css +52 -19
- package/src/components/layouts/layouts.stories.tsx +131 -12
- package/src/components/layouts/zoomed-full-body.css +40 -1
- 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/usePressTooltip.ts +29 -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 +4 -7
- package/src/types/integration.test.ts +32 -0
- package/src/types/integration.ts +31 -0
- package/src/version.ts +1 -1
|
@@ -92,6 +92,16 @@ import { sanitizeText } from '../../helpers/sanitizer';
|
|
|
92
92
|
import { TTSConfig, useTTS } from '../../helpers/tts/useTTS';
|
|
93
93
|
import ChatHistoryDrawer from '../ChatHistoryDrawer/ChatHistory';
|
|
94
94
|
import { STTConfig, useSTT } from '../../helpers/stt/useSTT';
|
|
95
|
+
import { useNats } from '../../helpers/nats/useNats';
|
|
96
|
+
import {
|
|
97
|
+
NatsProgressEvent,
|
|
98
|
+
NatsDialogResponseEvent,
|
|
99
|
+
NatsErrorEvent,
|
|
100
|
+
} from '../../helpers/nats/useNatsSession';
|
|
101
|
+
import {
|
|
102
|
+
isSessionExpiredNatsError,
|
|
103
|
+
isSessionExpiredNatsResponse,
|
|
104
|
+
} from '../../helpers/nats/isSessionExpiredError';
|
|
95
105
|
|
|
96
106
|
// Widget utilities and helpers
|
|
97
107
|
const getMemoriState = (integrationId?: string): object | null => {
|
|
@@ -122,7 +132,21 @@ const getMemoriState = (integrationId?: string): object | null => {
|
|
|
122
132
|
};
|
|
123
133
|
};
|
|
124
134
|
|
|
125
|
-
/**
|
|
135
|
+
/** Unified login token resolution: React state > ref > call-site override > props. */
|
|
136
|
+
const resolveLoginTokenValue = (
|
|
137
|
+
loginToken: string | undefined,
|
|
138
|
+
userTokenRef: string | undefined,
|
|
139
|
+
callAdditionalInfoLoginToken: string | undefined,
|
|
140
|
+
additionalInfoLoginToken: string | undefined,
|
|
141
|
+
authTokenProp: string | undefined
|
|
142
|
+
): string | undefined =>
|
|
143
|
+
loginToken ??
|
|
144
|
+
userTokenRef ??
|
|
145
|
+
callAdditionalInfoLoginToken ??
|
|
146
|
+
additionalInfoLoginToken ??
|
|
147
|
+
authTokenProp;
|
|
148
|
+
|
|
149
|
+
/** Place spec with all nulls for postEnterTextAsync when position is not set or user chose "I don't want to provide my position". */
|
|
126
150
|
const NULL_PLACE_SPEC = {
|
|
127
151
|
placeName: null,
|
|
128
152
|
latitude: null,
|
|
@@ -130,6 +154,18 @@ const NULL_PLACE_SPEC = {
|
|
|
130
154
|
uncertaintyKm: null,
|
|
131
155
|
} as const;
|
|
132
156
|
|
|
157
|
+
const logWidgetError = (context: string, detail?: unknown) => {
|
|
158
|
+
console.error(`[MemoriWidget] ${context}`, detail ?? '');
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/** Reads correlation id from HTTP async response (supports camelCase / snake_case). */
|
|
162
|
+
function readCorrelationID(response: {
|
|
163
|
+
correlationID?: string;
|
|
164
|
+
}): string | undefined {
|
|
165
|
+
const value = response.correlationID;
|
|
166
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
133
169
|
type MemoriTextEnteredEvent = CustomEvent<{
|
|
134
170
|
text: string;
|
|
135
171
|
waitForPrevious?: boolean;
|
|
@@ -363,7 +399,6 @@ window.typeBatchMessages = typeBatchMessages;
|
|
|
363
399
|
let audioContext: IAudioContext;
|
|
364
400
|
|
|
365
401
|
let memoriPassword: string | undefined;
|
|
366
|
-
let userToken: string | undefined;
|
|
367
402
|
|
|
368
403
|
export interface LayoutProps {
|
|
369
404
|
Header?: typeof Header;
|
|
@@ -580,6 +615,7 @@ const MemoriWidget = ({
|
|
|
580
615
|
const {
|
|
581
616
|
initSession,
|
|
582
617
|
deleteSession,
|
|
618
|
+
postEnterTextAsync,
|
|
583
619
|
postTextEnteredEvent,
|
|
584
620
|
postPlaceChangedEvent,
|
|
585
621
|
postDateChangedEvent,
|
|
@@ -617,36 +653,85 @@ const MemoriWidget = ({
|
|
|
617
653
|
const [loginToken, setLoginToken] = useState<string | undefined>(
|
|
618
654
|
additionalInfo?.loginToken ?? authToken
|
|
619
655
|
);
|
|
656
|
+
const userTokenRef = useRef<string | undefined>(
|
|
657
|
+
additionalInfo?.loginToken ?? authToken
|
|
658
|
+
);
|
|
659
|
+
const prevPropsLoginTokenRef = useRef<string | undefined>(
|
|
660
|
+
additionalInfo?.loginToken ?? authToken
|
|
661
|
+
);
|
|
662
|
+
|
|
620
663
|
const [user, setUser] = useState<User | undefined>({
|
|
621
664
|
avatarURL: typeof userAvatar === 'string' ? userAvatar : undefined,
|
|
622
665
|
} as User);
|
|
666
|
+
|
|
667
|
+
const resolveLoginToken = useCallback(
|
|
668
|
+
(callAdditionalInfoLoginToken?: string) =>
|
|
669
|
+
resolveLoginTokenValue(
|
|
670
|
+
loginToken,
|
|
671
|
+
userTokenRef.current,
|
|
672
|
+
callAdditionalInfoLoginToken,
|
|
673
|
+
additionalInfo?.loginToken,
|
|
674
|
+
authToken
|
|
675
|
+
),
|
|
676
|
+
[loginToken, additionalInfo?.loginToken, authToken]
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
// Sync loginToken when props change (including explicit removal from parent)
|
|
623
680
|
useEffect(() => {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
removeLocalConfig('loginToken');
|
|
642
|
-
}
|
|
643
|
-
});
|
|
681
|
+
const incomingToken = additionalInfo?.loginToken ?? authToken;
|
|
682
|
+
const prevPropsToken = prevPropsLoginTokenRef.current;
|
|
683
|
+
prevPropsLoginTokenRef.current = incomingToken;
|
|
684
|
+
|
|
685
|
+
if (incomingToken !== prevPropsToken) {
|
|
686
|
+
setLoginToken(incomingToken);
|
|
687
|
+
userTokenRef.current = incomingToken;
|
|
688
|
+
if (!incomingToken) {
|
|
689
|
+
removeLocalConfig('loginToken');
|
|
690
|
+
setUser(undefined);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}, [additionalInfo?.loginToken, authToken]);
|
|
694
|
+
|
|
695
|
+
useEffect(() => {
|
|
696
|
+
if (!loginToken || !(showLogin || memori.requireLoginToken)) {
|
|
697
|
+
return;
|
|
644
698
|
}
|
|
645
|
-
|
|
699
|
+
|
|
700
|
+
let cancelled = false;
|
|
701
|
+
|
|
702
|
+
client.backend
|
|
703
|
+
.pwlGetCurrentUser(loginToken)
|
|
704
|
+
.then(({ user: fetchedUser, resultCode }) => {
|
|
705
|
+
if (cancelled) return;
|
|
706
|
+
|
|
707
|
+
if (fetchedUser && resultCode === 0) {
|
|
708
|
+
setUser(fetchedUser);
|
|
709
|
+
setLocalConfig('loginToken', loginToken);
|
|
710
|
+
userTokenRef.current = loginToken;
|
|
711
|
+
|
|
712
|
+
if (!birthDate && fetchedUser.birthDate) {
|
|
713
|
+
setBirthDate(fetchedUser.birthDate);
|
|
714
|
+
setLocalConfig('birthDate', fetchedUser.birthDate);
|
|
715
|
+
}
|
|
716
|
+
} else {
|
|
717
|
+
setLoginToken(undefined);
|
|
718
|
+
userTokenRef.current = undefined;
|
|
719
|
+
setUser(undefined);
|
|
720
|
+
removeLocalConfig('loginToken');
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
return () => {
|
|
725
|
+
cancelled = true;
|
|
726
|
+
};
|
|
727
|
+
}, [loginToken, showLogin, memori.requireLoginToken]);
|
|
646
728
|
const [showLoginDrawer, setShowLoginDrawer] = useState(false);
|
|
647
729
|
|
|
648
730
|
const [clickedStart, setClickedStart] = useState(false);
|
|
649
731
|
const [gotErrorInOpening, setGotErrorInOpening] = useState(false);
|
|
732
|
+
const sessionStartingRef = useRef(false);
|
|
733
|
+
const needsCredits = tenant?.billingDelegation;
|
|
734
|
+
const [hasEnoughCredits, setHasEnoughCredits] = useState<boolean>(true);
|
|
650
735
|
|
|
651
736
|
const language =
|
|
652
737
|
memori.culture?.split('-')?.[0]?.toUpperCase()! ||
|
|
@@ -708,7 +793,33 @@ const MemoriWidget = ({
|
|
|
708
793
|
const [memoriTyping, setMemoriTyping] = useState<boolean>(false);
|
|
709
794
|
const [typingText, setTypingText] = useState<string>();
|
|
710
795
|
|
|
711
|
-
|
|
796
|
+
type EnterTextRetryParams = {
|
|
797
|
+
text?: string;
|
|
798
|
+
media?: Medium[];
|
|
799
|
+
translate?: boolean;
|
|
800
|
+
translatedText?: string;
|
|
801
|
+
hidden?: boolean;
|
|
802
|
+
typingText?: string;
|
|
803
|
+
useLoaderTextAsMsg?: boolean;
|
|
804
|
+
hasBatchQueued?: boolean;
|
|
805
|
+
expiredSessionID?: string;
|
|
806
|
+
continueFromChatLogID?: string;
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
type PendingEnterText = EnterTextRetryParams & {
|
|
810
|
+
msg?: string;
|
|
811
|
+
waitForResponse?: {
|
|
812
|
+
resolve: (event: NatsDialogResponseEvent) => void;
|
|
813
|
+
reject: (error: Error) => void;
|
|
814
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
815
|
+
};
|
|
816
|
+
};
|
|
817
|
+
const pendingEnterTextRef = useRef<Map<string, PendingEnterText>>(new Map());
|
|
818
|
+
const bufferedNatsResponsesRef = useRef<Map<string, NatsDialogResponseEvent>>(
|
|
819
|
+
new Map()
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
// Layout: from prop (string only) or integrationConfig. PII detection is only from integrationConfig (customData.layout as object with piiDetection).
|
|
712
823
|
const layoutName =
|
|
713
824
|
typeof layout === 'string'
|
|
714
825
|
? layout
|
|
@@ -825,7 +936,7 @@ const MemoriWidget = ({
|
|
|
825
936
|
|
|
826
937
|
if (!additionalInfo?.loginToken && !authToken) {
|
|
827
938
|
setLoginToken(getLocalConfig<typeof loginToken>('loginToken', undefined));
|
|
828
|
-
|
|
939
|
+
userTokenRef.current = getLocalConfig<typeof loginToken>('loginToken', undefined);
|
|
829
940
|
|
|
830
941
|
setBirthDate(getLocalConfig<string | undefined>('birthDate', undefined));
|
|
831
942
|
}
|
|
@@ -900,7 +1011,7 @@ const MemoriWidget = ({
|
|
|
900
1011
|
return Object.keys(place).length > 0 ? place : undefined;
|
|
901
1012
|
}, []);
|
|
902
1013
|
|
|
903
|
-
/** Place to send with
|
|
1014
|
+
/** Place to send with postEnterTextAsync: real place, nulls when no/declined position, or undefined when position not needed. */
|
|
904
1015
|
const getPlaceSpecForEnterText = useCallback(
|
|
905
1016
|
(venue: Venue | undefined) => {
|
|
906
1017
|
if (!memori.needsPosition) return undefined;
|
|
@@ -974,6 +1085,7 @@ const MemoriWidget = ({
|
|
|
974
1085
|
* @param typingText Optional custom typing indicator text
|
|
975
1086
|
* @param useLoaderTextAsMsg Whether to use the loader text as the message (default false)
|
|
976
1087
|
* @param hasBatchQueued Whether there are more messages queued to be sent (default false)
|
|
1088
|
+
* @param skipHistoryPush Skip adding the user message to history (e.g. session-expired retry)
|
|
977
1089
|
*/
|
|
978
1090
|
const sendMessage = async (
|
|
979
1091
|
text: string,
|
|
@@ -984,7 +1096,8 @@ const MemoriWidget = ({
|
|
|
984
1096
|
hidden: boolean = false,
|
|
985
1097
|
typingText?: string,
|
|
986
1098
|
useLoaderTextAsMsg = false,
|
|
987
|
-
hasBatchQueued = false
|
|
1099
|
+
hasBatchQueued = false,
|
|
1100
|
+
skipHistoryPush = false
|
|
988
1101
|
) => {
|
|
989
1102
|
// Get the session ID from params or global state
|
|
990
1103
|
const sessionID =
|
|
@@ -1051,7 +1164,7 @@ const MemoriWidget = ({
|
|
|
1051
1164
|
}
|
|
1052
1165
|
|
|
1053
1166
|
// Add user message to chat history if not hidden
|
|
1054
|
-
if (!hidden)
|
|
1167
|
+
if (!hidden && !skipHistoryPush)
|
|
1055
1168
|
pushMessage({
|
|
1056
1169
|
text: text,
|
|
1057
1170
|
translatedText,
|
|
@@ -1062,27 +1175,12 @@ const MemoriWidget = ({
|
|
|
1062
1175
|
: !!newSessionId,
|
|
1063
1176
|
});
|
|
1064
1177
|
|
|
1065
|
-
// Show typing indicator
|
|
1066
|
-
setMemoriTyping(true);
|
|
1067
|
-
setTypingText(typingText);
|
|
1068
|
-
|
|
1178
|
+
// Show typing indicator after the async enter-text request is accepted (HTTP 200).
|
|
1069
1179
|
let gotError = false;
|
|
1070
1180
|
|
|
1071
1181
|
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
1182
|
const placeSpec = getPlaceSpecForEnterText(position);
|
|
1085
|
-
const
|
|
1183
|
+
const response = await postEnterTextAsync({
|
|
1086
1184
|
sessionId: sessionID,
|
|
1087
1185
|
text: msg,
|
|
1088
1186
|
...(memori.needsDateTime && {
|
|
@@ -1090,85 +1188,35 @@ const MemoriWidget = ({
|
|
|
1090
1188
|
}),
|
|
1091
1189
|
...(placeSpec !== undefined && { place: placeSpec }),
|
|
1092
1190
|
});
|
|
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
|
-
}
|
|
1191
|
+
const correlationID = readCorrelationID(response);
|
|
1192
|
+
if (response.resultCode === 0 && correlationID) {
|
|
1193
|
+
registerPendingEnterText(correlationID, {
|
|
1194
|
+
msg,
|
|
1195
|
+
text,
|
|
1196
|
+
media,
|
|
1197
|
+
translate,
|
|
1198
|
+
translatedText,
|
|
1199
|
+
hidden,
|
|
1200
|
+
typingText,
|
|
1201
|
+
useLoaderTextAsMsg,
|
|
1202
|
+
hasBatchQueued,
|
|
1203
|
+
});
|
|
1204
|
+
setMemoriTyping(true);
|
|
1205
|
+
setTypingText(typingText);
|
|
1206
|
+
} else if (response.resultCode === 0) {
|
|
1207
|
+
logWidgetError('enter-text missing correlationID', response);
|
|
1142
1208
|
} 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
|
-
}
|
|
1209
|
+
retryAfterExpiredSessionRef.current({
|
|
1210
|
+
text,
|
|
1211
|
+
media,
|
|
1212
|
+
translate,
|
|
1213
|
+
translatedText,
|
|
1214
|
+
hidden,
|
|
1215
|
+
typingText,
|
|
1216
|
+
useLoaderTextAsMsg,
|
|
1217
|
+
hasBatchQueued,
|
|
1218
|
+
expiredSessionID: sessionID,
|
|
1219
|
+
continueFromChatLogID: chatLogID,
|
|
1172
1220
|
});
|
|
1173
1221
|
} else if (response.resultCode === 500 && response.resultMessage) {
|
|
1174
1222
|
setHistory(h => [
|
|
@@ -1183,22 +1231,15 @@ const MemoriWidget = ({
|
|
|
1183
1231
|
},
|
|
1184
1232
|
]);
|
|
1185
1233
|
} else {
|
|
1186
|
-
console.warn('[SEND_MESSAGE]', response);
|
|
1187
1234
|
return Promise.reject(response);
|
|
1188
1235
|
}
|
|
1189
1236
|
} catch (error) {
|
|
1190
|
-
console.log('error', error);
|
|
1191
|
-
console.error(error);
|
|
1192
1237
|
gotError = true;
|
|
1238
|
+
logWidgetError('sendMessage failed', error);
|
|
1193
1239
|
|
|
1194
1240
|
setTypingText(undefined);
|
|
1195
1241
|
setMemoriTyping(false);
|
|
1196
1242
|
}
|
|
1197
|
-
|
|
1198
|
-
if (!hasBatchQueued) {
|
|
1199
|
-
setTypingText(undefined);
|
|
1200
|
-
setMemoriTyping(false);
|
|
1201
|
-
}
|
|
1202
1243
|
};
|
|
1203
1244
|
|
|
1204
1245
|
/**
|
|
@@ -1211,12 +1252,6 @@ const MemoriWidget = ({
|
|
|
1211
1252
|
msg?: string,
|
|
1212
1253
|
avoidPushingMessage: boolean = false
|
|
1213
1254
|
) => {
|
|
1214
|
-
// console.log('[TRANSLATE] Starting translation with params:', {
|
|
1215
|
-
// state,
|
|
1216
|
-
// userLang,
|
|
1217
|
-
// msg
|
|
1218
|
-
// });
|
|
1219
|
-
|
|
1220
1255
|
const emission = state?.emission ?? currentDialogState?.emission;
|
|
1221
1256
|
|
|
1222
1257
|
let translatedState = { ...state };
|
|
@@ -1229,7 +1264,6 @@ const MemoriWidget = ({
|
|
|
1229
1264
|
!isMultilanguageEnabled ||
|
|
1230
1265
|
avoidPushingMessage
|
|
1231
1266
|
) {
|
|
1232
|
-
// console.log('[TRANSLATE] Skipping translation - using original emission');
|
|
1233
1267
|
translatedState = { ...state, emission };
|
|
1234
1268
|
if (emission) {
|
|
1235
1269
|
translatedMsg = {
|
|
@@ -1251,12 +1285,10 @@ const MemoriWidget = ({
|
|
|
1251
1285
|
}
|
|
1252
1286
|
} else {
|
|
1253
1287
|
try {
|
|
1254
|
-
// console.log('[TRANSLATE] Translating emission');
|
|
1255
1288
|
const t = await getTranslation(emission, userLang, language, baseUrl);
|
|
1256
1289
|
|
|
1257
1290
|
// Handle hints translation if present
|
|
1258
1291
|
if (state.hints && state.hints.length > 0) {
|
|
1259
|
-
// console.log('[TRANSLATE] Translating hints');
|
|
1260
1292
|
const translatedHints = await Promise.all(
|
|
1261
1293
|
(state.hints ?? []).map(async hint => {
|
|
1262
1294
|
const tHint = await getTranslation(
|
|
@@ -1288,7 +1320,6 @@ const MemoriWidget = ({
|
|
|
1288
1320
|
}
|
|
1289
1321
|
|
|
1290
1322
|
if (t.text.length > 0) {
|
|
1291
|
-
// console.log('[TRANSLATE] Creating translated message');
|
|
1292
1323
|
translatedMsg = {
|
|
1293
1324
|
text: emission,
|
|
1294
1325
|
translatedText: t.text,
|
|
@@ -1309,7 +1340,6 @@ const MemoriWidget = ({
|
|
|
1309
1340
|
};
|
|
1310
1341
|
}
|
|
1311
1342
|
} catch (error) {
|
|
1312
|
-
console.error('[TRANSLATE] Error during translation:', error);
|
|
1313
1343
|
translatedState = { ...state, emission };
|
|
1314
1344
|
translatedMsg = {
|
|
1315
1345
|
text: emission,
|
|
@@ -1330,10 +1360,8 @@ const MemoriWidget = ({
|
|
|
1330
1360
|
}
|
|
1331
1361
|
}
|
|
1332
1362
|
|
|
1333
|
-
// console.log('[TRANSLATE] Setting translated state and message');
|
|
1334
1363
|
setCurrentDialogState(translatedState);
|
|
1335
1364
|
if (!avoidPushingMessage && translatedMsg) {
|
|
1336
|
-
// console.log('[TRANSLATE] Pushing translated message', translatedMsg);
|
|
1337
1365
|
pushMessage(translatedMsg);
|
|
1338
1366
|
}
|
|
1339
1367
|
|
|
@@ -1439,7 +1467,6 @@ const MemoriWidget = ({
|
|
|
1439
1467
|
executableSnippets?.forEach(s => {
|
|
1440
1468
|
try {
|
|
1441
1469
|
setTimeout(() => {
|
|
1442
|
-
console.log('snippet', s);
|
|
1443
1470
|
// eslint-disable-next-line no-new-func
|
|
1444
1471
|
new Function(s.content ?? '')();
|
|
1445
1472
|
|
|
@@ -1453,8 +1480,8 @@ const MemoriWidget = ({
|
|
|
1453
1480
|
);
|
|
1454
1481
|
}, 400);
|
|
1455
1482
|
}, 1000);
|
|
1456
|
-
} catch
|
|
1457
|
-
|
|
1483
|
+
} catch {
|
|
1484
|
+
// ignore snippet execution errors
|
|
1458
1485
|
}
|
|
1459
1486
|
});
|
|
1460
1487
|
};
|
|
@@ -1505,6 +1532,10 @@ const MemoriWidget = ({
|
|
|
1505
1532
|
return;
|
|
1506
1533
|
}
|
|
1507
1534
|
|
|
1535
|
+
if (!(await checkCredits({ notify: true }))) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1508
1539
|
setLoading(true);
|
|
1509
1540
|
|
|
1510
1541
|
try {
|
|
@@ -1526,8 +1557,8 @@ const MemoriWidget = ({
|
|
|
1526
1557
|
referral = (() => {
|
|
1527
1558
|
return window.location.href;
|
|
1528
1559
|
})();
|
|
1529
|
-
} catch
|
|
1530
|
-
|
|
1560
|
+
} catch {
|
|
1561
|
+
// ignore referral URL errors
|
|
1531
1562
|
}
|
|
1532
1563
|
|
|
1533
1564
|
// Initialize session with parameters
|
|
@@ -1538,12 +1569,7 @@ const MemoriWidget = ({
|
|
|
1538
1569
|
pin: params.pin ?? personification?.pin,
|
|
1539
1570
|
additionalInfo: {
|
|
1540
1571
|
...(params.additionalInfo || additionalInfo || {}),
|
|
1541
|
-
loginToken:
|
|
1542
|
-
userToken ??
|
|
1543
|
-
loginToken ??
|
|
1544
|
-
params.additionalInfo?.loginToken ??
|
|
1545
|
-
additionalInfo?.loginToken ??
|
|
1546
|
-
authToken,
|
|
1572
|
+
loginToken: resolveLoginToken(params.additionalInfo?.loginToken),
|
|
1547
1573
|
language: (
|
|
1548
1574
|
userLang ??
|
|
1549
1575
|
memori.culture?.split('-')?.[0] ??
|
|
@@ -1589,7 +1615,7 @@ const MemoriWidget = ({
|
|
|
1589
1615
|
setGotErrorInOpening(true);
|
|
1590
1616
|
}
|
|
1591
1617
|
// Handle authentication error
|
|
1592
|
-
else if (session?.resultCode === 403) {
|
|
1618
|
+
else if (session?.resultCode === 403 && memori.privacyType !== 'PUBLIC') {
|
|
1593
1619
|
setMemoriPwd(undefined);
|
|
1594
1620
|
setAuthModalState('password');
|
|
1595
1621
|
return session;
|
|
@@ -1614,11 +1640,10 @@ const MemoriWidget = ({
|
|
|
1614
1640
|
duration: 0,
|
|
1615
1641
|
})
|
|
1616
1642
|
);
|
|
1617
|
-
setGotErrorInOpening(true);
|
|
1618
1643
|
return session;
|
|
1619
1644
|
}
|
|
1620
1645
|
} catch (err) {
|
|
1621
|
-
|
|
1646
|
+
logWidgetError('fetchSession failed', err);
|
|
1622
1647
|
}
|
|
1623
1648
|
};
|
|
1624
1649
|
|
|
@@ -1646,7 +1671,8 @@ const MemoriWidget = ({
|
|
|
1646
1671
|
additionalInfoProp?: { [key: string]: string | undefined },
|
|
1647
1672
|
continueFromChatLogID?: string,
|
|
1648
1673
|
continueFromSessionID?: string,
|
|
1649
|
-
isSessionExpired?: boolean
|
|
1674
|
+
isSessionExpired?: boolean,
|
|
1675
|
+
suppressHistoryUpdate?: boolean
|
|
1650
1676
|
) => {
|
|
1651
1677
|
// Set loading state while reopening session
|
|
1652
1678
|
setLoading(true);
|
|
@@ -1657,12 +1683,10 @@ const MemoriWidget = ({
|
|
|
1657
1683
|
undefined
|
|
1658
1684
|
);
|
|
1659
1685
|
let userBirthDate = birthDate ?? storageBirthDate;
|
|
1660
|
-
// console.log('[REOPEN_SESSION] Using birth date:', userBirthDate);
|
|
1661
1686
|
|
|
1662
1687
|
try {
|
|
1663
1688
|
// Show age verification if required and birth date not provided
|
|
1664
1689
|
if (!userBirthDate && !!minAge) {
|
|
1665
|
-
// console.log('[REOPEN_SESSION] Age verification required, showing modal');
|
|
1666
1690
|
setShowAgeVerification(true);
|
|
1667
1691
|
return;
|
|
1668
1692
|
}
|
|
@@ -1676,24 +1700,26 @@ const MemoriWidget = ({
|
|
|
1676
1700
|
!recoveryTokens &&
|
|
1677
1701
|
!memoriTokens
|
|
1678
1702
|
) {
|
|
1679
|
-
// console.log('[REOPEN_SESSION] Authentication required, showing modal');
|
|
1680
1703
|
setAuthModalState('password');
|
|
1681
1704
|
return;
|
|
1682
1705
|
}
|
|
1683
1706
|
|
|
1707
|
+
if (!(await checkCredits({ notify: true }))) {
|
|
1708
|
+
setLoading(false);
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1684
1712
|
// Get current URL as referral
|
|
1685
1713
|
let referral;
|
|
1686
1714
|
try {
|
|
1687
1715
|
referral = (() => {
|
|
1688
1716
|
return window.location.href;
|
|
1689
1717
|
})();
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
console.debug('[REOPEN_SESSION] Error getting referral:', err);
|
|
1718
|
+
} catch {
|
|
1719
|
+
// ignore referral URL errors
|
|
1693
1720
|
}
|
|
1694
1721
|
|
|
1695
1722
|
// Initialize session with provided parameters
|
|
1696
|
-
// console.log('[REOPEN_SESSION] Initializing session...');
|
|
1697
1723
|
const { sessionID, currentState, ...response } = await initSession({
|
|
1698
1724
|
memoriID: memori.engineMemoriID ?? '',
|
|
1699
1725
|
password: password || memoriPwd || memori.secretToken,
|
|
@@ -1712,12 +1738,7 @@ const MemoriWidget = ({
|
|
|
1712
1738
|
birthDate: userBirthDate,
|
|
1713
1739
|
additionalInfo: {
|
|
1714
1740
|
...(additionalInfoProp || additionalInfo || {}),
|
|
1715
|
-
loginToken:
|
|
1716
|
-
userToken ??
|
|
1717
|
-
loginToken ??
|
|
1718
|
-
additionalInfoProp?.loginToken ??
|
|
1719
|
-
additionalInfo?.loginToken ??
|
|
1720
|
-
authToken,
|
|
1741
|
+
loginToken: resolveLoginToken(additionalInfoProp?.loginToken),
|
|
1721
1742
|
language: (
|
|
1722
1743
|
userLang ??
|
|
1723
1744
|
memori.culture?.split('-')?.[0] ??
|
|
@@ -1730,27 +1751,34 @@ const MemoriWidget = ({
|
|
|
1730
1751
|
|
|
1731
1752
|
// Handle successful session initialization
|
|
1732
1753
|
if (sessionID && currentState && response.resultCode === 0) {
|
|
1733
|
-
console.log(
|
|
1734
|
-
'[REOPEN_SESSION] Session initialized successfully:',
|
|
1735
|
-
sessionID
|
|
1736
|
-
);
|
|
1737
1754
|
setSessionId(sessionID);
|
|
1738
1755
|
|
|
1739
1756
|
// Update dialog state and history if requested
|
|
1740
1757
|
if (updateDialogState) {
|
|
1741
|
-
// console.log('[REOPEN_SESSION] Updating dialog state');
|
|
1742
1758
|
setCurrentDialogState(currentState);
|
|
1743
1759
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1760
|
+
const sessionExpiredStatus =
|
|
1761
|
+
isSessionExpired && history.length > 1
|
|
1762
|
+
? t('sessionExpiredReopening')
|
|
1763
|
+
: null;
|
|
1764
|
+
|
|
1765
|
+
if (sessionExpiredStatus && suppressHistoryUpdate) {
|
|
1766
|
+
pushMessage({
|
|
1767
|
+
text: '',
|
|
1768
|
+
emitter: 'system',
|
|
1769
|
+
fromUser: false,
|
|
1770
|
+
initial: sessionExpiredStatus as any,
|
|
1771
|
+
contextVars: {},
|
|
1772
|
+
date: new Date().toISOString(),
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
if (currentState.emission && !suppressHistoryUpdate) {
|
|
1749
1777
|
// Determine initial status message based on context
|
|
1750
1778
|
// Show status message only if session expired and there's existing history
|
|
1751
1779
|
const initialStatus =
|
|
1752
|
-
|
|
1753
|
-
?
|
|
1780
|
+
sessionExpiredStatus
|
|
1781
|
+
? sessionExpiredStatus
|
|
1754
1782
|
: history.length <= 1
|
|
1755
1783
|
? true
|
|
1756
1784
|
: undefined;
|
|
@@ -1816,8 +1844,10 @@ const MemoriWidget = ({
|
|
|
1816
1844
|
setGotErrorInOpening(true);
|
|
1817
1845
|
}
|
|
1818
1846
|
// Handle authentication error
|
|
1819
|
-
else if (
|
|
1820
|
-
|
|
1847
|
+
else if (
|
|
1848
|
+
response?.resultCode === 403 &&
|
|
1849
|
+
memori.privacyType !== 'PUBLIC'
|
|
1850
|
+
) {
|
|
1821
1851
|
setMemoriPwd(undefined);
|
|
1822
1852
|
setAuthModalState('password');
|
|
1823
1853
|
}
|
|
@@ -1833,7 +1863,7 @@ const MemoriWidget = ({
|
|
|
1833
1863
|
setGotErrorInOpening(true);
|
|
1834
1864
|
}
|
|
1835
1865
|
} catch (err) {
|
|
1836
|
-
|
|
1866
|
+
logWidgetError('reopenSession failed', err);
|
|
1837
1867
|
}
|
|
1838
1868
|
// Reset loading state
|
|
1839
1869
|
setLoading(false);
|
|
@@ -1841,6 +1871,99 @@ const MemoriWidget = ({
|
|
|
1841
1871
|
return null;
|
|
1842
1872
|
};
|
|
1843
1873
|
|
|
1874
|
+
const retryAfterExpiredSessionRef = useRef<
|
|
1875
|
+
(params: EnterTextRetryParams) => ReturnType<typeof reopenSession>
|
|
1876
|
+
>(() => Promise.resolve(null));
|
|
1877
|
+
|
|
1878
|
+
retryAfterExpiredSessionRef.current = (params: EnterTextRetryParams) => {
|
|
1879
|
+
const {
|
|
1880
|
+
text,
|
|
1881
|
+
media,
|
|
1882
|
+
translate = true,
|
|
1883
|
+
translatedText,
|
|
1884
|
+
hidden = false,
|
|
1885
|
+
typingText,
|
|
1886
|
+
useLoaderTextAsMsg = false,
|
|
1887
|
+
hasBatchQueued = false,
|
|
1888
|
+
expiredSessionID,
|
|
1889
|
+
continueFromChatLogID: continueFromChatLogIDParam,
|
|
1890
|
+
} = params;
|
|
1891
|
+
|
|
1892
|
+
const continueFromSessionID = expiredSessionID ?? sessionId;
|
|
1893
|
+
const continueFromChatLogID = continueFromChatLogIDParam ?? chatLogID;
|
|
1894
|
+
|
|
1895
|
+
const reopenAfterExpiry = () =>
|
|
1896
|
+
reopenSession(
|
|
1897
|
+
true,
|
|
1898
|
+
memoriPwd || memori.secretToken,
|
|
1899
|
+
memoriTokens,
|
|
1900
|
+
undefined,
|
|
1901
|
+
undefined,
|
|
1902
|
+
{
|
|
1903
|
+
LANG: userLang,
|
|
1904
|
+
PATHNAME: window.location.pathname,
|
|
1905
|
+
ROUTE: window.location.pathname?.split('/')?.pop() || '',
|
|
1906
|
+
...(initialContextVars || {}),
|
|
1907
|
+
},
|
|
1908
|
+
initialQuestion,
|
|
1909
|
+
undefined,
|
|
1910
|
+
undefined,
|
|
1911
|
+
continueFromChatLogID,
|
|
1912
|
+
continueFromSessionID,
|
|
1913
|
+
true,
|
|
1914
|
+
true
|
|
1915
|
+
);
|
|
1916
|
+
|
|
1917
|
+
const scheduleRetry = (newSessionID: string) => {
|
|
1918
|
+
setTimeout(() => {
|
|
1919
|
+
sendMessage(
|
|
1920
|
+
text!,
|
|
1921
|
+
media,
|
|
1922
|
+
newSessionID,
|
|
1923
|
+
translate,
|
|
1924
|
+
translatedText,
|
|
1925
|
+
hidden,
|
|
1926
|
+
typingText,
|
|
1927
|
+
useLoaderTextAsMsg,
|
|
1928
|
+
hasBatchQueued,
|
|
1929
|
+
true
|
|
1930
|
+
);
|
|
1931
|
+
}, 500);
|
|
1932
|
+
};
|
|
1933
|
+
|
|
1934
|
+
const handleReopenFailure = (state: Awaited<ReturnType<typeof reopenSession>>) => {
|
|
1935
|
+
setMemoriTyping(false);
|
|
1936
|
+
setTypingText(undefined);
|
|
1937
|
+
// `null` = explicit failure; `undefined` = auth/age modal opened (message kept in history)
|
|
1938
|
+
if (state === null && text && !hidden) {
|
|
1939
|
+
add(
|
|
1940
|
+
createAlertOptions({
|
|
1941
|
+
description: t('errors.SESSION_EXPIRED'),
|
|
1942
|
+
severity: 'error',
|
|
1943
|
+
})
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1947
|
+
|
|
1948
|
+
if (!text) {
|
|
1949
|
+
return reopenAfterExpiry().then(state => {
|
|
1950
|
+
if (!state?.sessionID) {
|
|
1951
|
+
handleReopenFailure(state);
|
|
1952
|
+
}
|
|
1953
|
+
return state;
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
return reopenAfterExpiry().then(state => {
|
|
1958
|
+
if (state?.sessionID) {
|
|
1959
|
+
scheduleRetry(state.sessionID);
|
|
1960
|
+
} else {
|
|
1961
|
+
handleReopenFailure(state);
|
|
1962
|
+
}
|
|
1963
|
+
return state;
|
|
1964
|
+
});
|
|
1965
|
+
};
|
|
1966
|
+
|
|
1844
1967
|
const changeTag = async (
|
|
1845
1968
|
memoriId: string,
|
|
1846
1969
|
sessionId: string,
|
|
@@ -1848,7 +1971,6 @@ const MemoriWidget = ({
|
|
|
1848
1971
|
pin?: string
|
|
1849
1972
|
) => {
|
|
1850
1973
|
if (!memoriId || !sessionId) {
|
|
1851
|
-
console.error('CHANGETAG/Session not found');
|
|
1852
1974
|
return Promise.reject('Session not found');
|
|
1853
1975
|
}
|
|
1854
1976
|
|
|
@@ -1888,7 +2010,6 @@ const MemoriWidget = ({
|
|
|
1888
2010
|
};
|
|
1889
2011
|
}
|
|
1890
2012
|
} else if ([400, 401, 403, 404, 500].includes(resultCode)) {
|
|
1891
|
-
console.warn('[APPCONTEXT/CHANGETAG]', resultCode);
|
|
1892
2013
|
let storageBirthDate = getLocalConfig<string | undefined>(
|
|
1893
2014
|
'birthDate',
|
|
1894
2015
|
undefined
|
|
@@ -1899,8 +2020,8 @@ const MemoriWidget = ({
|
|
|
1899
2020
|
referral = (() => {
|
|
1900
2021
|
return window.location.href;
|
|
1901
2022
|
})();
|
|
1902
|
-
} catch
|
|
1903
|
-
|
|
2023
|
+
} catch {
|
|
2024
|
+
// ignore referral URL errors
|
|
1904
2025
|
}
|
|
1905
2026
|
|
|
1906
2027
|
fetchSession({
|
|
@@ -1918,11 +2039,7 @@ const MemoriWidget = ({
|
|
|
1918
2039
|
birthDate: birthDate || storageBirthDate || undefined,
|
|
1919
2040
|
additionalInfo: {
|
|
1920
2041
|
...(additionalInfo || {}),
|
|
1921
|
-
loginToken:
|
|
1922
|
-
userToken ??
|
|
1923
|
-
loginToken ??
|
|
1924
|
-
additionalInfo?.loginToken ??
|
|
1925
|
-
authToken,
|
|
2042
|
+
loginToken: resolveLoginToken(),
|
|
1926
2043
|
language: (
|
|
1927
2044
|
userLang ??
|
|
1928
2045
|
memori.culture?.split('-')?.[0] ??
|
|
@@ -1942,7 +2059,6 @@ const MemoriWidget = ({
|
|
|
1942
2059
|
}
|
|
1943
2060
|
} catch (_e) {
|
|
1944
2061
|
let err = _e as Error;
|
|
1945
|
-
console.warn('[APPCONTEXT/CHANGETAG]', err);
|
|
1946
2062
|
return Promise.reject(err);
|
|
1947
2063
|
}
|
|
1948
2064
|
|
|
@@ -1969,6 +2085,7 @@ const MemoriWidget = ({
|
|
|
1969
2085
|
return () => {
|
|
1970
2086
|
setHasUserActivatedSpeak(false);
|
|
1971
2087
|
setClickedStart(false);
|
|
2088
|
+
sessionStartingRef.current = false;
|
|
1972
2089
|
clearInteractionTimeout();
|
|
1973
2090
|
timeoutRef.current = undefined;
|
|
1974
2091
|
};
|
|
@@ -1981,8 +2098,6 @@ const MemoriWidget = ({
|
|
|
1981
2098
|
const [requestedListening, setRequestedListening] = useState(false);
|
|
1982
2099
|
const startListeningRef = useRef<(() => Promise<void>) | null>(null);
|
|
1983
2100
|
|
|
1984
|
-
// console.log('tenantID', tenantID);
|
|
1985
|
-
|
|
1986
2101
|
// Define TTS configuration
|
|
1987
2102
|
const ttsConfig = useMemo(
|
|
1988
2103
|
() => ({
|
|
@@ -2037,7 +2152,6 @@ const MemoriWidget = ({
|
|
|
2037
2152
|
'muteSpeaker',
|
|
2038
2153
|
!defaultEnableAudio
|
|
2039
2154
|
);
|
|
2040
|
-
console.log('[MemoriWidget] shouldPlayAudio', currentSpeakerMuted);
|
|
2041
2155
|
return (
|
|
2042
2156
|
text &&
|
|
2043
2157
|
text.trim() &&
|
|
@@ -2049,7 +2163,6 @@ const MemoriWidget = ({
|
|
|
2049
2163
|
|
|
2050
2164
|
// Create a single, centralized function to process and send messages
|
|
2051
2165
|
const processSpeechAndSendMessage = (text: string) => {
|
|
2052
|
-
// console.log('processSpeechAndSendMessage', text);
|
|
2053
2166
|
// Skip if already processing or no text
|
|
2054
2167
|
if (!text || text.trim().length === 0) {
|
|
2055
2168
|
return;
|
|
@@ -2058,17 +2171,15 @@ const MemoriWidget = ({
|
|
|
2058
2171
|
try {
|
|
2059
2172
|
// Process the text
|
|
2060
2173
|
const message = stripDuplicates(text);
|
|
2061
|
-
console.debug('Processing speech message:', message);
|
|
2062
2174
|
|
|
2063
2175
|
if (message.length > 0) {
|
|
2064
2176
|
setUserMessage('');
|
|
2065
2177
|
|
|
2066
2178
|
// Send the message
|
|
2067
|
-
console.debug('Sending message:', message);
|
|
2068
2179
|
sendMessage(message);
|
|
2069
2180
|
}
|
|
2070
|
-
} catch
|
|
2071
|
-
|
|
2181
|
+
} catch {
|
|
2182
|
+
// ignore speech processing errors
|
|
2072
2183
|
}
|
|
2073
2184
|
};
|
|
2074
2185
|
|
|
@@ -2148,8 +2259,7 @@ const MemoriWidget = ({
|
|
|
2148
2259
|
}
|
|
2149
2260
|
|
|
2150
2261
|
return translatedState;
|
|
2151
|
-
} catch
|
|
2152
|
-
console.error('Error in translateAndSpeak:', error);
|
|
2262
|
+
} catch {
|
|
2153
2263
|
// Still update activation state even if there's an error
|
|
2154
2264
|
if (!hasUserActivatedSpeak) {
|
|
2155
2265
|
setHasUserActivatedSpeak(true);
|
|
@@ -2166,6 +2276,277 @@ const MemoriWidget = ({
|
|
|
2166
2276
|
]
|
|
2167
2277
|
);
|
|
2168
2278
|
|
|
2279
|
+
const processEnterTextDialogResponse = useCallback(
|
|
2280
|
+
(event: NatsDialogResponseEvent, pending: PendingEnterText) => {
|
|
2281
|
+
const {
|
|
2282
|
+
msg,
|
|
2283
|
+
typingText: pendingTypingText,
|
|
2284
|
+
useLoaderTextAsMsg,
|
|
2285
|
+
} = pending;
|
|
2286
|
+
const currentState = event.currentState;
|
|
2287
|
+
|
|
2288
|
+
if (event.resultCode !== 0 || !currentState) {
|
|
2289
|
+
if (isSessionExpiredNatsResponse(event) && pending.text) {
|
|
2290
|
+
setMemoriTyping(false);
|
|
2291
|
+
setTypingText(undefined);
|
|
2292
|
+
retryAfterExpiredSessionRef.current({
|
|
2293
|
+
text: pending.text,
|
|
2294
|
+
media: pending.media,
|
|
2295
|
+
translate: pending.translate,
|
|
2296
|
+
translatedText: pending.translatedText,
|
|
2297
|
+
hidden: pending.hidden,
|
|
2298
|
+
typingText: pending.typingText,
|
|
2299
|
+
useLoaderTextAsMsg: pending.useLoaderTextAsMsg,
|
|
2300
|
+
hasBatchQueued: pending.hasBatchQueued,
|
|
2301
|
+
expiredSessionID: sessionId,
|
|
2302
|
+
continueFromChatLogID: chatLogID,
|
|
2303
|
+
});
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
if (event.resultCode === 500 && event.resultMessage) {
|
|
2308
|
+
setHistory(h => [
|
|
2309
|
+
...h,
|
|
2310
|
+
{
|
|
2311
|
+
text: 'Error: ' + event.resultMessage,
|
|
2312
|
+
emitter: 'system',
|
|
2313
|
+
fromUser: false,
|
|
2314
|
+
initial: false,
|
|
2315
|
+
contextVars: {},
|
|
2316
|
+
date: new Date().toISOString(),
|
|
2317
|
+
},
|
|
2318
|
+
]);
|
|
2319
|
+
}
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
if (!msg) {
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
setChatLogID(undefined);
|
|
2328
|
+
const emission =
|
|
2329
|
+
useLoaderTextAsMsg && pendingTypingText
|
|
2330
|
+
? pendingTypingText
|
|
2331
|
+
: currentState.emission ?? currentDialogState?.emission;
|
|
2332
|
+
|
|
2333
|
+
if (
|
|
2334
|
+
userLang.toLowerCase() !== language.toLowerCase() &&
|
|
2335
|
+
emission &&
|
|
2336
|
+
isMultilanguageEnabled
|
|
2337
|
+
) {
|
|
2338
|
+
currentState.emission = emission;
|
|
2339
|
+
|
|
2340
|
+
translateDialogState(currentState, userLang, msg).then(ts => {
|
|
2341
|
+
const text = ts.translatedEmission || ts.emission;
|
|
2342
|
+
if (text && shouldPlayAudio(text)) {
|
|
2343
|
+
handleSpeak(text);
|
|
2344
|
+
}
|
|
2345
|
+
});
|
|
2346
|
+
} else {
|
|
2347
|
+
setCurrentDialogState({
|
|
2348
|
+
...currentState,
|
|
2349
|
+
emission,
|
|
2350
|
+
});
|
|
2351
|
+
|
|
2352
|
+
if (emission) {
|
|
2353
|
+
pushMessage({
|
|
2354
|
+
text: emission,
|
|
2355
|
+
emitter: currentState.emitter,
|
|
2356
|
+
media: currentState.emittedMedia ?? currentState.media,
|
|
2357
|
+
llmUsage: (currentState as any).llmUsage,
|
|
2358
|
+
fromUser: false,
|
|
2359
|
+
questionAnswered: msg,
|
|
2360
|
+
generatedByAI: !!currentState.completion,
|
|
2361
|
+
contextVars: currentState.contextVars,
|
|
2362
|
+
date: currentState.currentDate,
|
|
2363
|
+
placeName: currentState.currentPlaceName,
|
|
2364
|
+
placeLatitude: currentState.currentLatitude,
|
|
2365
|
+
placeLongitude: currentState.currentLongitude,
|
|
2366
|
+
placeUncertaintyKm: currentState.currentUncertaintyKm,
|
|
2367
|
+
tag: currentState.currentTag,
|
|
2368
|
+
memoryTags: currentState.memoryTags,
|
|
2369
|
+
} as any);
|
|
2370
|
+
if (emission && shouldPlayAudio(emission)) {
|
|
2371
|
+
handleSpeak(emission);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
},
|
|
2376
|
+
[
|
|
2377
|
+
userLang,
|
|
2378
|
+
language,
|
|
2379
|
+
isMultilanguageEnabled,
|
|
2380
|
+
currentDialogState?.emission,
|
|
2381
|
+
translateDialogState,
|
|
2382
|
+
handleSpeak,
|
|
2383
|
+
shouldPlayAudio,
|
|
2384
|
+
]
|
|
2385
|
+
);
|
|
2386
|
+
|
|
2387
|
+
const clearEnterTextPending = useCallback(
|
|
2388
|
+
(correlationID: string, pending: PendingEnterText) => {
|
|
2389
|
+
if (pending.waitForResponse?.timeoutId) {
|
|
2390
|
+
clearTimeout(pending.waitForResponse.timeoutId);
|
|
2391
|
+
}
|
|
2392
|
+
pendingEnterTextRef.current.delete(correlationID);
|
|
2393
|
+
},
|
|
2394
|
+
[]
|
|
2395
|
+
);
|
|
2396
|
+
|
|
2397
|
+
const deliverEnterTextNatsError = useCallback(
|
|
2398
|
+
(event: NatsErrorEvent) => {
|
|
2399
|
+
const correlationID = event.correlationID;
|
|
2400
|
+
let pending: PendingEnterText | undefined;
|
|
2401
|
+
|
|
2402
|
+
if (correlationID) {
|
|
2403
|
+
pending = pendingEnterTextRef.current.get(correlationID);
|
|
2404
|
+
if (pending) {
|
|
2405
|
+
clearEnterTextPending(correlationID, pending);
|
|
2406
|
+
pending.waitForResponse?.reject(
|
|
2407
|
+
new Error(
|
|
2408
|
+
event.errorMessage ?? String(event.errorCode ?? 'NATS error')
|
|
2409
|
+
)
|
|
2410
|
+
);
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
if (isSessionExpiredNatsError(event) && pending?.text) {
|
|
2415
|
+
setMemoriTyping(false);
|
|
2416
|
+
setTypingText(undefined);
|
|
2417
|
+
retryAfterExpiredSessionRef.current({
|
|
2418
|
+
text: pending.text,
|
|
2419
|
+
media: pending.media,
|
|
2420
|
+
translate: pending.translate,
|
|
2421
|
+
translatedText: pending.translatedText,
|
|
2422
|
+
hidden: pending.hidden,
|
|
2423
|
+
typingText: pending.typingText,
|
|
2424
|
+
useLoaderTextAsMsg: pending.useLoaderTextAsMsg,
|
|
2425
|
+
hasBatchQueued: pending.hasBatchQueued,
|
|
2426
|
+
expiredSessionID: sessionId,
|
|
2427
|
+
continueFromChatLogID: chatLogID,
|
|
2428
|
+
});
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
const errorText = event.errorMessage
|
|
2433
|
+
? `Error: ${event.errorMessage}`
|
|
2434
|
+
: event.errorCode
|
|
2435
|
+
? `Error: ${event.errorCode}`
|
|
2436
|
+
: 'Error: An unexpected error occurred';
|
|
2437
|
+
|
|
2438
|
+
pushMessage({
|
|
2439
|
+
text: errorText,
|
|
2440
|
+
emitter: 'system',
|
|
2441
|
+
fromUser: false,
|
|
2442
|
+
initial: false,
|
|
2443
|
+
contextVars: {},
|
|
2444
|
+
date: new Date().toISOString(),
|
|
2445
|
+
});
|
|
2446
|
+
|
|
2447
|
+
setMemoriTyping(false);
|
|
2448
|
+
setTypingText(undefined);
|
|
2449
|
+
},
|
|
2450
|
+
[clearEnterTextPending]
|
|
2451
|
+
);
|
|
2452
|
+
|
|
2453
|
+
const deliverEnterTextNatsResponse = useCallback(
|
|
2454
|
+
(correlationID: string, event: NatsDialogResponseEvent) => {
|
|
2455
|
+
const pending = pendingEnterTextRef.current.get(correlationID);
|
|
2456
|
+
if (!pending) {
|
|
2457
|
+
bufferedNatsResponsesRef.current.set(correlationID, event);
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
clearEnterTextPending(correlationID, pending);
|
|
2462
|
+
|
|
2463
|
+
if (pending.waitForResponse) {
|
|
2464
|
+
pending.waitForResponse.resolve(event);
|
|
2465
|
+
setMemoriTyping(false);
|
|
2466
|
+
setTypingText(undefined);
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
processEnterTextDialogResponse(event, pending);
|
|
2471
|
+
|
|
2472
|
+
if (!pending.hasBatchQueued) {
|
|
2473
|
+
setMemoriTyping(false);
|
|
2474
|
+
setTypingText(undefined);
|
|
2475
|
+
}
|
|
2476
|
+
},
|
|
2477
|
+
[processEnterTextDialogResponse, clearEnterTextPending]
|
|
2478
|
+
);
|
|
2479
|
+
|
|
2480
|
+
const registerPendingEnterText = useCallback(
|
|
2481
|
+
(correlationID: string, pending: PendingEnterText) => {
|
|
2482
|
+
const buffered = bufferedNatsResponsesRef.current.get(correlationID);
|
|
2483
|
+
if (buffered) {
|
|
2484
|
+
bufferedNatsResponsesRef.current.delete(correlationID);
|
|
2485
|
+
pendingEnterTextRef.current.set(correlationID, pending);
|
|
2486
|
+
deliverEnterTextNatsResponse(correlationID, buffered);
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
pendingEnterTextRef.current.set(correlationID, pending);
|
|
2491
|
+
},
|
|
2492
|
+
[deliverEnterTextNatsResponse]
|
|
2493
|
+
);
|
|
2494
|
+
|
|
2495
|
+
const waitForEnterTextNatsResponse = useCallback(
|
|
2496
|
+
(correlationID: string, timeoutMs = 120000) =>
|
|
2497
|
+
new Promise<NatsDialogResponseEvent>((resolve, reject) => {
|
|
2498
|
+
const timeoutId = setTimeout(() => {
|
|
2499
|
+
const current = pendingEnterTextRef.current.get(correlationID);
|
|
2500
|
+
if (current) {
|
|
2501
|
+
clearEnterTextPending(correlationID, current);
|
|
2502
|
+
}
|
|
2503
|
+
logWidgetError('NATS timeout', { correlationID, timeoutMs });
|
|
2504
|
+
reject(new Error('NATS enter-text response timeout'));
|
|
2505
|
+
}, timeoutMs);
|
|
2506
|
+
|
|
2507
|
+
registerPendingEnterText(correlationID, {
|
|
2508
|
+
waitForResponse: {
|
|
2509
|
+
resolve: event => {
|
|
2510
|
+
clearTimeout(timeoutId);
|
|
2511
|
+
resolve(event);
|
|
2512
|
+
},
|
|
2513
|
+
reject: error => {
|
|
2514
|
+
clearTimeout(timeoutId);
|
|
2515
|
+
reject(error);
|
|
2516
|
+
},
|
|
2517
|
+
timeoutId,
|
|
2518
|
+
},
|
|
2519
|
+
});
|
|
2520
|
+
}),
|
|
2521
|
+
[registerPendingEnterText, clearEnterTextPending]
|
|
2522
|
+
);
|
|
2523
|
+
|
|
2524
|
+
// NATS subscription: receives progress updates and the async enter-text response.
|
|
2525
|
+
useNats({
|
|
2526
|
+
baseUrl,
|
|
2527
|
+
sessionId,
|
|
2528
|
+
onProgress: useCallback((event: NatsProgressEvent) => {
|
|
2529
|
+
if (event.message) {
|
|
2530
|
+
setTypingText(event.message);
|
|
2531
|
+
}
|
|
2532
|
+
}, []),
|
|
2533
|
+
onDialogResponse: useCallback(
|
|
2534
|
+
(event: NatsDialogResponseEvent) => {
|
|
2535
|
+
const correlationID = event.correlationID;
|
|
2536
|
+
if (!correlationID) {
|
|
2537
|
+
logWidgetError('NATS dialog response missing correlationID', event);
|
|
2538
|
+
setMemoriTyping(false);
|
|
2539
|
+
setTypingText(undefined);
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
deliverEnterTextNatsResponse(correlationID, event);
|
|
2544
|
+
},
|
|
2545
|
+
[deliverEnterTextNatsResponse]
|
|
2546
|
+
),
|
|
2547
|
+
onError: deliverEnterTextNatsError,
|
|
2548
|
+
});
|
|
2549
|
+
|
|
2169
2550
|
const focusChatInput = () => {
|
|
2170
2551
|
let textarea = document.querySelector(
|
|
2171
2552
|
'#chat-fieldset textarea'
|
|
@@ -2194,8 +2575,8 @@ const MemoriWidget = ({
|
|
|
2194
2575
|
setClickedStart(false);
|
|
2195
2576
|
timeoutRef.current = undefined;
|
|
2196
2577
|
ttsStop();
|
|
2197
|
-
} catch
|
|
2198
|
-
//
|
|
2578
|
+
} catch {
|
|
2579
|
+
// ignore reset errors
|
|
2199
2580
|
}
|
|
2200
2581
|
};
|
|
2201
2582
|
useEffect(() => {
|
|
@@ -2451,12 +2832,6 @@ const MemoriWidget = ({
|
|
|
2451
2832
|
chatLog?: ChatLog,
|
|
2452
2833
|
targetSessionID?: string
|
|
2453
2834
|
) => {
|
|
2454
|
-
// console.log('[onClickStart] Starting with params:', {
|
|
2455
|
-
// session,
|
|
2456
|
-
// initialSessionExpired,
|
|
2457
|
-
// chatLog
|
|
2458
|
-
// });
|
|
2459
|
-
|
|
2460
2835
|
const sessionID = chatLog ? undefined : session?.sessionID || sessionId;
|
|
2461
2836
|
const dialogState = chatLog
|
|
2462
2837
|
? undefined
|
|
@@ -2485,10 +2860,17 @@ const MemoriWidget = ({
|
|
|
2485
2860
|
return;
|
|
2486
2861
|
}
|
|
2487
2862
|
|
|
2863
|
+
if (!(await checkCredits({ notify: true }))) {
|
|
2864
|
+
setClickedStart(false);
|
|
2865
|
+
setLoading(false);
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2488
2869
|
// Handle age verification
|
|
2489
2870
|
if (!sessionID && !!minAge && !birth) {
|
|
2490
2871
|
setShowAgeVerification(true);
|
|
2491
2872
|
setClickedStart(false);
|
|
2873
|
+
return;
|
|
2492
2874
|
}
|
|
2493
2875
|
// Handle authentication
|
|
2494
2876
|
else if (
|
|
@@ -2505,42 +2887,43 @@ const MemoriWidget = ({
|
|
|
2505
2887
|
}
|
|
2506
2888
|
// Create new session if needed
|
|
2507
2889
|
else if (!sessionID || initialSessionExpired) {
|
|
2508
|
-
setClickedStart(false);
|
|
2509
2890
|
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
|
-
|
|
2891
|
+
if (sessionStartingRef.current) {
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
sessionStartingRef.current = true;
|
|
2895
|
+
try {
|
|
2896
|
+
const session = await fetchSession({
|
|
2897
|
+
memoriID: memori.engineMemoriID!,
|
|
2898
|
+
password: secret || memoriPwd || memori.secretToken,
|
|
2899
|
+
tag: personification?.tag,
|
|
2900
|
+
pin: personification?.pin,
|
|
2901
|
+
continueFromChatLogID: chatLog?.chatLogID,
|
|
2902
|
+
initialContextVars: {
|
|
2903
|
+
LANG: userLang,
|
|
2904
|
+
PATHNAME: window.location.pathname?.toUpperCase(),
|
|
2905
|
+
ROUTE:
|
|
2906
|
+
window.location.pathname?.split('/')?.pop()?.toUpperCase() ||
|
|
2907
|
+
'',
|
|
2908
|
+
...((!chatLog
|
|
2909
|
+
? initialContextVars
|
|
2910
|
+
: chatLog.lines[chatLog.lines.length - 1].contextVars) || {}),
|
|
2911
|
+
},
|
|
2912
|
+
initialQuestion: chatLog ? undefined : initialQuestion,
|
|
2913
|
+
birthDate: birth,
|
|
2914
|
+
additionalInfo: {
|
|
2915
|
+
...(additionalInfo || {}),
|
|
2916
|
+
loginToken: resolveLoginToken(),
|
|
2917
|
+
language: (
|
|
2918
|
+
userLang ??
|
|
2919
|
+
memori.culture?.split('-')?.[0] ??
|
|
2920
|
+
'IT'
|
|
2921
|
+
).toLowerCase(),
|
|
2922
|
+
timeZoneOffset: new Date().getTimezoneOffset().toString(),
|
|
2923
|
+
},
|
|
2924
|
+
});
|
|
2542
2925
|
|
|
2543
|
-
|
|
2926
|
+
if (session?.dialogState) {
|
|
2544
2927
|
// reset history
|
|
2545
2928
|
if (!chatLog) {
|
|
2546
2929
|
setHistory([]);
|
|
@@ -2549,6 +2932,7 @@ const MemoriWidget = ({
|
|
|
2549
2932
|
await translateAndSpeak(session.dialogState, userLang);
|
|
2550
2933
|
// No need for additional handleSpeak call since translateAndSpeak already handles it
|
|
2551
2934
|
setHasUserActivatedSpeak(true);
|
|
2935
|
+
setClickedStart(false);
|
|
2552
2936
|
} else {
|
|
2553
2937
|
const messages = chatLog.lines.map(
|
|
2554
2938
|
(l, i) =>
|
|
@@ -2596,8 +2980,8 @@ const MemoriWidget = ({
|
|
|
2596
2980
|
};
|
|
2597
2981
|
})
|
|
2598
2982
|
);
|
|
2599
|
-
} catch
|
|
2600
|
-
|
|
2983
|
+
} catch {
|
|
2984
|
+
// ignore translation errors
|
|
2601
2985
|
}
|
|
2602
2986
|
}
|
|
2603
2987
|
|
|
@@ -2610,12 +2994,18 @@ const MemoriWidget = ({
|
|
|
2610
2994
|
true
|
|
2611
2995
|
).finally(() => {
|
|
2612
2996
|
setHasUserActivatedSpeak(true);
|
|
2997
|
+
setClickedStart(false);
|
|
2613
2998
|
});
|
|
2614
2999
|
}
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
3000
|
+
} else if (session?.resultCode === 0) {
|
|
3001
|
+
sessionStartingRef.current = false;
|
|
3002
|
+
await onClickStart((session as any) || undefined);
|
|
3003
|
+
} else {
|
|
3004
|
+
setLoading(false);
|
|
3005
|
+
setClickedStart(false);
|
|
3006
|
+
}
|
|
3007
|
+
} finally {
|
|
3008
|
+
sessionStartingRef.current = false;
|
|
2619
3009
|
}
|
|
2620
3010
|
|
|
2621
3011
|
return;
|
|
@@ -2628,9 +3018,7 @@ const MemoriWidget = ({
|
|
|
2628
3018
|
|
|
2629
3019
|
if (response.resultCode !== 0 || !currentState) {
|
|
2630
3020
|
const { chatLogs } = await getSessionChatLogs(sessionID!, sessionID!);
|
|
2631
|
-
setGotErrorInOpening(true);
|
|
2632
3021
|
setSessionId(undefined);
|
|
2633
|
-
setClickedStart(false);
|
|
2634
3022
|
await onClickStart(undefined, true, chatLogs?.[0]);
|
|
2635
3023
|
return;
|
|
2636
3024
|
}
|
|
@@ -2656,11 +3044,11 @@ const MemoriWidget = ({
|
|
|
2656
3044
|
|
|
2657
3045
|
if (session && session.resultCode === 0) {
|
|
2658
3046
|
await translateAndSpeak(session.currentState, userLang);
|
|
3047
|
+
setClickedStart(false);
|
|
2659
3048
|
} else {
|
|
2660
3049
|
throw new Error('No session');
|
|
2661
3050
|
}
|
|
2662
|
-
} catch
|
|
2663
|
-
console.error('[onClickStart] Error changing tag:', e);
|
|
3051
|
+
} catch {
|
|
2664
3052
|
reopenSession(
|
|
2665
3053
|
true,
|
|
2666
3054
|
memori?.secretToken,
|
|
@@ -2679,6 +3067,7 @@ const MemoriWidget = ({
|
|
|
2679
3067
|
birth
|
|
2680
3068
|
).then(() => {
|
|
2681
3069
|
setHasUserActivatedSpeak(true);
|
|
3070
|
+
setClickedStart(false);
|
|
2682
3071
|
});
|
|
2683
3072
|
}
|
|
2684
3073
|
}
|
|
@@ -2701,6 +3090,7 @@ const MemoriWidget = ({
|
|
|
2701
3090
|
|
|
2702
3091
|
if (session && session.resultCode === 0) {
|
|
2703
3092
|
await translateAndSpeak(session.currentState, userLang);
|
|
3093
|
+
setClickedStart(false);
|
|
2704
3094
|
} else {
|
|
2705
3095
|
throw new Error('No session');
|
|
2706
3096
|
}
|
|
@@ -2723,6 +3113,7 @@ const MemoriWidget = ({
|
|
|
2723
3113
|
birth
|
|
2724
3114
|
).then(() => {
|
|
2725
3115
|
setHasUserActivatedSpeak(true);
|
|
3116
|
+
setClickedStart(false);
|
|
2726
3117
|
});
|
|
2727
3118
|
}
|
|
2728
3119
|
}
|
|
@@ -2769,14 +3160,14 @@ const MemoriWidget = ({
|
|
|
2769
3160
|
).text,
|
|
2770
3161
|
}))
|
|
2771
3162
|
);
|
|
2772
|
-
} catch
|
|
2773
|
-
|
|
3163
|
+
} catch {
|
|
3164
|
+
// ignore translation errors
|
|
2774
3165
|
}
|
|
2775
3166
|
}
|
|
2776
3167
|
|
|
2777
3168
|
setHistory(translatedMessages);
|
|
2778
|
-
} catch
|
|
2779
|
-
|
|
3169
|
+
} catch {
|
|
3170
|
+
// ignore chat log retrieval errors
|
|
2780
3171
|
}
|
|
2781
3172
|
|
|
2782
3173
|
if (
|
|
@@ -2785,6 +3176,7 @@ const MemoriWidget = ({
|
|
|
2785
3176
|
) {
|
|
2786
3177
|
// we have a history, don't push message
|
|
2787
3178
|
setHasUserActivatedSpeak(true);
|
|
3179
|
+
setClickedStart(false);
|
|
2788
3180
|
await translateAndSpeak(
|
|
2789
3181
|
currentState,
|
|
2790
3182
|
userLang,
|
|
@@ -2794,16 +3186,13 @@ const MemoriWidget = ({
|
|
|
2794
3186
|
!!translatedMessages?.length
|
|
2795
3187
|
);
|
|
2796
3188
|
} else {
|
|
2797
|
-
console.log('[onClickStart] Starting with initial question');
|
|
2798
3189
|
// remove default initial message
|
|
2799
3190
|
translatedMessages = [];
|
|
2800
3191
|
setHistory([]);
|
|
2801
3192
|
|
|
2802
|
-
setMemoriTyping(true);
|
|
2803
|
-
|
|
2804
3193
|
// we have no chat history, we start by initial question
|
|
2805
3194
|
const placeSpec = getPlaceSpecForEnterText(position);
|
|
2806
|
-
const response = await
|
|
3195
|
+
const response = await postEnterTextAsync({
|
|
2807
3196
|
sessionId: sessionID!,
|
|
2808
3197
|
text: initialQuestion,
|
|
2809
3198
|
...(memori.needsDateTime && {
|
|
@@ -2811,8 +3200,7 @@ const MemoriWidget = ({
|
|
|
2811
3200
|
}),
|
|
2812
3201
|
...(placeSpec !== undefined && { place: placeSpec }),
|
|
2813
3202
|
});
|
|
2814
|
-
|
|
2815
|
-
// Handle 500 error from TextEnteredEvent
|
|
3203
|
+
// Handle 500 error from EnterTextAsync
|
|
2816
3204
|
if (response.resultCode === 500 && response.resultMessage) {
|
|
2817
3205
|
setHistory(h => [
|
|
2818
3206
|
...h,
|
|
@@ -2825,16 +3213,33 @@ const MemoriWidget = ({
|
|
|
2825
3213
|
date: new Date().toISOString(),
|
|
2826
3214
|
},
|
|
2827
3215
|
]);
|
|
2828
|
-
setMemoriTyping(false);
|
|
2829
3216
|
return;
|
|
2830
3217
|
}
|
|
2831
3218
|
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
3219
|
+
const onClickStartCorrelationID = readCorrelationID(response);
|
|
3220
|
+
if (response.resultCode === 0 && onClickStartCorrelationID) {
|
|
3221
|
+
setMemoriTyping(true);
|
|
3222
|
+
try {
|
|
3223
|
+
const natsEvent = await waitForEnterTextNatsResponse(
|
|
3224
|
+
onClickStartCorrelationID
|
|
3225
|
+
);
|
|
3226
|
+
if (natsEvent.resultCode === 0 && natsEvent.currentState) {
|
|
3227
|
+
await translateAndSpeak(
|
|
3228
|
+
natsEvent.currentState,
|
|
3229
|
+
userLang,
|
|
3230
|
+
undefined,
|
|
3231
|
+
false
|
|
3232
|
+
);
|
|
3233
|
+
setClickedStart(false);
|
|
3234
|
+
}
|
|
3235
|
+
} catch (err) {
|
|
3236
|
+
logWidgetError('onClickStart NATS wait failed', err);
|
|
3237
|
+
setMemoriTyping(false);
|
|
3238
|
+
setTypingText(undefined);
|
|
3239
|
+
}
|
|
3240
|
+
} else if (response.resultCode === 0) {
|
|
3241
|
+
logWidgetError('onClickStart enter-text missing correlationID', response);
|
|
3242
|
+
}
|
|
2838
3243
|
}
|
|
2839
3244
|
}
|
|
2840
3245
|
}
|
|
@@ -2845,6 +3250,7 @@ const MemoriWidget = ({
|
|
|
2845
3250
|
|
|
2846
3251
|
// everything is fine, just translate dialog state and activate chat
|
|
2847
3252
|
await translateAndSpeak(dialogState!, userLang);
|
|
3253
|
+
setClickedStart(false);
|
|
2848
3254
|
}
|
|
2849
3255
|
},
|
|
2850
3256
|
[memoriPwd, memori, memoriTokens, birthDate, sessionId, userLang, position]
|
|
@@ -2861,10 +3267,24 @@ const MemoriWidget = ({
|
|
|
2861
3267
|
);
|
|
2862
3268
|
|
|
2863
3269
|
useEffect(() => {
|
|
2864
|
-
if (
|
|
3270
|
+
if (
|
|
3271
|
+
!clickedStart &&
|
|
3272
|
+
!sessionStartingRef.current &&
|
|
3273
|
+
!sessionId &&
|
|
3274
|
+
autoStart &&
|
|
3275
|
+
selectedLayout !== 'HIDDEN_CHAT' &&
|
|
3276
|
+
(!needsCredits || hasEnoughCredits)
|
|
3277
|
+
) {
|
|
2865
3278
|
onClickStart();
|
|
2866
3279
|
}
|
|
2867
|
-
}, [
|
|
3280
|
+
}, [
|
|
3281
|
+
clickedStart,
|
|
3282
|
+
autoStart,
|
|
3283
|
+
selectedLayout,
|
|
3284
|
+
sessionId,
|
|
3285
|
+
needsCredits,
|
|
3286
|
+
hasEnoughCredits,
|
|
3287
|
+
]);
|
|
2868
3288
|
|
|
2869
3289
|
useEffect(() => {
|
|
2870
3290
|
const targetNode =
|
|
@@ -2875,29 +3295,31 @@ const MemoriWidget = ({
|
|
|
2875
3295
|
return;
|
|
2876
3296
|
}
|
|
2877
3297
|
|
|
3298
|
+
const propsToken = additionalInfo?.loginToken ?? authToken;
|
|
3299
|
+
const initialDomToken = targetNode.getAttribute('authtoken') || undefined;
|
|
3300
|
+
if (initialDomToken && !propsToken) {
|
|
3301
|
+
setLoginToken(initialDomToken);
|
|
3302
|
+
userTokenRef.current = initialDomToken;
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
const applyAuthTokenFromElement = (element: Element) => {
|
|
3306
|
+
const clientNode =
|
|
3307
|
+
element.nodeName === 'MEMORI-CLIENT'
|
|
3308
|
+
? element
|
|
3309
|
+
: element.closest('memori-client') ?? element.parentElement;
|
|
3310
|
+
const token = clientNode?.getAttribute('authtoken') || undefined;
|
|
3311
|
+
setLoginToken(token);
|
|
3312
|
+
userTokenRef.current = token;
|
|
3313
|
+
};
|
|
3314
|
+
|
|
2878
3315
|
const config = { attributes: true, childList: false, subtree: false };
|
|
2879
|
-
const callback: MutationCallback =
|
|
3316
|
+
const callback: MutationCallback = mutationList => {
|
|
2880
3317
|
for (const mutation of mutationList) {
|
|
2881
3318
|
if (
|
|
2882
3319
|
mutation.type === 'attributes' &&
|
|
2883
3320
|
mutation.attributeName?.toLowerCase() === 'authtoken'
|
|
2884
3321
|
) {
|
|
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
|
-
}
|
|
3322
|
+
applyAuthTokenFromElement(mutation.target as Element);
|
|
2901
3323
|
}
|
|
2902
3324
|
}
|
|
2903
3325
|
};
|
|
@@ -2907,7 +3329,7 @@ const MemoriWidget = ({
|
|
|
2907
3329
|
return () => {
|
|
2908
3330
|
observer.disconnect();
|
|
2909
3331
|
};
|
|
2910
|
-
}, []);
|
|
3332
|
+
}, [memori.name, memori.memoriID, additionalInfo?.loginToken, authToken]);
|
|
2911
3333
|
|
|
2912
3334
|
/**
|
|
2913
3335
|
* Experts references
|
|
@@ -2921,11 +3343,9 @@ const MemoriWidget = ({
|
|
|
2921
3343
|
|
|
2922
3344
|
if (resp.resultCode === 0) {
|
|
2923
3345
|
setExperts(experts);
|
|
2924
|
-
} else {
|
|
2925
|
-
console.warn('Error fetching experts', resp);
|
|
2926
3346
|
}
|
|
2927
|
-
} catch
|
|
2928
|
-
|
|
3347
|
+
} catch {
|
|
3348
|
+
// ignore expert fetch errors
|
|
2929
3349
|
}
|
|
2930
3350
|
}, [sessionId, memori?.enableBoardOfExperts]);
|
|
2931
3351
|
useEffect(() => {
|
|
@@ -2938,39 +3358,74 @@ const MemoriWidget = ({
|
|
|
2938
3358
|
!!user?.userID &&
|
|
2939
3359
|
user?.pAndCUAccepted;
|
|
2940
3360
|
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
3361
|
+
const handleNotEnoughCredits = useCallback(() => {
|
|
3362
|
+
setHasEnoughCredits(false);
|
|
3363
|
+
setAuthModalState(null);
|
|
3364
|
+
add(
|
|
3365
|
+
createAlertOptions({
|
|
3366
|
+
description: t('notEnoughCredits'),
|
|
3367
|
+
severity: 'error',
|
|
3368
|
+
})
|
|
3369
|
+
);
|
|
3370
|
+
}, [add, t]);
|
|
3371
|
+
const checkCredits = useCallback(
|
|
3372
|
+
async (options?: { notify?: boolean }) => {
|
|
3373
|
+
if (!tenant?.billingDelegation) return true;
|
|
3374
|
+
|
|
3375
|
+
// Billing delegation is active: credits MUST be verified.
|
|
3376
|
+
// Without either owner identifier we cannot call the API, so we fail closed
|
|
3377
|
+
// instead of silently letting the session start unverified.
|
|
3378
|
+
if (!ownerUserID && !ownerUserName) {
|
|
3379
|
+
if (options?.notify) {
|
|
3380
|
+
handleNotEnoughCredits();
|
|
3381
|
+
} else {
|
|
3382
|
+
setHasEnoughCredits(false);
|
|
3383
|
+
}
|
|
3384
|
+
return false;
|
|
3385
|
+
}
|
|
2946
3386
|
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
3387
|
+
try {
|
|
3388
|
+
const resp = await getCredits({
|
|
3389
|
+
operation: deepThoughtEnabled
|
|
3390
|
+
? 'dt_session_creation'
|
|
3391
|
+
: 'session_creation',
|
|
3392
|
+
baseUrl: baseUrl,
|
|
3393
|
+
userID: ownerUserID,
|
|
3394
|
+
userName: ownerUserName,
|
|
3395
|
+
tenant: tenantID,
|
|
3396
|
+
});
|
|
2957
3397
|
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3398
|
+
if (resp.enough) {
|
|
3399
|
+
setHasEnoughCredits(true);
|
|
3400
|
+
return true;
|
|
3401
|
+
} else {
|
|
3402
|
+
if (options?.notify) {
|
|
3403
|
+
handleNotEnoughCredits();
|
|
3404
|
+
} else {
|
|
3405
|
+
setHasEnoughCredits(false);
|
|
3406
|
+
}
|
|
3407
|
+
return false;
|
|
3408
|
+
}
|
|
3409
|
+
} catch (err) {
|
|
3410
|
+
logWidgetError('checkCredits failed', err);
|
|
3411
|
+
return true;
|
|
2963
3412
|
}
|
|
2964
|
-
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
3413
|
+
},
|
|
3414
|
+
[
|
|
3415
|
+
baseUrl,
|
|
3416
|
+
deepThoughtEnabled,
|
|
3417
|
+
handleNotEnoughCredits,
|
|
3418
|
+
ownerUserID,
|
|
3419
|
+
ownerUserName,
|
|
3420
|
+
tenant?.billingDelegation,
|
|
3421
|
+
tenantID,
|
|
3422
|
+
]
|
|
3423
|
+
);
|
|
2969
3424
|
useEffect(() => {
|
|
2970
3425
|
if (tenant?.billingDelegation) {
|
|
2971
3426
|
checkCredits();
|
|
2972
3427
|
}
|
|
2973
|
-
}, [tenant?.billingDelegation, deepThoughtEnabled]);
|
|
3428
|
+
}, [tenant?.billingDelegation, deepThoughtEnabled, checkCredits]);
|
|
2974
3429
|
|
|
2975
3430
|
useEffect(() => {
|
|
2976
3431
|
if (__WEBCOMPONENT__) return;
|
|
@@ -3043,7 +3498,7 @@ const MemoriWidget = ({
|
|
|
3043
3498
|
setShowLoginDrawer(false);
|
|
3044
3499
|
setUser(undefined);
|
|
3045
3500
|
setLoginToken(undefined);
|
|
3046
|
-
|
|
3501
|
+
userTokenRef.current = undefined;
|
|
3047
3502
|
removeLocalConfig('loginToken');
|
|
3048
3503
|
});
|
|
3049
3504
|
},
|
|
@@ -3120,8 +3575,7 @@ const MemoriWidget = ({
|
|
|
3120
3575
|
showTypingText:
|
|
3121
3576
|
showTypingText ?? integrationConfig?.showTypingText ?? false,
|
|
3122
3577
|
history: showFullHistory ? history : history.slice(-2),
|
|
3123
|
-
authToken:
|
|
3124
|
-
loginToken ?? userToken ?? additionalInfo?.loginToken ?? authToken,
|
|
3578
|
+
authToken: resolveLoginToken(),
|
|
3125
3579
|
dialogState: currentDialogState,
|
|
3126
3580
|
pushMessage,
|
|
3127
3581
|
simulateUserPrompt,
|
|
@@ -3520,7 +3974,7 @@ const MemoriWidget = ({
|
|
|
3520
3974
|
setShowLoginDrawer(false);
|
|
3521
3975
|
setUser(user);
|
|
3522
3976
|
setLoginToken(token);
|
|
3523
|
-
|
|
3977
|
+
userTokenRef.current = token;
|
|
3524
3978
|
setLocalConfig('loginToken', token);
|
|
3525
3979
|
// Push a message with initial status to show status message when a new session is created after login
|
|
3526
3980
|
if (
|
|
@@ -3563,7 +4017,7 @@ const MemoriWidget = ({
|
|
|
3563
4017
|
setShowLoginDrawer(false);
|
|
3564
4018
|
setUser(undefined);
|
|
3565
4019
|
setLoginToken(undefined);
|
|
3566
|
-
|
|
4020
|
+
userTokenRef.current = undefined;
|
|
3567
4021
|
removeLocalConfig('loginToken');
|
|
3568
4022
|
});
|
|
3569
4023
|
}}
|