@memori.ai/memori-react 8.39.0 → 8.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/components/MemoriWidget/MemoriWidget.d.ts +2 -1
  3. package/dist/components/MemoriWidget/MemoriWidget.js +357 -73
  4. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  5. package/dist/helpers/credits.d.ts +3 -2
  6. package/dist/helpers/credits.js +4 -3
  7. package/dist/helpers/credits.js.map +1 -1
  8. package/dist/helpers/nats/getNatsConfig.d.ts +5 -0
  9. package/dist/helpers/nats/getNatsConfig.js +29 -0
  10. package/dist/helpers/nats/getNatsConfig.js.map +1 -0
  11. package/dist/helpers/nats/useNats.d.ts +12 -0
  12. package/dist/helpers/nats/useNats.js +72 -0
  13. package/dist/helpers/nats/useNats.js.map +1 -0
  14. package/dist/helpers/nats/useNatsSession.d.ts +27 -0
  15. package/dist/helpers/nats/useNatsSession.js +108 -0
  16. package/dist/helpers/nats/useNatsSession.js.map +1 -0
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/version.d.ts +1 -1
  20. package/dist/version.js +1 -1
  21. package/esm/components/MemoriWidget/MemoriWidget.d.ts +2 -1
  22. package/esm/components/MemoriWidget/MemoriWidget.js +357 -73
  23. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  24. package/esm/helpers/credits.d.ts +3 -2
  25. package/esm/helpers/credits.js +4 -3
  26. package/esm/helpers/credits.js.map +1 -1
  27. package/esm/helpers/nats/getNatsConfig.d.ts +5 -0
  28. package/esm/helpers/nats/getNatsConfig.js +25 -0
  29. package/esm/helpers/nats/getNatsConfig.js.map +1 -0
  30. package/esm/helpers/nats/useNats.d.ts +12 -0
  31. package/esm/helpers/nats/useNats.js +68 -0
  32. package/esm/helpers/nats/useNats.js.map +1 -0
  33. package/esm/helpers/nats/useNatsSession.d.ts +27 -0
  34. package/esm/helpers/nats/useNatsSession.js +103 -0
  35. package/esm/helpers/nats/useNatsSession.js.map +1 -0
  36. package/esm/index.js +1 -1
  37. package/esm/index.js.map +1 -1
  38. package/esm/version.d.ts +1 -1
  39. package/esm/version.js +1 -1
  40. package/package.json +3 -2
  41. package/src/components/MemoriWidget/MemoriWidget.tsx +475 -108
  42. package/src/components/layouts/layouts.stories.tsx +28 -34
  43. package/src/helpers/credits.ts +6 -3
  44. package/src/helpers/nats/getNatsConfig.ts +69 -0
  45. package/src/helpers/nats/useNats.ts +122 -0
  46. package/src/helpers/nats/useNatsSession.ts +210 -0
  47. package/src/index.stories.tsx +19 -3
  48. package/src/index.tsx +1 -0
  49. package/src/version.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
 
2
2
 
