@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
@@ -38,6 +38,7 @@ import { sanitizeText } from '../../helpers/sanitizer';
38
38
  import { useTTS } from '../../helpers/tts/useTTS';
39
39
  import ChatHistoryDrawer from '../ChatHistoryDrawer/ChatHistory';
40
40
  import { useSTT } from '../../helpers/stt/useSTT';
41
+ import { useNats } from '../../helpers/nats/useNats';
41
42
  const getMemoriState = (integrationId) => {
42
43
  var _a, _b, _c, _d, _f;
43
44
  let widget = integrationId
@@ -65,6 +66,11 @@ const NULL_PLACE_SPEC = {
65
66
  longitude: null,
66
67
  uncertaintyKm: null,
67
68
  };
69
+ const ENTER_TEXT_NATS_TIMEOUT_MS = 120000;
70
+ function readCorrelationID(response) {
71
+ const value = response.correlationID;
72
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
73
+ }
68
74
  const typeMessage = (message, waitForPrevious = true, hidden = false, typingText, useLoaderTextAsMsg = false, hasBatchQueued = false) => {
69
75
  const e = new CustomEvent('MemoriTextEntered', {
70
76
  detail: {
@@ -161,7 +167,7 @@ window.typeBatchMessages = typeBatchMessages;
161
167
  let audioContext;
162
168
  let memoriPassword;
163
169
  let userToken;
164
- 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, }) => {
170
+ 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, }) => {
165
171
  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;
166
172
  const { t, i18n } = useTranslation();
167
173
  const [isClient, setIsClient] = useState(false);
@@ -169,7 +175,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
169
175
  setIsClient(true);
170
176
  }, []);
171
177
  const client = memoriApiClient(apiURL, engineURL);
172
- const { initSession, deleteSession, postTextEnteredEvent, postPlaceChangedEvent, postDateChangedEvent, postTagChangedEvent, getSession, getExpertReferences, getSessionChatLogs, } = client;
178
+ const { initSession, deleteSession, postEnterTextAsync, postTextEnteredEvent, postPlaceChangedEvent, postDateChangedEvent, postTagChangedEvent, getSession, getExpertReferences, getSessionChatLogs, } = client;
173
179
  const [instruct, setInstruct] = useState(false);
174
180
  const [enableFocusChatInput, setEnableFocusChatInput] = useState(true);
175
181
  const [loginToken, setLoginToken] = useState((_a = additionalInfo === null || additionalInfo === void 0 ? void 0 : additionalInfo.loginToken) !== null && _a !== void 0 ? _a : authToken);
@@ -234,6 +240,8 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
234
240
  const [loading, setLoading] = useState(false);
235
241
  const [memoriTyping, setMemoriTyping] = useState(false);
236
242
  const [typingText, setTypingText] = useState();
243
+ const pendingEnterTextRef = useRef(new Map());
244
+ const bufferedNatsResponsesRef = useRef(new Map());
237
245
  const layoutName = typeof layout === 'string'
238
246
  ? layout
239
247
  : typeof (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.layout) === 'string'
@@ -382,7 +390,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
382
390
  };
383
391
  const [chatLogID, setChatLogID] = useState(undefined);
384
392
  const sendMessage = async (text, media, newSessionId, translate = true, translatedText, hidden = false, typingText, useLoaderTextAsMsg = false, hasBatchQueued = false) => {
385
- var _a, _b, _c, _d, _f, _g;
393
+ var _a, _b, _c, _d;
386
394
  const sessionID = newSessionId ||
387
395
  sessionId ||
388
396
  ((_a = window.getMemoriState()) === null || _a === void 0 ? void 0 : _a.sessionID);
@@ -436,12 +444,16 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
436
444
  ? !!newSessionId && newSessionId !== sessionId
437
445
  : !!newSessionId,
438
446
  });
439
- setMemoriTyping(true);
440
- setTypingText(typingText);
441
447
  let gotError = false;