3
+ ## [8.40.0](https://github.com/memori-ai/memori-react/compare/v8.39.0...v8.40.0) (2026-06-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * enhance user identification for credit verification by adding ownerUserName ([540e50a](https://github.com/memori-ai/memori-react/commit/540e50aa7b913122e09d988a21701635342c1fe3))
9
+ * integrate NATS support for real-time event handling in MemoriWidget ([2fc0a8d](https://github.com/memori-ai/memori-react/commit/2fc0a8dcec8d6a04d89a7b014ca353fd478e847d))
10
+
11
+
12
+ ### Maintenance
13
+
14
+ * refactor MemoriWidget for improved NATS event handling ([7d18afa](https://github.com/memori-ai/memori-react/commit/7d18afa28d4f6cc24b3907d34bd34732e2a720c1))
15
+
3
16
  ## [8.39.0](https://github.com/memori-ai/memori-react/compare/v8.38.8...v8.39.0) (2026-06-12)
4
17
 
5
18
 
@@ -83,6 +83,7 @@ export interface LayoutProps {
83
83
  }
84
84
  export interface Props {
85
85
  memori: Memori;
86
+ ownerUserName?: string | null;
86
87
  ownerUserID?: string | null;
87
88
  tenantID: string;
88
89
  memoriConfigs?: MemoriConfig[];
@@ -148,5 +149,5 @@ export interface Props {
148
149
  maxTotalMessagePayload?: number;
149
150
  maxTextareaCharacters?: number;
150
151
  }
151
- declare const MemoriWidget: ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang, uiLang, spokenLang, multilingual, integration, layout, customLayout, showShare, preview, embed, showCopyButton, showTranslationOriginal, showInputs, showDates, showContextPerLine, showMessageConsumption, showSettings, showTypingText, showClear, showLogin, showUpload, showOnlyLastMessages, showChatHistory, showReasoning, avatar3dHidden, height, secret, baseUrl, apiURL, engineURL, initialContextVars, initialQuestion, ttsProvider, ogImage, sessionID: initialSessionID, tenant, personification, authToken, enableAudio, defaultSpeakerActive, disableTextEnteredEvents, onStateChange, additionalInfo, additionalSettings, customMediaRenderer, userAvatar, __WEBCOMPONENT__, useMathFormatting, autoStart, applyVarsToRoot, showFunctionCache, maxTotalMessagePayload, maxTextareaCharacters, }: Props) => JSX.Element;
152
+ declare const MemoriWidget: ({ memori, memoriConfigs, ownerUserID, ownerUserName, tenantID, memoriLang, uiLang, spokenLang, multilingual, integration, layout, customLayout, showShare, preview, embed, showCopyButton, showTranslationOriginal, showInputs, showDates, showContextPerLine, showMessageConsumption, showSettings, showTypingText, showClear, showLogin, showUpload, showOnlyLastMessages, showChatHistory, showReasoning, avatar3dHidden, height, secret, baseUrl, apiURL, engineURL, initialContextVars, initialQuestion, ttsProvider, ogImage, sessionID: initialSessionID, tenant, personification, authToken, enableAudio, defaultSpeakerActive, disableTextEnteredEvents, onStateChange, additionalInfo, additionalSettings, customMediaRenderer, userAvatar, __WEBCOMPONENT__, useMathFormatting, autoStart, applyVarsToRoot, showFunctionCache, maxTotalMessagePayload, maxTextareaCharacters, }: Props) => JSX.Element;
152
153
  export default MemoriWidget;
@@ -41,6 +41,7 @@ const sanitizer_1 = require("../../helpers/sanitizer");
41
41
  const useTTS_1 = require("../../helpers/tts/useTTS");
42
42
  const ChatHistory_1 = tslib_1.__importDefault(require("../ChatHistoryDrawer/ChatHistory"));
43
43
  const useSTT_1 = require("../../helpers/stt/useSTT");
44
+ const useNats_1 = require("../../helpers/nats/useNats");
44
45
  const getMemoriState = (integrationId) => {
45
46
  var _a, _b, _c, _d, _f;
46
47
  let widget = integrationId
@@ -68,6 +69,11 @@ const NULL_PLACE_SPEC = {
68
69
  longitude: null,
69
70
  uncertaintyKm: null,
70
71
  };
72
+ const ENTER_TEXT_NATS_TIMEOUT_MS = 120000;
73
+ function readCorrelationID(response) {
74
+ const value = response.correlationID;
75
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
76
+ }
71
77
  const typeMessage = (message, waitForPrevious = true, hidden = false, typingText, useLoaderTextAsMsg = false, hasBatchQueued = false) => {
72
78
  const e = new CustomEvent('MemoriTextEntered', {
73
79
  detail: {
@@ -164,7 +170,7 @@ window.typeBatchMessages = typeBatchMessages;
164
170
  let audioContext;
165
171
  let memoriPassword;
166
172
  let userToken;
167
- const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang, uiLang, spokenLang, multilingual, integration, layout, customLayout, showShare, preview = false, embed = false, showCopyButton = true, showTranslationOriginal = false, showInputs = true, showDates = false, showContextPerLine = false, showMessageConsumption = false, showSettings, showTypingText = false, showClear = false, showLogin = false, showUpload, showOnlyLastMessages, showChatHistory, showReasoning, avatar3dHidden, height = '100vh', secret, baseUrl = 'https://aisuru-staging.aclambda.online', apiURL = 'https://backend-staging.memori.ai', engineURL = 'https://engine-staging.memori.ai', initialContextVars, initialQuestion, ttsProvider, ogImage, sessionID: initialSessionID, tenant, personification, authToken, enableAudio, defaultSpeakerActive = true, disableTextEnteredEvents = false, onStateChange, additionalInfo, additionalSettings, customMediaRenderer, userAvatar, __WEBCOMPONENT__ = false, useMathFormatting = false, autoStart = false, applyVarsToRoot = false, showFunctionCache = false, maxTotalMessagePayload, maxTextareaCharacters, }) => {
173
+ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, ownerUserName, tenantID, memoriLang, uiLang, spokenLang, multilingual, integration, layout, customLayout, showShare, preview = false, embed = false, showCopyButton = true, showTranslationOriginal = false, showInputs = true, showDates = false, showContextPerLine = false, showMessageConsumption = false, showSettings, showTypingText = false, showClear = false, showLogin = false, showUpload, showOnlyLastMessages, showChatHistory, showReasoning, avatar3dHidden, height = '100vh', secret, baseUrl = 'https://aisuru-staging.aclambda.online', apiURL = 'https://backend-staging.memori.ai', engineURL = 'https://engine-staging.memori.ai', initialContextVars, initialQuestion, ttsProvider, ogImage, sessionID: initialSessionID, tenant, personification, authToken, enableAudio, defaultSpeakerActive = true, disableTextEnteredEvents = false, onStateChange, additionalInfo, additionalSettings, customMediaRenderer, userAvatar, __WEBCOMPONENT__ = false, useMathFormatting = false, autoStart = false, applyVarsToRoot = false, showFunctionCache = false, maxTotalMessagePayload, maxTextareaCharacters, }) => {
168
174
  var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
169
175
  const { t, i18n } = (0, react_i18next_1.useTranslation)();
170
176
  const [isClient, setIsClient] = (0, react_1.useState)(false);
@@ -172,7 +178,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
172
178
  setIsClient(true);
173
179
  }, []);
174
180
  const client = (0, memori_api_client_1.default)(apiURL, engineURL);
175
- const { initSession, deleteSession, postTextEnteredEvent, postPlaceChangedEvent, postDateChangedEvent, postTagChangedEvent, getSession, getExpertReferences, getSessionChatLogs, } = client;
181
+ const { initSession, deleteSession, postEnterTextAsync, postTextEnteredEvent, postPlaceChangedEvent, postDateChangedEvent, postTagChangedEvent, getSession, getExpertReferences, getSessionChatLogs, } = client;
176
182
  const [instruct, setInstruct] = (0, react_1.useState)(false);
177
183
  const [enableFocusChatInput, setEnableFocusChatInput] = (0, react_1.useState)(true);
178
184
  const [loginToken, setLoginToken] = (0, react_1.useState)((_a = additionalInfo === null || additionalInfo === void 0 ? void 0 : additionalInfo.loginToken) !== null && _a !== void 0 ? _a : authToken);
@@ -237,6 +243,8 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
237
243
  const [loading, setLoading] = (0, react_1.useState)(false);
238
244
  const [memoriTyping, setMemoriTyping] = (0, react_1.useState)(false);
239
245
  const [typingText, setTypingText] = (0, react_1.useState)();
246
+ const pendingEnterTextRef = (0, react_1.useRef)(new Map());
247
+ const bufferedNatsResponsesRef = (0, react_1.useRef)(new Map());
240
248
  const layoutName = typeof layout === 'string'
241
249
  ? layout
242
250
  : typeof (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.layout) === 'string'
@@ -385,7 +393,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
385
393
  };
386
394
  const [chatLogID, setChatLogID] = (0, react_1.useState)(undefined);
387
395
  const sendMessage = async (text, media, newSessionId, translate = true, translatedText, hidden = false, typingText, useLoaderTextAsMsg = false, hasBatchQueued = false) => {
388
- var _a, _b, _c, _d, _f, _g;
396
+ var _a, _b, _c, _d;
389
397
  const sessionID = newSessionId ||
390
398
  sessionId ||
391
399
  ((_a = window.getMemoriState()) === null || _a === void 0 ? void 0 : _a.sessionID);
@@ -439,12 +447,16 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
439
447
  ? !!newSessionId && newSessionId !== sessionId
440
448
  : !!newSessionId,
441
449
  });
442
- setMemoriTyping(true);
443
- setTypingText(typingText);
444
450
  let gotError = false;
445
451
  try {
446
452
  const placeSpec = getPlaceSpecForEnterText(position);
447
- const { currentState, ...response } = await postTextEnteredEvent({
453
+ console.debug('[EnterText] sendMessage: posting', {
454
+ sessionId: sessionID,
455
+ textLength: msg.length,
456
+ hasBatchQueued,
457
+ typingText,
458
+ });
459
+ const response = await postEnterTextAsync({
448
460
  sessionId: sessionID,
449
461
  text: msg,
450
462
  ...(memori.needsDateTime && {
@@ -452,57 +464,35 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
452
464
  }),
453
465
  ...(placeSpec !== undefined && { place: placeSpec }),
454
466
  });
455
- if (response.resultCode === 0 && currentState) {
456
- setChatLogID(undefined);
457
- const emission = useLoaderTextAsMsg && typingText
458
- ? typingText
459
- : (_c = currentState.emission) !== null && _c !== void 0 ? _c : currentDialogState === null || currentDialogState === void 0 ? void 0 : currentDialogState.emission;
460
- if (userLang.toLowerCase() !== language.toLowerCase() &&
461
- emission &&
462
- isMultilanguageEnabled) {
463
- currentState.emission = emission;
464
- translateDialogState(currentState, userLang, msg).then(ts => {
465
- let text = ts.translatedEmission || ts.emission;
466
- if (text && shouldPlayAudio(text)) {
467
- handleSpeak(text);
468
- }
469
- });
470
- }
471
- else {
472
- setCurrentDialogState({
473
- ...currentState,
474
- emission,
475
- });
476
- if (emission) {
477
- pushMessage({
478
- text: emission,
479
- emitter: currentState.emitter,
480
- media: (_d = currentState.emittedMedia) !== null && _d !== void 0 ? _d : currentState.media,
481
- llmUsage: currentState.llmUsage,
482
- fromUser: false,
483
- questionAnswered: msg,
484
- generatedByAI: !!currentState.completion,
485
- contextVars: currentState.contextVars,
486
- date: currentState.currentDate,
487
- placeName: currentState.currentPlaceName,
488
- placeLatitude: currentState.currentLatitude,
489
- placeLongitude: currentState.currentLongitude,
490
- placeUncertaintyKm: currentState.currentUncertaintyKm,
491
- tag: currentState.currentTag,
492
- memoryTags: currentState.memoryTags,
493
- });
494
- if (emission && shouldPlayAudio(emission)) {
495
- handleSpeak(emission);
496
- }
497
- }
498
- }
467
+ console.debug('[EnterText] sendMessage: HTTP response', {
468
+ resultCode: response.resultCode,
469
+ correlationID: readCorrelationID(response),
470
+ resultMessage: response.resultMessage,
471
+ });
472
+ const correlationID = readCorrelationID(response);
473
+ if (response.resultCode === 0 && correlationID) {
474
+ registerPendingEnterText(correlationID, {
475
+ msg,
476
+ typingText,
477
+ useLoaderTextAsMsg,
478
+ hasBatchQueued,
479
+ });
480
+ console.info('[EnterText] sendMessage: accepted, showing typing indicator', {
481
+ correlationID: correlationID,
482
+ typingText,
483
+ });
484
+ setMemoriTyping(true);
485
+ setTypingText(typingText);
486
+ }
487
+ else if (response.resultCode === 0) {
488
+ console.error('[EnterText] sendMessage: HTTP 200 but missing correlationID — cannot match NATS response', response);
499
489
  }
500
490
  else if (response.resultCode === 404) {
501
491
  setHistory(h => [...h.slice(0, h.length - 1)]);
502
492
  reopenSession(true, memoriPwd || memori.secretToken, memoriTokens, undefined, undefined, {
503
493
  LANG: userLang,
504
494
  PATHNAME: window.location.pathname,
505
- ROUTE: ((_g = (_f = window.location.pathname) === null || _f === void 0 ? void 0 : _f.split('/')) === null || _g === void 0 ? void 0 : _g.pop()) || '',
495
+ ROUTE: ((_d = (_c = window.location.pathname) === null || _c === void 0 ? void 0 : _c.split('/')) === null || _d === void 0 ? void 0 : _d.pop()) || '',
506
496
  ...(initialContextVars || {}),
507
497
  }, initialQuestion, undefined, undefined, undefined, undefined, true).then(state => {
508
498
  console.info('session timeout');
@@ -532,16 +522,11 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
532
522
  }
533
523
  }
534
524
  catch (error) {
535
- console.log('error', error);
536
- console.error(error);
525
+ console.error('[EnterText] sendMessage: request failed', error);
537
526
  gotError = true;
538
527
  setTypingText(undefined);
539
528
  setMemoriTyping(false);
540
529
  }
541
- if (!hasBatchQueued) {
542
- setTypingText(undefined);
543
- setMemoriTyping(false);
544
- }
545
530
  };
546
531
  const translateDialogState = async (state, userLang, msg, avoidPushingMessage = false) => {
547
532
  var _a, _b, _c, _d, _f, _g;
@@ -763,7 +748,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
763
748
  setAuthModalState('password');
764
749
  return;
765
750
  }
766
- if (!(await checkCredits({ notify: true, goBack: true }))) {
751
+ if (!(await checkCredits({ notify: true }))) {
767
752
  return;
768
753
  }
769
754
  setLoading(true);
@@ -846,7 +831,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
846
831
  setAuthModalState('password');
847
832
  return;
848
833
  }
849
- if (!(await checkCredits({ notify: true, goBack: true }))) {
834
+ if (!(await checkCredits({ notify: true }))) {
850
835
  setLoading(false);
851
836
  return null;
852
837
  }
@@ -1159,6 +1144,277 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1159
1144
  setHasUserActivatedSpeak,
1160
1145
  speakerMuted,
1161
1146
  ]);
1147
+ const processEnterTextDialogResponse = (0, react_1.useCallback)((event, pending) => {
1148
+ var _a, _b;
1149
+ console.debug('[EnterText] processDialogResponse', {
1150
+ correlationID: event.correlationID,
1151
+ resultCode: event.resultCode,
1152
+ hasCurrentState: !!event.currentState,
1153
+ hasBatchQueued: pending.hasBatchQueued,
1154
+ });
1155
+ const { msg, typingText: pendingTypingText, useLoaderTextAsMsg, } = pending;
1156
+ const currentState = event.currentState;
1157
+ if (event.resultCode !== 0 || !currentState) {
1158
+ if (event.resultCode === 500 && event.resultMessage) {
1159
+ console.warn('[EnterText] processDialogResponse: server error', {
1160
+ correlationID: event.correlationID,
1161
+ resultMessage: event.resultMessage,
1162
+ });
1163
+ setHistory(h => [
1164
+ ...h,
1165
+ {
1166
+ text: 'Error: ' + event.resultMessage,
1167
+ emitter: 'system',
1168
+ fromUser: false,
1169
+ initial: false,
1170
+ contextVars: {},
1171
+ date: new Date().toISOString(),
1172
+ },
1173
+ ]);
1174
+ }
1175
+ else if (event.resultCode !== 0) {
1176
+ console.warn('[SEND_MESSAGE/NATS]', event);
1177
+ }
1178
+ return;
1179
+ }
1180
+ if (!msg) {
1181
+ console.debug('[EnterText] processDialogResponse: no msg in pending, skipping');
1182
+ return;
1183
+ }
1184
+ setChatLogID(undefined);
1185
+ const emission = useLoaderTextAsMsg && pendingTypingText
1186
+ ? pendingTypingText
1187
+ : (_a = currentState.emission) !== null && _a !== void 0 ? _a : currentDialogState === null || currentDialogState === void 0 ? void 0 : currentDialogState.emission;
1188
+ console.debug('[EnterText] processDialogResponse: rendering emission', {
1189
+ correlationID: event.correlationID,
1190
+ emissionPreview: emission === null || emission === void 0 ? void 0 : emission.slice(0, 80),
1191
+ state: currentState.state,
1192
+ });
1193
+ if (userLang.toLowerCase() !== language.toLowerCase() &&
1194
+ emission &&
1195
+ isMultilanguageEnabled) {
1196
+ currentState.emission = emission;
1197
+ translateDialogState(currentState, userLang, msg).then(ts => {
1198
+ const text = ts.translatedEmission || ts.emission;
1199
+ if (text && shouldPlayAudio(text)) {
1200
+ handleSpeak(text);
1201
+ }
1202
+ });
1203
+ }
1204
+ else {
1205
+ setCurrentDialogState({
1206
+ ...currentState,
1207
+ emission,
1208
+ });
1209
+ if (emission) {
1210
+ pushMessage({
1211
+ text: emission,
1212
+ emitter: currentState.emitter,
1213
+ media: (_b = currentState.emittedMedia) !== null && _b !== void 0 ? _b : currentState.media,
1214
+ llmUsage: currentState.llmUsage,
1215
+ fromUser: false,
1216
+ questionAnswered: msg,
1217
+ generatedByAI: !!currentState.completion,
1218
+ contextVars: currentState.contextVars,
1219
+ date: currentState.currentDate,
1220
+ placeName: currentState.currentPlaceName,
1221
+ placeLatitude: currentState.currentLatitude,
1222
+ placeLongitude: currentState.currentLongitude,
1223
+ placeUncertaintyKm: currentState.currentUncertaintyKm,
1224
+ tag: currentState.currentTag,
1225
+ memoryTags: currentState.memoryTags,
1226
+ });
1227
+ if (emission && shouldPlayAudio(emission)) {
1228
+ handleSpeak(emission);
1229
+ }
1230
+ }
1231
+ }
1232
+ }, [
1233
+ userLang,
1234
+ language,
1235
+ isMultilanguageEnabled,
1236
+ currentDialogState === null || currentDialogState === void 0 ? void 0 : currentDialogState.emission,
1237
+ translateDialogState,
1238
+ handleSpeak,
1239
+ shouldPlayAudio,
1240
+ ]);
1241
+ const clearEnterTextPending = (0, react_1.useCallback)((correlationID, pending) => {
1242
+ var _a;
1243
+ if (pending.natsTimeoutId) {
1244
+ clearTimeout(pending.natsTimeoutId);
1245
+ }
1246
+ if ((_a = pending.waitForResponse) === null || _a === void 0 ? void 0 : _a.timeoutId) {
1247
+ clearTimeout(pending.waitForResponse.timeoutId);
1248
+ }
1249
+ pendingEnterTextRef.current.delete(correlationID);
1250
+ }, []);
1251
+ const deliverEnterTextNatsError = (0, react_1.useCallback)((event) => {
1252
+ var _a, _b, _c;
1253
+ const correlationID = event.correlationID;
1254
+ const errorText = event.errorMessage
1255
+ ? `Error: ${event.errorMessage}`
1256
+ : event.errorCode
1257
+ ? `Error: ${event.errorCode}`
1258
+ : 'Error: An unexpected error occurred';
1259
+ console.error('[EnterText] NATS error event', {
1260
+ correlationID,
1261
+ errorCode: event.errorCode,
1262
+ errorMessage: event.errorMessage,
1263
+ });
1264
+ pushMessage({
1265
+ text: errorText,
1266
+ emitter: 'system',
1267
+ fromUser: false,
1268
+ initial: false,
1269
+ contextVars: {},
1270
+ date: new Date().toISOString(),
1271
+ });
1272
+ if (correlationID) {
1273
+ const pending = pendingEnterTextRef.current.get(correlationID);
1274
+ if (pending) {
1275
+ clearEnterTextPending(correlationID, pending);
1276
+ (_a = pending.waitForResponse) === null || _a === void 0 ? void 0 : _a.reject(new Error((_b = event.errorMessage) !== null && _b !== void 0 ? _b : String((_c = event.errorCode) !== null && _c !== void 0 ? _c : 'NATS error')));
1277
+ }
1278
+ }
1279
+ setMemoriTyping(false);
1280
+ setTypingText(undefined);
1281
+ }, [clearEnterTextPending]);
1282
+ const deliverEnterTextNatsResponse = (0, react_1.useCallback)((correlationID, event) => {
1283
+ const pending = pendingEnterTextRef.current.get(correlationID);
1284
+ if (!pending) {
1285
+ const pendingCorrelationIDs = [...pendingEnterTextRef.current.keys()];
1286
+ console.warn('[EnterText] NATS response buffered (no matching pending)', {
1287
+ receivedCorrelationID: correlationID,
1288
+ resultCode: event.resultCode,
1289
+ pendingCorrelationIDs,
1290
+ hint: pendingCorrelationIDs.length > 0
1291
+ ? 'Use one of pendingCorrelationIDs in your nats pub correlation_id'
1292
+ : 'Send a message in the widget first, then copy correlationID from HTTP response logs',
1293
+ });
1294
+ bufferedNatsResponsesRef.current.set(correlationID, event);
1295
+ return;
1296
+ }
1297
+ clearEnterTextPending(correlationID, pending);
1298
+ if (pending.waitForResponse) {
1299
+ console.info('[EnterText] NATS response delivered to waiter', {
1300
+ correlationID,
1301
+ resultCode: event.resultCode,
1302
+ });
1303
+ pending.waitForResponse.resolve(event);
1304
+ setMemoriTyping(false);
1305
+ setTypingText(undefined);
1306
+ return;
1307
+ }
1308
+ processEnterTextDialogResponse(event, pending);
1309
+ if (!pending.hasBatchQueued) {
1310
+ console.info('[EnterText] typing indicator cleared', { correlationID });
1311
+ setMemoriTyping(false);
1312
+ setTypingText(undefined);
1313
+ }
1314
+ else {
1315
+ console.debug('[EnterText] typing kept (batch queued)', {
1316
+ correlationID,
1317
+ });
1318
+ }
1319
+ }, [processEnterTextDialogResponse, clearEnterTextPending]);
1320
+ const registerPendingEnterText = (0, react_1.useCallback)((correlationID, pending) => {
1321
+ const buffered = bufferedNatsResponsesRef.current.get(correlationID);
1322
+ if (buffered) {
1323
+ console.info('[EnterText] replaying buffered NATS response', {
1324
+ correlationID,
1325
+ waitForResponse: !!pending.waitForResponse,
1326
+ });
1327
+ bufferedNatsResponsesRef.current.delete(correlationID);
1328
+ pendingEnterTextRef.current.set(correlationID, pending);
1329
+ deliverEnterTextNatsResponse(correlationID, buffered);
1330
+ return;
1331
+ }
1332
+ if (!pending.waitForResponse && !pending.natsTimeoutId) {
1333
+ pending.natsTimeoutId = setTimeout(() => {
1334
+ var _a;
1335
+ const current = pendingEnterTextRef.current.get(correlationID);
1336
+ if (!current)
1337
+ return;
1338
+ clearEnterTextPending(correlationID, current);
1339
+ console.error('[EnterText] NATS response timeout', {
1340
+ correlationID,
1341
+ timeoutMs: ENTER_TEXT_NATS_TIMEOUT_MS,
1342
+ });
1343
+ if (!current.hasBatchQueued) {
1344
+ setMemoriTyping(false);
1345
+ setTypingText(undefined);
1346
+ }
1347
+ (_a = current.waitForResponse) === null || _a === void 0 ? void 0 : _a.reject(new Error('NATS enter-text response timeout'));
1348
+ }, ENTER_TEXT_NATS_TIMEOUT_MS);
1349
+ }
1350
+ console.debug('[EnterText] pending registered', {
1351
+ correlationID,
1352
+ waitForResponse: !!pending.waitForResponse,
1353
+ hasBatchQueued: pending.hasBatchQueued,
1354
+ });
1355
+ pendingEnterTextRef.current.set(correlationID, pending);
1356
+ }, [deliverEnterTextNatsResponse, clearEnterTextPending]);
1357
+ const waitForEnterTextNatsResponse = (0, react_1.useCallback)((correlationID, timeoutMs = 120000) => new Promise((resolve, reject) => {
1358
+ console.debug('[EnterText] waiting for NATS response', {
1359
+ correlationID,
1360
+ timeoutMs,
1361
+ });
1362
+ const timeoutId = setTimeout(() => {
1363
+ const current = pendingEnterTextRef.current.get(correlationID);
1364
+ if (current) {
1365
+ clearEnterTextPending(correlationID, current);
1366
+ }
1367
+ console.error('[EnterText] NATS response timeout', {
1368
+ correlationID,
1369
+ timeoutMs,
1370
+ });
1371
+ reject(new Error('NATS enter-text response timeout'));
1372
+ }, timeoutMs);
1373
+ registerPendingEnterText(correlationID, {
1374
+ waitForResponse: {
1375
+ resolve: event => {
1376
+ clearTimeout(timeoutId);
1377
+ resolve(event);
1378
+ },
1379
+ reject: error => {
1380
+ clearTimeout(timeoutId);
1381
+ reject(error);
1382
+ },
1383
+ timeoutId,
1384
+ },
1385
+ });
1386
+ }), [registerPendingEnterText, clearEnterTextPending]);
1387
+ (0, useNats_1.useNats)({
1388
+ baseUrl,
1389
+ sessionId,
1390
+ onProgress: (0, react_1.useCallback)((event) => {
1391
+ console.debug('[EnterText] NATS progress', {
1392
+ correlationID: event.correlationID,
1393
+ step: event.currentStep,
1394
+ finalStep: event.finalStep,
1395
+ message: event.message,
1396
+ });
1397
+ if (event.message) {
1398
+ setTypingText(event.message);
1399
+ }
1400
+ }, []),
1401
+ onDialogResponse: (0, react_1.useCallback)((event) => {
1402
+ const correlationID = event.correlationID;
1403
+ console.debug('[EnterText] NATS dialog.text_entered_response received', {
1404
+ correlationID,
1405
+ resultCode: event.resultCode,
1406
+ requestID: event.requestID,
1407
+ });
1408
+ if (!correlationID) {
1409
+ console.warn('[EnterText] dialog_text_entered_response without correlationID', event);
1410
+ setMemoriTyping(false);
1411
+ setTypingText(undefined);
1412
+ return;
1413
+ }
1414
+ deliverEnterTextNatsResponse(correlationID, event);
1415
+ }, [deliverEnterTextNatsResponse]),
1416
+ onError: deliverEnterTextNatsError,
1417
+ });
1162
1418
  const focusChatInput = () => {
1163
1419
  let textarea = document.querySelector('#chat-fieldset textarea');
1164
1420
  if (textarea && enableFocusChatInput) {
@@ -1353,7 +1609,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1353
1609
  };
1354
1610
  }, [sessionId, userLang, disableTextEnteredEvents]);
1355
1611
  const onClickStart = (0, react_1.useCallback)(async (session, initialSessionExpired = false, chatLog, targetSessionID) => {
1356
- var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
1612
+ var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
1357
1613
  const sessionID = chatLog ? undefined : (session === null || session === void 0 ? void 0 : session.sessionID) || sessionId;
1358
1614
  const dialogState = chatLog
1359
1615
  ? undefined
@@ -1370,7 +1626,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1370
1626
  setShowPositionDrawer(true);
1371
1627
  return;
1372
1628
  }
1373
- if (!(await checkCredits({ notify: true, goBack: true }))) {
1629
+ if (!(await checkCredits({ notify: true }))) {
1374
1630
  setClickedStart(false);
1375
1631
  setLoading(false);
1376
1632
  return;
@@ -1576,9 +1832,11 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1576
1832
  console.log('[onClickStart] Starting with initial question');
1577
1833
  translatedMessages = [];
1578
1834
  setHistory([]);
1579
- setMemoriTyping(true);
1580
1835
  const placeSpec = getPlaceSpecForEnterText(position);
1581
- const response = await postTextEnteredEvent({
1836
+ console.debug('[EnterText] onClickStart: posting initial question', {
1837
+ sessionId: sessionID,
1838
+ });
1839
+ const response = await postEnterTextAsync({
1582
1840
  sessionId: sessionID,
1583
1841
  text: initialQuestion,
1584
1842
  ...(memori.needsDateTime && {
@@ -1586,6 +1844,10 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1586
1844
  }),
1587
1845
  ...(placeSpec !== undefined && { place: placeSpec }),
1588
1846
  });
1847
+ console.debug('[EnterText] onClickStart: HTTP response', {
1848
+ resultCode: response.resultCode,
1849
+ correlationID: readCorrelationID(response),
1850
+ });
1589
1851
  if (response.resultCode === 500 && response.resultMessage) {
1590
1852
  setHistory(h => [
1591
1853
  ...h,
@@ -1598,10 +1860,33 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1598
1860
  date: new Date().toISOString(),
1599
1861
  },
1600
1862
  ]);
1601
- setMemoriTyping(false);
1602
1863
  return;
1603
1864
  }
1604
- await translateAndSpeak((_w = response.currentState) !== null && _w !== void 0 ? _w : currentState, userLang, undefined, false);
1865
+ const onClickStartCorrelationID = readCorrelationID(response);
1866
+ if (response.resultCode === 0 && onClickStartCorrelationID) {
1867
+ console.info('[EnterText] onClickStart: accepted, showing typing indicator', {
1868
+ correlationID: onClickStartCorrelationID,
1869
+ });
1870
+ setMemoriTyping(true);
1871
+ try {
1872
+ const natsEvent = await waitForEnterTextNatsResponse(onClickStartCorrelationID);
1873
+ console.info('[EnterText] onClickStart: NATS response received', {
1874
+ correlationID: onClickStartCorrelationID,
1875
+ resultCode: natsEvent.resultCode,
1876
+ });
1877
+ if (natsEvent.resultCode === 0 && natsEvent.currentState) {
1878
+ await translateAndSpeak(natsEvent.currentState, userLang, undefined, false);
1879
+ }
1880
+ }
1881
+ catch (e) {
1882
+ console.error('[EnterText] onClickStart: NATS wait failed', e);
1883
+ setMemoriTyping(false);
1884
+ setTypingText(undefined);
1885
+ }
1886
+ }
1887
+ else if (response.resultCode === 0) {
1888
+ console.error('[EnterText] onClickStart: HTTP 200 but missing correlationID', response);
1889
+ }
1605
1890
  }
1606
1891
  }
1607
1892
  }
@@ -1672,21 +1957,18 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1672
1957
  (user === null || user === void 0 ? void 0 : user.pAndCUAccepted);
1673
1958
  const needsCredits = tenant === null || tenant === void 0 ? void 0 : tenant.billingDelegation;
1674
1959
  const [hasEnoughCredits, setHasEnoughCredits] = (0, react_1.useState)(true);
1675
- const handleNotEnoughCredits = (0, react_1.useCallback)((goBack = false) => {
1960
+ const handleNotEnoughCredits = (0, react_1.useCallback)(() => {
1676
1961
  setHasEnoughCredits(false);
1677
1962
  setAuthModalState(null);
1678
1963
  react_hot_toast_1.default.error(t('notEnoughCredits'));
1679
- if (goBack && window.history.length > 1) {
1680
- window.history.back();
1681
- }
1682
1964
  }, [t]);
1683
1965
  const checkCredits = (0, react_1.useCallback)(async (options) => {
1684
1966
  if (!(tenant === null || tenant === void 0 ? void 0 : tenant.billingDelegation))
1685
1967
  return true;
1686
- if (!ownerUserID) {
1687
- console.warn('Cannot verify credits: missing ownerUserID');
1968
+ if (!ownerUserID && !ownerUserName) {
1969
+ console.warn('Cannot verify credits: missing owner identifier');
1688
1970
  if (options === null || options === void 0 ? void 0 : options.notify) {
1689
- handleNotEnoughCredits(!!options.goBack);
1971
+ handleNotEnoughCredits();
1690
1972
  }
1691
1973
  else {
1692
1974
  setHasEnoughCredits(false);
@@ -1700,6 +1982,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1700
1982
  : 'session_creation',
1701
1983
  baseUrl: baseUrl,
1702
1984
  userID: ownerUserID,
1985
+ userName: ownerUserName,
1703
1986
  tenant: tenantID,
1704
1987
  });
1705
1988
  if (resp.enough) {
@@ -1709,7 +1992,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1709
1992
  else {
1710
1993
  console.warn('Not enough credits. Required:', resp.required);
1711
1994
  if (options === null || options === void 0 ? void 0 : options.notify) {
1712
- handleNotEnoughCredits(!!options.goBack);
1995
+ handleNotEnoughCredits();
1713
1996
  }
1714
1997
  else {
1715
1998
  setHasEnoughCredits(false);
@@ -1727,6 +2010,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1727
2010
  deepThoughtEnabled,
1728
2011
  handleNotEnoughCredits,
1729
2012
  ownerUserID,
2013
+ ownerUserName,
1730
2014
  tenant === null || tenant === void 0 ? void 0 : tenant.billingDelegation,
1731
2015
  tenantID,
1732
2016
  ]);