442
448
  try {
443
449
  const placeSpec = getPlaceSpecForEnterText(position);
444
- const { currentState, ...response } = await postTextEnteredEvent({
450
+ console.debug('[EnterText] sendMessage: posting', {
451
+ sessionId: sessionID,
452
+ textLength: msg.length,
453
+ hasBatchQueued,
454
+ typingText,
455
+ });
456
+ const response = await postEnterTextAsync({
445
457
  sessionId: sessionID,
446
458
  text: msg,
447
459
  ...(memori.needsDateTime && {
@@ -449,57 +461,35 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
449
461
  }),
450
462
  ...(placeSpec !== undefined && { place: placeSpec }),
451
463
  });
452
- if (response.resultCode === 0 && currentState) {
453
- setChatLogID(undefined);
454
- const emission = useLoaderTextAsMsg && typingText
455
- ? typingText
456
- : (_c = currentState.emission) !== null && _c !== void 0 ? _c : currentDialogState === null || currentDialogState === void 0 ? void 0 : currentDialogState.emission;
457
- if (userLang.toLowerCase() !== language.toLowerCase() &&
458
- emission &&
459
- isMultilanguageEnabled) {
460
- currentState.emission = emission;
461
- translateDialogState(currentState, userLang, msg).then(ts => {
462
- let text = ts.translatedEmission || ts.emission;
463
- if (text && shouldPlayAudio(text)) {
464
- handleSpeak(text);
465
- }
466
- });
467
- }
468
- else {
469
- setCurrentDialogState({
470
- ...currentState,
471
- emission,
472
- });
473
- if (emission) {
474
- pushMessage({
475
- text: emission,
476
- emitter: currentState.emitter,
477
- media: (_d = currentState.emittedMedia) !== null && _d !== void 0 ? _d : currentState.media,
478
- llmUsage: currentState.llmUsage,
479
- fromUser: false,
480
- questionAnswered: msg,
481
- generatedByAI: !!currentState.completion,
482
- contextVars: currentState.contextVars,
483
- date: currentState.currentDate,
484
- placeName: currentState.currentPlaceName,
485
- placeLatitude: currentState.currentLatitude,
486
- placeLongitude: currentState.currentLongitude,
487
- placeUncertaintyKm: currentState.currentUncertaintyKm,
488
- tag: currentState.currentTag,
489
- memoryTags: currentState.memoryTags,
490
- });
491
- if (emission && shouldPlayAudio(emission)) {
492
- handleSpeak(emission);
493
- }
494
- }
495
- }
464
+ console.debug('[EnterText] sendMessage: HTTP response', {
465
+ resultCode: response.resultCode,
466
+ correlationID: readCorrelationID(response),
467
+ resultMessage: response.resultMessage,
468
+ });
469
+ const correlationID = readCorrelationID(response);
470
+ if (response.resultCode === 0 && correlationID) {
471
+ registerPendingEnterText(correlationID, {
472
+ msg,
473
+ typingText,
474
+ useLoaderTextAsMsg,
475
+ hasBatchQueued,
476
+ });
477
+ console.info('[EnterText] sendMessage: accepted, showing typing indicator', {
478
+ correlationID: correlationID,
479
+ typingText,
480
+ });
481
+ setMemoriTyping(true);
482
+ setTypingText(typingText);
483
+ }
484
+ else if (response.resultCode === 0) {
485
+ console.error('[EnterText] sendMessage: HTTP 200 but missing correlationID — cannot match NATS response', response);
496
486
  }
497
487
  else if (response.resultCode === 404) {
498
488
  setHistory(h => [...h.slice(0, h.length - 1)]);
499
489
  reopenSession(true, memoriPwd || memori.secretToken, memoriTokens, undefined, undefined, {
500
490
  LANG: userLang,
501
491
  PATHNAME: window.location.pathname,
502
- ROUTE: ((_g = (_f = window.location.pathname) === null || _f === void 0 ? void 0 : _f.split('/')) === null || _g === void 0 ? void 0 : _g.pop()) || '',
492
+ ROUTE: ((_d = (_c = window.location.pathname) === null || _c === void 0 ? void 0 : _c.split('/')) === null || _d === void 0 ? void 0 : _d.pop()) || '',
503
493
  ...(initialContextVars || {}),
504
494
  }, initialQuestion, undefined, undefined, undefined, undefined, true).then(state => {
505
495
  console.info('session timeout');
@@ -529,16 +519,11 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
529
519
  }
530
520
  }
531
521
  catch (error) {
532
- console.log('error', error);
533
- console.error(error);
522
+ console.error('[EnterText] sendMessage: request failed', error);
534
523
  gotError = true;
535
524
  setTypingText(undefined);
536
525
  setMemoriTyping(false);
537
526
  }
538
- if (!hasBatchQueued) {
539
- setTypingText(undefined);
540
- setMemoriTyping(false);
541
- }
542
527
  };
543
528
  const translateDialogState = async (state, userLang, msg, avoidPushingMessage = false) => {
544
529
  var _a, _b, _c, _d, _f, _g;
@@ -760,7 +745,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
760
745
  setAuthModalState('password');
761
746
  return;
762
747
  }
763
- if (!(await checkCredits({ notify: true, goBack: true }))) {
748
+ if (!(await checkCredits({ notify: true }))) {
764
749
  return;
765
750
  }
766
751
  setLoading(true);
@@ -843,7 +828,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
843
828
  setAuthModalState('password');
844
829
  return;
845
830
  }
846
- if (!(await checkCredits({ notify: true, goBack: true }))) {
831
+ if (!(await checkCredits({ notify: true }))) {
847
832
  setLoading(false);
848
833
  return null;
849
834
  }
@@ -1156,6 +1141,277 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1156
1141
  setHasUserActivatedSpeak,
1157
1142
  speakerMuted,
1158
1143
  ]);
1144
+ const processEnterTextDialogResponse = useCallback((event, pending) => {
1145
+ var _a, _b;
1146
+ console.debug('[EnterText] processDialogResponse', {
1147
+ correlationID: event.correlationID,
1148
+ resultCode: event.resultCode,
1149
+ hasCurrentState: !!event.currentState,
1150
+ hasBatchQueued: pending.hasBatchQueued,
1151
+ });
1152
+ const { msg, typingText: pendingTypingText, useLoaderTextAsMsg, } = pending;
1153
+ const currentState = event.currentState;
1154
+ if (event.resultCode !== 0 || !currentState) {
1155
+ if (event.resultCode === 500 && event.resultMessage) {
1156
+ console.warn('[EnterText] processDialogResponse: server error', {
1157
+ correlationID: event.correlationID,
1158
+ resultMessage: event.resultMessage,
1159
+ });
1160
+ setHistory(h => [
1161
+ ...h,
1162
+ {
1163
+ text: 'Error: ' + event.resultMessage,
1164
+ emitter: 'system',
1165
+ fromUser: false,
1166
+ initial: false,
1167
+ contextVars: {},
1168
+ date: new Date().toISOString(),
1169
+ },
1170
+ ]);
1171
+ }
1172
+ else if (event.resultCode !== 0) {
1173
+ console.warn('[SEND_MESSAGE/NATS]', event);
1174
+ }
1175
+ return;
1176
+ }
1177
+ if (!msg) {
1178
+ console.debug('[EnterText] processDialogResponse: no msg in pending, skipping');
1179
+ return;
1180
+ }
1181
+ setChatLogID(undefined);
1182
+ const emission = useLoaderTextAsMsg && pendingTypingText
1183
+ ? pendingTypingText
1184
+ : (_a = currentState.emission) !== null && _a !== void 0 ? _a : currentDialogState === null || currentDialogState === void 0 ? void 0 : currentDialogState.emission;
1185
+ console.debug('[EnterText] processDialogResponse: rendering emission', {
1186
+ correlationID: event.correlationID,
1187
+ emissionPreview: emission === null || emission === void 0 ? void 0 : emission.slice(0, 80),
1188
+ state: currentState.state,
1189
+ });
1190
+ if (userLang.toLowerCase() !== language.toLowerCase() &&
1191
+ emission &&
1192
+ isMultilanguageEnabled) {
1193
+ currentState.emission = emission;
1194
+ translateDialogState(currentState, userLang, msg).then(ts => {
1195
+ const text = ts.translatedEmission || ts.emission;
1196
+ if (text && shouldPlayAudio(text)) {
1197
+ handleSpeak(text);
1198
+ }
1199
+ });
1200
+ }
1201
+ else {
1202
+ setCurrentDialogState({
1203
+ ...currentState,
1204
+ emission,
1205
+ });
1206
+ if (emission) {
1207
+ pushMessage({
1208
+ text: emission,
1209
+ emitter: currentState.emitter,
1210
+ media: (_b = currentState.emittedMedia) !== null && _b !== void 0 ? _b : currentState.media,
1211
+ llmUsage: currentState.llmUsage,
1212
+ fromUser: false,
1213
+ questionAnswered: msg,
1214
+ generatedByAI: !!currentState.completion,
1215
+ contextVars: currentState.contextVars,
1216
+ date: currentState.currentDate,
1217
+ placeName: currentState.currentPlaceName,
1218
+ placeLatitude: currentState.currentLatitude,
1219
+ placeLongitude: currentState.currentLongitude,
1220
+ placeUncertaintyKm: currentState.currentUncertaintyKm,
1221
+ tag: currentState.currentTag,
1222
+ memoryTags: currentState.memoryTags,
1223
+ });
1224
+ if (emission && shouldPlayAudio(emission)) {
1225
+ handleSpeak(emission);
1226
+ }
1227
+ }
1228
+ }
1229
+ }, [
1230
+ userLang,
1231
+ language,
1232
+ isMultilanguageEnabled,
1233
+ currentDialogState === null || currentDialogState === void 0 ? void 0 : currentDialogState.emission,
1234
+ translateDialogState,
1235
+ handleSpeak,
1236
+ shouldPlayAudio,
1237
+ ]);
1238
+ const clearEnterTextPending = useCallback((correlationID, pending) => {
1239
+ var _a;
1240
+ if (pending.natsTimeoutId) {
1241
+ clearTimeout(pending.natsTimeoutId);
1242
+ }
1243
+ if ((_a = pending.waitForResponse) === null || _a === void 0 ? void 0 : _a.timeoutId) {
1244
+ clearTimeout(pending.waitForResponse.timeoutId);
1245
+ }
1246
+ pendingEnterTextRef.current.delete(correlationID);
1247
+ }, []);
1248
+ const deliverEnterTextNatsError = useCallback((event) => {
1249
+ var _a, _b, _c;
1250
+ const correlationID = event.correlationID;
1251
+ const errorText = event.errorMessage
1252
+ ? `Error: ${event.errorMessage}`
1253
+ : event.errorCode
1254
+ ? `Error: ${event.errorCode}`
1255
+ : 'Error: An unexpected error occurred';
1256
+ console.error('[EnterText] NATS error event', {
1257
+ correlationID,
1258
+ errorCode: event.errorCode,
1259
+ errorMessage: event.errorMessage,
1260
+ });
1261
+ pushMessage({
1262
+ text: errorText,
1263
+ emitter: 'system',
1264
+ fromUser: false,
1265
+ initial: false,
1266
+ contextVars: {},
1267
+ date: new Date().toISOString(),
1268
+ });
1269
+ if (correlationID) {
1270
+ const pending = pendingEnterTextRef.current.get(correlationID);
1271
+ if (pending) {
1272
+ clearEnterTextPending(correlationID, pending);
1273
+ (_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')));
1274
+ }
1275
+ }
1276
+ setMemoriTyping(false);
1277
+ setTypingText(undefined);
1278
+ }, [clearEnterTextPending]);
1279
+ const deliverEnterTextNatsResponse = useCallback((correlationID, event) => {
1280
+ const pending = pendingEnterTextRef.current.get(correlationID);
1281
+ if (!pending) {
1282
+ const pendingCorrelationIDs = [...pendingEnterTextRef.current.keys()];
1283
+ console.warn('[EnterText] NATS response buffered (no matching pending)', {
1284
+ receivedCorrelationID: correlationID,
1285
+ resultCode: event.resultCode,
1286
+ pendingCorrelationIDs,
1287
+ hint: pendingCorrelationIDs.length > 0
1288
+ ? 'Use one of pendingCorrelationIDs in your nats pub correlation_id'
1289
+ : 'Send a message in the widget first, then copy correlationID from HTTP response logs',
1290
+ });
1291
+ bufferedNatsResponsesRef.current.set(correlationID, event);
1292
+ return;
1293
+ }
1294
+ clearEnterTextPending(correlationID, pending);
1295
+ if (pending.waitForResponse) {
1296
+ console.info('[EnterText] NATS response delivered to waiter', {
1297
+ correlationID,
1298
+ resultCode: event.resultCode,
1299
+ });
1300
+ pending.waitForResponse.resolve(event);
1301
+ setMemoriTyping(false);
1302
+ setTypingText(undefined);
1303
+ return;
1304
+ }
1305
+ processEnterTextDialogResponse(event, pending);
1306
+ if (!pending.hasBatchQueued) {
1307
+ console.info('[EnterText] typing indicator cleared', { correlationID });
1308
+ setMemoriTyping(false);
1309
+ setTypingText(undefined);
1310
+ }
1311
+ else {
1312
+ console.debug('[EnterText] typing kept (batch queued)', {
1313
+ correlationID,
1314
+ });
1315
+ }
1316
+ }, [processEnterTextDialogResponse, clearEnterTextPending]);
1317
+ const registerPendingEnterText = useCallback((correlationID, pending) => {
1318
+ const buffered = bufferedNatsResponsesRef.current.get(correlationID);
1319
+ if (buffered) {
1320
+ console.info('[EnterText] replaying buffered NATS response', {
1321
+ correlationID,
1322
+ waitForResponse: !!pending.waitForResponse,
1323
+ });
1324
+ bufferedNatsResponsesRef.current.delete(correlationID);
1325
+ pendingEnterTextRef.current.set(correlationID, pending);
1326
+ deliverEnterTextNatsResponse(correlationID, buffered);
1327
+ return;
1328
+ }
1329
+ if (!pending.waitForResponse && !pending.natsTimeoutId) {
1330
+ pending.natsTimeoutId = setTimeout(() => {
1331
+ var _a;
1332
+ const current = pendingEnterTextRef.current.get(correlationID);
1333
+ if (!current)
1334
+ return;
1335
+ clearEnterTextPending(correlationID, current);
1336
+ console.error('[EnterText] NATS response timeout', {
1337
+ correlationID,
1338
+ timeoutMs: ENTER_TEXT_NATS_TIMEOUT_MS,
1339
+ });
1340
+ if (!current.hasBatchQueued) {
1341
+ setMemoriTyping(false);
1342
+ setTypingText(undefined);
1343
+ }
1344
+ (_a = current.waitForResponse) === null || _a === void 0 ? void 0 : _a.reject(new Error('NATS enter-text response timeout'));
1345
+ }, ENTER_TEXT_NATS_TIMEOUT_MS);
1346
+ }
1347
+ console.debug('[EnterText] pending registered', {
1348
+ correlationID,
1349
+ waitForResponse: !!pending.waitForResponse,
1350
+ hasBatchQueued: pending.hasBatchQueued,
1351
+ });
1352
+ pendingEnterTextRef.current.set(correlationID, pending);
1353
+ }, [deliverEnterTextNatsResponse, clearEnterTextPending]);
1354
+ const waitForEnterTextNatsResponse = useCallback((correlationID, timeoutMs = 120000) => new Promise((resolve, reject) => {
1355
+ console.debug('[EnterText] waiting for NATS response', {
1356
+ correlationID,
1357
+ timeoutMs,
1358
+ });
1359
+ const timeoutId = setTimeout(() => {
1360
+ const current = pendingEnterTextRef.current.get(correlationID);
1361
+ if (current) {
1362
+ clearEnterTextPending(correlationID, current);
1363
+ }
1364
+ console.error('[EnterText] NATS response timeout', {
1365
+ correlationID,
1366
+ timeoutMs,
1367
+ });
1368
+ reject(new Error('NATS enter-text response timeout'));
1369
+ }, timeoutMs);
1370
+ registerPendingEnterText(correlationID, {
1371
+ waitForResponse: {
1372
+ resolve: event => {
1373
+ clearTimeout(timeoutId);
1374
+ resolve(event);
1375
+ },
1376
+ reject: error => {
1377
+ clearTimeout(timeoutId);
1378
+ reject(error);
1379
+ },
1380
+ timeoutId,
1381
+ },
1382
+ });
1383
+ }), [registerPendingEnterText, clearEnterTextPending]);
1384
+ useNats({
1385
+ baseUrl,
1386
+ sessionId,
1387
+ onProgress: useCallback((event) => {
1388
+ console.debug('[EnterText] NATS progress', {
1389
+ correlationID: event.correlationID,
1390
+ step: event.currentStep,
1391
+ finalStep: event.finalStep,
1392
+ message: event.message,
1393
+ });
1394
+ if (event.message) {
1395
+ setTypingText(event.message);
1396
+ }
1397
+ }, []),
1398
+ onDialogResponse: useCallback((event) => {
1399
+ const correlationID = event.correlationID;
1400
+ console.debug('[EnterText] NATS dialog.text_entered_response received', {
1401
+ correlationID,
1402
+ resultCode: event.resultCode,
1403
+ requestID: event.requestID,
1404
+ });
1405
+ if (!correlationID) {
1406
+ console.warn('[EnterText] dialog_text_entered_response without correlationID', event);
1407
+ setMemoriTyping(false);
1408
+ setTypingText(undefined);
1409
+ return;
1410
+ }
1411
+ deliverEnterTextNatsResponse(correlationID, event);
1412
+ }, [deliverEnterTextNatsResponse]),
1413
+ onError: deliverEnterTextNatsError,
1414
+ });
1159
1415
  const focusChatInput = () => {
1160
1416
  let textarea = document.querySelector('#chat-fieldset textarea');
1161
1417
  if (textarea && enableFocusChatInput) {
@@ -1350,7 +1606,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1350
1606
  };
1351
1607
  }, [sessionId, userLang, disableTextEnteredEvents]);
1352
1608
  const onClickStart = useCallback(async (session, initialSessionExpired = false, chatLog, targetSessionID) => {
1353
- var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
1609
+ var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
1354
1610
  const sessionID = chatLog ? undefined : (session === null || session === void 0 ? void 0 : session.sessionID) || sessionId;
1355
1611
  const dialogState = chatLog
1356
1612
  ? undefined
@@ -1367,7 +1623,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1367
1623
  setShowPositionDrawer(true);
1368
1624
  return;
1369
1625
  }
1370
- if (!(await checkCredits({ notify: true, goBack: true }))) {
1626
+ if (!(await checkCredits({ notify: true }))) {
1371
1627
  setClickedStart(false);
1372
1628
  setLoading(false);
1373
1629
  return;
@@ -1573,9 +1829,11 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1573
1829
  console.log('[onClickStart] Starting with initial question');
1574
1830
  translatedMessages = [];
1575
1831
  setHistory([]);
1576
- setMemoriTyping(true);
1577
1832
  const placeSpec = getPlaceSpecForEnterText(position);
1578
- const response = await postTextEnteredEvent({
1833
+ console.debug('[EnterText] onClickStart: posting initial question', {
1834
+ sessionId: sessionID,
1835
+ });
1836
+ const response = await postEnterTextAsync({
1579
1837
  sessionId: sessionID,
1580
1838
  text: initialQuestion,
1581
1839
  ...(memori.needsDateTime && {
@@ -1583,6 +1841,10 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1583
1841
  }),
1584
1842
  ...(placeSpec !== undefined && { place: placeSpec }),
1585
1843
  });
1844
+ console.debug('[EnterText] onClickStart: HTTP response', {
1845
+ resultCode: response.resultCode,
1846
+ correlationID: readCorrelationID(response),
1847
+ });
1586
1848
  if (response.resultCode === 500 && response.resultMessage) {
1587
1849
  setHistory(h => [
1588
1850
  ...h,
@@ -1595,10 +1857,33 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1595
1857
  date: new Date().toISOString(),
1596
1858
  },
1597
1859
  ]);
1598
- setMemoriTyping(false);
1599
1860
  return;
1600
1861
  }
1601
- await translateAndSpeak((_w = response.currentState) !== null && _w !== void 0 ? _w : currentState, userLang, undefined, false);
1862
+ const onClickStartCorrelationID = readCorrelationID(response);
1863
+ if (response.resultCode === 0 && onClickStartCorrelationID) {
1864
+ console.info('[EnterText] onClickStart: accepted, showing typing indicator', {
1865
+ correlationID: onClickStartCorrelationID,
1866
+ });
1867
+ setMemoriTyping(true);
1868
+ try {
1869
+ const natsEvent = await waitForEnterTextNatsResponse(onClickStartCorrelationID);
1870
+ console.info('[EnterText] onClickStart: NATS response received', {
1871
+ correlationID: onClickStartCorrelationID,
1872
+ resultCode: natsEvent.resultCode,
1873
+ });
1874
+ if (natsEvent.resultCode === 0 && natsEvent.currentState) {
1875
+ await translateAndSpeak(natsEvent.currentState, userLang, undefined, false);
1876
+ }
1877
+ }
1878
+ catch (e) {
1879
+ console.error('[EnterText] onClickStart: NATS wait failed', e);
1880
+ setMemoriTyping(false);
1881
+ setTypingText(undefined);
1882
+ }
1883
+ }
1884
+ else if (response.resultCode === 0) {
1885
+ console.error('[EnterText] onClickStart: HTTP 200 but missing correlationID', response);
1886
+ }
1602
1887
  }
1603
1888
  }
1604
1889
  }
@@ -1669,21 +1954,18 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1669
1954
  (user === null || user === void 0 ? void 0 : user.pAndCUAccepted);
1670
1955
  const needsCredits = tenant === null || tenant === void 0 ? void 0 : tenant.billingDelegation;
1671
1956
  const [hasEnoughCredits, setHasEnoughCredits] = useState(true);
1672
- const handleNotEnoughCredits = useCallback((goBack = false) => {
1957
+ const handleNotEnoughCredits = useCallback(() => {
1673
1958
  setHasEnoughCredits(false);
1674
1959
  setAuthModalState(null);
1675
1960
  toast.error(t('notEnoughCredits'));
1676
- if (goBack && window.history.length > 1) {
1677
- window.history.back();
1678
- }
1679
1961
  }, [t]);
1680
1962
  const checkCredits = useCallback(async (options) => {
1681
1963
  if (!(tenant === null || tenant === void 0 ? void 0 : tenant.billingDelegation))
1682
1964
  return true;
1683
- if (!ownerUserID) {
1684
- console.warn('Cannot verify credits: missing ownerUserID');
1965
+ if (!ownerUserID && !ownerUserName) {
1966
+ console.warn('Cannot verify credits: missing owner identifier');
1685
1967
  if (options === null || options === void 0 ? void 0 : options.notify) {
1686
- handleNotEnoughCredits(!!options.goBack);
1968
+ handleNotEnoughCredits();
1687
1969
  }
1688
1970
  else {
1689
1971
  setHasEnoughCredits(false);
@@ -1697,6 +1979,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1697
1979
  : 'session_creation',
1698
1980
  baseUrl: baseUrl,
1699
1981
  userID: ownerUserID,
1982
+ userName: ownerUserName,
1700
1983
  tenant: tenantID,
1701
1984
  });
1702
1985
  if (resp.enough) {
@@ -1706,7 +1989,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1706
1989
  else {
1707
1990
  console.warn('Not enough credits. Required:', resp.required);
1708
1991
  if (options === null || options === void 0 ? void 0 : options.notify) {
1709
- handleNotEnoughCredits(!!options.goBack);
1992
+ handleNotEnoughCredits();
1710
1993
  }
1711
1994
  else {
1712
1995
  setHasEnoughCredits(false);
@@ -1724,6 +2007,7 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, tenantID, memoriLang
1724
2007
  deepThoughtEnabled,
1725
2008
  handleNotEnoughCredits,
1726
2009
  ownerUserID,
2010
+ ownerUserName,
1727
2011
  tenant === null || tenant === void 0 ? void 0 : tenant.billingDelegation,
1728
2012
  tenantID,
1729
2013
  ]);