@memori.ai/memori-react 8.40.0 → 8.40.2

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.
@@ -131,6 +131,10 @@ const NULL_PLACE_SPEC = {
131
131
 
132
132
  const ENTER_TEXT_NATS_TIMEOUT_MS = 120_000;
133
133
 
134
+ const logWidgetError = (context: string, detail?: unknown) => {
135
+ console.error(`[MemoriWidget] ${context}`, detail ?? '');
136
+ };
137
+
134
138
  /** Reads correlation id from HTTP async response (supports camelCase / snake_case). */
135
139
  function readCorrelationID(response: {
136
140
  correlationID?: string;
@@ -582,6 +586,7 @@ const MemoriWidget = ({
582
586
  const [showLoginDrawer, setShowLoginDrawer] = useState(false);
583
587
 
584
588
  const [clickedStart, setClickedStart] = useState(false);
589
+ const sessionStartingRef = useRef(false);
585
590
 
586
591
  const language =
587
592
  memori.culture?.split('-')?.[0]?.toUpperCase()! ||
@@ -984,12 +989,6 @@ const MemoriWidget = ({
984
989
 
985
990
  try {
986
991
  const placeSpec = getPlaceSpecForEnterText(position);
987
- console.debug('[EnterText] sendMessage: posting', {
988
- sessionId: sessionID,
989
- textLength: msg.length,
990
- hasBatchQueued,
991
- typingText,
992
- });
993
992
  const response = await postEnterTextAsync({
994
993
  sessionId: sessionID,
995
994
  text: msg,
@@ -998,11 +997,6 @@ const MemoriWidget = ({
998
997
  }),
999
998
  ...(placeSpec !== undefined && { place: placeSpec }),
1000
999
  });
1001
- console.debug('[EnterText] sendMessage: HTTP response', {
1002
- resultCode: response.resultCode,
1003
- correlationID: readCorrelationID(response),
1004
- resultMessage: response.resultMessage,
1005
- });
1006
1000
  const correlationID = readCorrelationID(response);
1007
1001
  if (response.resultCode === 0 && correlationID) {
1008
1002
  registerPendingEnterText(correlationID, {
@@ -1011,20 +1005,10 @@ const MemoriWidget = ({
1011
1005
  useLoaderTextAsMsg,
1012
1006
  hasBatchQueued,
1013
1007
  });
1014
- console.info(
1015
- '[EnterText] sendMessage: accepted, showing typing indicator',
1016
- {
1017
- correlationID: correlationID,
1018
- typingText,
1019
- }
1020
- );
1021
1008
  setMemoriTyping(true);
1022
1009
  setTypingText(typingText);
1023
1010
  } else if (response.resultCode === 0) {
1024
- console.error(
1025
- '[EnterText] sendMessage: HTTP 200 but missing correlationID — cannot match NATS response',
1026
- response
1027
- );
1011
+ logWidgetError('enter-text missing correlationID', response);
1028
1012
  } else if (response.resultCode === 404) {
1029
1013
  // Handle expired session
1030
1014
  // remove last sent message, will set it as initial
@@ -1049,7 +1033,6 @@ const MemoriWidget = ({
1049
1033
  undefined,
1050
1034
  true // isSessionExpired
1051
1035
  ).then(state => {
1052
- console.info('session timeout');
1053
1036
  if (state?.sessionID) {
1054
1037
  setTimeout(() => {
1055
1038
  sendMessage(text, media, state?.sessionID);
@@ -1069,12 +1052,11 @@ const MemoriWidget = ({
1069
1052
  },
1070
1053
  ]);
1071
1054
  } else {
1072
- console.warn('[SEND_MESSAGE]', response);
1073
1055
  return Promise.reject(response);
1074
1056
  }
1075
1057
  } catch (error) {
1076
- console.error('[EnterText] sendMessage: request failed', error);
1077
1058
  gotError = true;
1059
+ logWidgetError('sendMessage failed', error);
1078
1060
 
1079
1061
  setTypingText(undefined);
1080
1062
  setMemoriTyping(false);
@@ -1091,12 +1073,6 @@ const MemoriWidget = ({
1091
1073
  msg?: string,
1092
1074
  avoidPushingMessage: boolean = false
1093
1075
  ) => {
1094
- // console.log('[TRANSLATE] Starting translation with params:', {
1095
- // state,
1096
- // userLang,
1097
- // msg
1098
- // });
1099
-
1100
1076
  const emission = state?.emission ?? currentDialogState?.emission;
1101
1077
 
1102
1078
  let translatedState = { ...state };
@@ -1109,7 +1085,6 @@ const MemoriWidget = ({
1109
1085
  !isMultilanguageEnabled ||
1110
1086
  avoidPushingMessage
1111
1087
  ) {
1112
- // console.log('[TRANSLATE] Skipping translation - using original emission');
1113
1088
  translatedState = { ...state, emission };
1114
1089
  if (emission) {
1115
1090
  translatedMsg = {
@@ -1131,12 +1106,10 @@ const MemoriWidget = ({
1131
1106
  }
1132
1107
  } else {
1133
1108
  try {
1134
- // console.log('[TRANSLATE] Translating emission');
1135
1109
  const t = await getTranslation(emission, userLang, language, baseUrl);
1136
1110
 
1137
1111
  // Handle hints translation if present
1138
1112
  if (state.hints && state.hints.length > 0) {
1139
- // console.log('[TRANSLATE] Translating hints');
1140
1113
  const translatedHints = await Promise.all(
1141
1114
  (state.hints ?? []).map(async hint => {
1142
1115
  const tHint = await getTranslation(
@@ -1168,7 +1141,6 @@ const MemoriWidget = ({
1168
1141
  }
1169
1142
 
1170
1143
  if (t.text.length > 0) {
1171
- // console.log('[TRANSLATE] Creating translated message');
1172
1144
  translatedMsg = {
1173
1145
  text: emission,
1174
1146
  translatedText: t.text,
@@ -1189,7 +1161,6 @@ const MemoriWidget = ({
1189
1161
  };
1190
1162
  }
1191
1163
  } catch (error) {
1192
- console.error('[TRANSLATE] Error during translation:', error);
1193
1164
  translatedState = { ...state, emission };
1194
1165
  translatedMsg = {
1195
1166
  text: emission,
@@ -1210,10 +1181,8 @@ const MemoriWidget = ({
1210
1181
  }
1211
1182
  }
1212
1183
 
1213
- // console.log('[TRANSLATE] Setting translated state and message');
1214
1184
  setCurrentDialogState(translatedState);
1215
1185
  if (!avoidPushingMessage && translatedMsg) {
1216
- // console.log('[TRANSLATE] Pushing translated message', translatedMsg);
1217
1186
  pushMessage(translatedMsg);
1218
1187
  }
1219
1188
 
@@ -1319,7 +1288,6 @@ const MemoriWidget = ({
1319
1288
  executableSnippets?.forEach(s => {
1320
1289
  try {
1321
1290
  setTimeout(() => {
1322
- console.log('snippet', s);
1323
1291
  // eslint-disable-next-line no-new-func
1324
1292
  new Function(s.content ?? '')();
1325
1293
 
@@ -1333,8 +1301,8 @@ const MemoriWidget = ({
1333
1301
  );
1334
1302
  }, 400);
1335
1303
  }, 1000);
1336
- } catch (e) {
1337
- console.warn(e);
1304
+ } catch {
1305
+ // ignore snippet execution errors
1338
1306
  }
1339
1307
  });
1340
1308
  };
@@ -1410,8 +1378,8 @@ const MemoriWidget = ({
1410
1378
  referral = (() => {
1411
1379
  return window.location.href;
1412
1380
  })();
1413
- } catch (err) {
1414
- console.debug(err);
1381
+ } catch {
1382
+ // ignore referral URL errors
1415
1383
  }
1416
1384
 
1417
1385
  // Initialize session with parameters
@@ -1463,7 +1431,6 @@ const MemoriWidget = ({
1463
1431
  else if (
1464
1432
  session?.resultMessage.startsWith('This Memori is aged restricted')
1465
1433
  ) {
1466
- console.warn(session);
1467
1434
  toast.error(t('underageTwinSession', { age: minAge }));
1468
1435
  }
1469
1436
  // Handle authentication error
@@ -1474,7 +1441,6 @@ const MemoriWidget = ({
1474
1441
  }
1475
1442
  // Handle other errors
1476
1443
  else {
1477
- console.warn(session);
1478
1444
  toast.error(
1479
1445
  tst => (
1480
1446
  <div>
@@ -1496,7 +1462,7 @@ const MemoriWidget = ({
1496
1462
  return session;
1497
1463
  }
1498
1464
  } catch (err) {
1499
- console.error(err);
1465
+ logWidgetError('fetchSession failed', err);
1500
1466
  }
1501
1467
  };
1502
1468
 
@@ -1535,12 +1501,10 @@ const MemoriWidget = ({
1535
1501
  undefined
1536
1502
  );
1537
1503
  let userBirthDate = birthDate ?? storageBirthDate;
1538
- // console.log('[REOPEN_SESSION] Using birth date:', userBirthDate);
1539
1504
 
1540
1505
  try {
1541
1506
  // Show age verification if required and birth date not provided
1542
1507
  if (!userBirthDate && !!minAge) {
1543
- // console.log('[REOPEN_SESSION] Age verification required, showing modal');
1544
1508
  setShowAgeVerification(true);
1545
1509
  return;
1546
1510
  }
@@ -1554,7 +1518,6 @@ const MemoriWidget = ({
1554
1518
  !recoveryTokens &&
1555
1519
  !memoriTokens
1556
1520
  ) {
1557
- // console.log('[REOPEN_SESSION] Authentication required, showing modal');
1558
1521
  setAuthModalState('password');
1559
1522
  return;
1560
1523
  }
@@ -1570,13 +1533,11 @@ const MemoriWidget = ({
1570
1533
  referral = (() => {
1571
1534
  return window.location.href;
1572
1535
  })();
1573
- // console.log('[REOPEN_SESSION] Got referral:', referral);
1574
- } catch (err) {
1575
- console.debug('[REOPEN_SESSION] Error getting referral:', err);
1536
+ } catch {
1537
+ // ignore referral URL errors
1576
1538
  }
1577
1539
 
1578
1540
  // Initialize session with provided parameters
1579
- // console.log('[REOPEN_SESSION] Initializing session...');
1580
1541
  const { sessionID, currentState, ...response } = await initSession({
1581
1542
  memoriID: memori.engineMemoriID ?? '',
1582
1543
  password: password || memoriPwd || memori.secretToken,
@@ -1613,22 +1574,13 @@ const MemoriWidget = ({
1613
1574
 
1614
1575
  // Handle successful session initialization
1615
1576
  if (sessionID && currentState && response.resultCode === 0) {
1616
- console.log(
1617
- '[REOPEN_SESSION] Session initialized successfully:',
1618
- sessionID
1619
- );
1620
1577
  setSessionId(sessionID);
1621
1578
 
1622
1579
  // Update dialog state and history if requested
1623
1580
  if (updateDialogState) {
1624
- // console.log('[REOPEN_SESSION] Updating dialog state');
1625
1581
  setCurrentDialogState(currentState);
1626
1582
 
1627
1583
  if (currentState.emission) {
1628
- console.log(
1629
- '[REOPEN_SESSION] Processing emission:',
1630
- currentState.emission
1631
- );
1632
1584
  // Determine initial status message based on context
1633
1585
  // Show status message only if session expired and there's existing history
1634
1586
  const initialStatus =
@@ -1689,7 +1641,6 @@ const MemoriWidget = ({
1689
1641
  else if (
1690
1642
  response?.resultMessage.startsWith('This Memori is aged restricted')
1691
1643
  ) {
1692
- console.error('[REOPEN_SESSION] Age restriction error:', response);
1693
1644
  toast.error(t('underageTwinSession', { age: minAge }));
1694
1645
  }
1695
1646
  // Handle authentication error
@@ -1697,17 +1648,15 @@ const MemoriWidget = ({
1697
1648
  response?.resultCode === 403 &&
1698
1649
  memori.privacyType !== 'PUBLIC'
1699
1650
  ) {
1700
- console.error('[REOPEN_SESSION] Authentication error');
1701
1651
  setMemoriPwd(undefined);
1702
1652
  setAuthModalState('password');
1703
1653
  }
1704
1654
  // Handle other errors
1705
1655
  else {
1706
- console.error('[REOPEN_SESSION] Other error:', response);
1707
1656
  toast.error(t(getErrori18nKey(response.resultCode)));
1708
1657
  }
1709
1658
  } catch (err) {
1710
- console.error('[REOPEN_SESSION] Caught error:', err);
1659
+ logWidgetError('reopenSession failed', err);
1711
1660
  }
1712
1661
  // Reset loading state
1713
1662
  setLoading(false);
@@ -1722,7 +1671,6 @@ const MemoriWidget = ({
1722
1671
  pin?: string
1723
1672
  ) => {
1724
1673
  if (!memoriId || !sessionId) {
1725
- console.error('CHANGETAG/Session not found');
1726
1674
  return Promise.reject('Session not found');
1727
1675
  }
1728
1676
 
@@ -1762,7 +1710,6 @@ const MemoriWidget = ({
1762
1710
  };
1763
1711
  }
1764
1712
  } else if ([400, 401, 403, 404, 500].includes(resultCode)) {
1765
- console.warn('[APPCONTEXT/CHANGETAG]', resultCode);
1766
1713
  let storageBirthDate = getLocalConfig<string | undefined>(
1767
1714
  'birthDate',
1768
1715
  undefined
@@ -1773,8 +1720,8 @@ const MemoriWidget = ({
1773
1720
  referral = (() => {
1774
1721
  return window.location.href;
1775
1722
  })();
1776
- } catch (err) {
1777
- console.debug(err);
1723
+ } catch {
1724
+ // ignore referral URL errors
1778
1725
  }
1779
1726
 
1780
1727
  fetchSession({
@@ -1816,7 +1763,6 @@ const MemoriWidget = ({
1816
1763
  }
1817
1764
  } catch (_e) {
1818
1765
  let err = _e as Error;
1819
- console.warn('[APPCONTEXT/CHANGETAG]', err);
1820
1766
  return Promise.reject(err);
1821
1767
  }
1822
1768
 
@@ -1843,6 +1789,7 @@ const MemoriWidget = ({
1843
1789
  return () => {
1844
1790
  setHasUserActivatedSpeak(false);
1845
1791
  setClickedStart(false);
1792
+ sessionStartingRef.current = false;
1846
1793
  clearInteractionTimeout();
1847
1794
  timeoutRef.current = undefined;
1848
1795
  };
@@ -1855,8 +1802,6 @@ const MemoriWidget = ({
1855
1802
  const [requestedListening, setRequestedListening] = useState(false);
1856
1803
  const startListeningRef = useRef<(() => Promise<void>) | null>(null);
1857
1804
 
1858
- // console.log('tenantID', tenantID);
1859
-
1860
1805
  // Define TTS configuration
1861
1806
  const ttsConfig = useMemo(
1862
1807
  () => ({
@@ -1911,7 +1856,6 @@ const MemoriWidget = ({
1911
1856
  'muteSpeaker',
1912
1857
  !defaultEnableAudio
1913
1858
  );
1914
- console.log('[MemoriWidget] shouldPlayAudio', currentSpeakerMuted);
1915
1859
  return (
1916
1860
  text &&
1917
1861
  text.trim() &&
@@ -1923,7 +1867,6 @@ const MemoriWidget = ({
1923
1867
 
1924
1868
  // Create a single, centralized function to process and send messages
1925
1869
  const processSpeechAndSendMessage = (text: string) => {
1926
- // console.log('processSpeechAndSendMessage', text);
1927
1870
  // Skip if already processing or no text
1928
1871
  if (!text || text.trim().length === 0) {
1929
1872
  return;
@@ -1932,17 +1875,15 @@ const MemoriWidget = ({
1932
1875
  try {
1933
1876
  // Process the text
1934
1877
  const message = stripDuplicates(text);
1935
- console.debug('Processing speech message:', message);
1936
1878
 
1937
1879
  if (message.length > 0) {
1938
1880
  setUserMessage('');
1939
1881
 
1940
1882
  // Send the message
1941
- console.debug('Sending message:', message);
1942
1883
  sendMessage(message);
1943
1884
  }
1944
- } catch (error) {
1945
- console.error('Error in processSpeechAndSendMessage:', error);
1885
+ } catch {
1886
+ // ignore speech processing errors
1946
1887
  }
1947
1888
  };
1948
1889
 
@@ -2025,8 +1966,7 @@ const MemoriWidget = ({
2025
1966
  }
2026
1967
 
2027
1968
  return translatedState;
2028
- } catch (error) {
2029
- console.error('Error in translateAndSpeak:', error);
1969
+ } catch {
2030
1970
  // Still update activation state even if there's an error
2031
1971
  if (!hasUserActivatedSpeak) {
2032
1972
  setHasUserActivatedSpeak(true);
@@ -2045,12 +1985,6 @@ const MemoriWidget = ({
2045
1985
 
2046
1986
  const processEnterTextDialogResponse = useCallback(
2047
1987
  (event: NatsDialogResponseEvent, pending: PendingEnterText) => {
2048
- console.debug('[EnterText] processDialogResponse', {
2049
- correlationID: event.correlationID,
2050
- resultCode: event.resultCode,
2051
- hasCurrentState: !!event.currentState,
2052
- hasBatchQueued: pending.hasBatchQueued,
2053
- });
2054
1988
  const {
2055
1989
  msg,
2056
1990
  typingText: pendingTypingText,
@@ -2060,10 +1994,6 @@ const MemoriWidget = ({
2060
1994
 
2061
1995
  if (event.resultCode !== 0 || !currentState) {
2062
1996
  if (event.resultCode === 500 && event.resultMessage) {
2063
- console.warn('[EnterText] processDialogResponse: server error', {
2064
- correlationID: event.correlationID,
2065
- resultMessage: event.resultMessage,
2066
- });
2067
1997
  setHistory(h => [
2068
1998
  ...h,
2069
1999
  {
@@ -2075,16 +2005,11 @@ const MemoriWidget = ({
2075
2005
  date: new Date().toISOString(),
2076
2006
  },
2077
2007
  ]);
2078
- } else if (event.resultCode !== 0) {
2079
- console.warn('[SEND_MESSAGE/NATS]', event);
2080
2008
  }
2081
2009
  return;
2082
2010
  }
2083
2011
 
2084
2012
  if (!msg) {
2085
- console.debug(
2086
- '[EnterText] processDialogResponse: no msg in pending, skipping'
2087
- );
2088
2013
  return;
2089
2014
  }
2090
2015
 
@@ -2094,12 +2019,6 @@ const MemoriWidget = ({
2094
2019
  ? pendingTypingText
2095
2020
  : currentState.emission ?? currentDialogState?.emission;
2096
2021
 
2097
- console.debug('[EnterText] processDialogResponse: rendering emission', {
2098
- correlationID: event.correlationID,
2099
- emissionPreview: emission?.slice(0, 80),
2100
- state: currentState.state,
2101
- });
2102
-
2103
2022
  if (
2104
2023
  userLang.toLowerCase() !== language.toLowerCase() &&
2105
2024
  emission &&
@@ -2176,12 +2095,6 @@ const MemoriWidget = ({
2176
2095
  ? `Error: ${event.errorCode}`
2177
2096
  : 'Error: An unexpected error occurred';
2178
2097
 
2179
- console.error('[EnterText] NATS error event', {
2180
- correlationID,
2181
- errorCode: event.errorCode,
2182
- errorMessage: event.errorMessage,
2183
- });
2184
-
2185
2098
  pushMessage({
2186
2099
  text: errorText,
2187
2100
  emitter: 'system',
@@ -2211,19 +2124,6 @@ const MemoriWidget = ({
2211
2124
  (correlationID: string, event: NatsDialogResponseEvent) => {
2212
2125
  const pending = pendingEnterTextRef.current.get(correlationID);
2213
2126
  if (!pending) {
2214
- const pendingCorrelationIDs = [...pendingEnterTextRef.current.keys()];
2215
- console.warn(
2216
- '[EnterText] NATS response buffered (no matching pending)',
2217
- {
2218
- receivedCorrelationID: correlationID,
2219
- resultCode: event.resultCode,
2220
- pendingCorrelationIDs,
2221
- hint:
2222
- pendingCorrelationIDs.length > 0
2223
- ? 'Use one of pendingCorrelationIDs in your nats pub correlation_id'
2224
- : 'Send a message in the widget first, then copy correlationID from HTTP response logs',
2225
- }
2226
- );
2227
2127
  bufferedNatsResponsesRef.current.set(correlationID, event);
2228
2128
  return;
2229
2129
  }
@@ -2231,10 +2131,6 @@ const MemoriWidget = ({
2231
2131
  clearEnterTextPending(correlationID, pending);
2232
2132
 
2233
2133
  if (pending.waitForResponse) {
2234
- console.info('[EnterText] NATS response delivered to waiter', {
2235
- correlationID,
2236
- resultCode: event.resultCode,
2237
- });
2238
2134
  pending.waitForResponse.resolve(event);
2239
2135
  setMemoriTyping(false);
2240
2136
  setTypingText(undefined);
@@ -2244,13 +2140,8 @@ const MemoriWidget = ({
2244
2140
  processEnterTextDialogResponse(event, pending);
2245
2141
 
2246
2142
  if (!pending.hasBatchQueued) {
2247
- console.info('[EnterText] typing indicator cleared', { correlationID });
2248
2143
  setMemoriTyping(false);
2249
2144
  setTypingText(undefined);
2250
- } else {
2251
- console.debug('[EnterText] typing kept (batch queued)', {
2252
- correlationID,
2253
- });
2254
2145
  }
2255
2146
  },
2256
2147
  [processEnterTextDialogResponse, clearEnterTextPending]
@@ -2260,10 +2151,6 @@ const MemoriWidget = ({
2260
2151
  (correlationID: string, pending: PendingEnterText) => {
2261
2152
  const buffered = bufferedNatsResponsesRef.current.get(correlationID);
2262
2153
  if (buffered) {
2263
- console.info('[EnterText] replaying buffered NATS response', {
2264
- correlationID,
2265
- waitForResponse: !!pending.waitForResponse,
2266
- });
2267
2154
  bufferedNatsResponsesRef.current.delete(correlationID);
2268
2155
  pendingEnterTextRef.current.set(correlationID, pending);
2269
2156
  deliverEnterTextNatsResponse(correlationID, buffered);
@@ -2275,7 +2162,7 @@ const MemoriWidget = ({
2275
2162
  const current = pendingEnterTextRef.current.get(correlationID);
2276
2163
  if (!current) return;
2277
2164
  clearEnterTextPending(correlationID, current);
2278
- console.error('[EnterText] NATS response timeout', {
2165
+ logWidgetError('NATS timeout', {
2279
2166
  correlationID,
2280
2167
  timeoutMs: ENTER_TEXT_NATS_TIMEOUT_MS,
2281
2168
  });
@@ -2289,11 +2176,6 @@ const MemoriWidget = ({
2289
2176
  }, ENTER_TEXT_NATS_TIMEOUT_MS);
2290
2177
  }
2291
2178
 
2292
- console.debug('[EnterText] pending registered', {
2293
- correlationID,
2294
- waitForResponse: !!pending.waitForResponse,
2295
- hasBatchQueued: pending.hasBatchQueued,
2296
- });
2297
2179
  pendingEnterTextRef.current.set(correlationID, pending);
2298
2180
  },
2299
2181
  [deliverEnterTextNatsResponse, clearEnterTextPending]
@@ -2302,19 +2184,12 @@ const MemoriWidget = ({
2302
2184
  const waitForEnterTextNatsResponse = useCallback(
2303
2185
  (correlationID: string, timeoutMs = 120000) =>
2304
2186
  new Promise<NatsDialogResponseEvent>((resolve, reject) => {
2305
- console.debug('[EnterText] waiting for NATS response', {
2306
- correlationID,
2307
- timeoutMs,
2308
- });
2309
2187
  const timeoutId = setTimeout(() => {
2310
2188
  const current = pendingEnterTextRef.current.get(correlationID);
2311
2189
  if (current) {
2312
2190
  clearEnterTextPending(correlationID, current);
2313
2191
  }
2314
- console.error('[EnterText] NATS response timeout', {
2315
- correlationID,
2316
- timeoutMs,
2317
- });
2192
+ logWidgetError('NATS timeout', { correlationID, timeoutMs });
2318
2193
  reject(new Error('NATS enter-text response timeout'));
2319
2194
  }, timeoutMs);
2320
2195
 
@@ -2340,12 +2215,6 @@ const MemoriWidget = ({
2340
2215
  baseUrl,
2341
2216
  sessionId,
2342
2217
  onProgress: useCallback((event: NatsProgressEvent) => {
2343
- console.debug('[EnterText] NATS progress', {
2344
- correlationID: event.correlationID,
2345
- step: event.currentStep,
2346
- finalStep: event.finalStep,
2347
- message: event.message,
2348
- });
2349
2218
  if (event.message) {
2350
2219
  setTypingText(event.message);
2351
2220
  }
@@ -2353,19 +2222,8 @@ const MemoriWidget = ({
2353
2222
  onDialogResponse: useCallback(
2354
2223
  (event: NatsDialogResponseEvent) => {
2355
2224
  const correlationID = event.correlationID;
2356
- console.debug(
2357
- '[EnterText] NATS dialog.text_entered_response received',
2358
- {
2359
- correlationID,
2360
- resultCode: event.resultCode,
2361
- requestID: event.requestID,
2362
- }
2363
- );
2364
2225
  if (!correlationID) {
2365
- console.warn(
2366
- '[EnterText] dialog_text_entered_response without correlationID',
2367
- event
2368
- );
2226
+ logWidgetError('NATS dialog response missing correlationID', event);
2369
2227
  setMemoriTyping(false);
2370
2228
  setTypingText(undefined);
2371
2229
  return;
@@ -2406,8 +2264,8 @@ const MemoriWidget = ({
2406
2264
  setClickedStart(false);
2407
2265
  timeoutRef.current = undefined;
2408
2266
  ttsStop();
2409
- } catch (e) {
2410
- // console.log('Error: resetUIEffects', e);
2267
+ } catch {
2268
+ // ignore reset errors
2411
2269
  }
2412
2270
  };
2413
2271
  useEffect(() => {
@@ -2671,12 +2529,6 @@ const MemoriWidget = ({
2671
2529
  chatLog?: ChatLog,
2672
2530
  targetSessionID?: string
2673
2531
  ) => {
2674
- // console.log('[onClickStart] Starting with params:', {
2675
- // session,
2676
- // initialSessionExpired,
2677
- // chatLog
2678
- // });
2679
-
2680
2532
  const sessionID = chatLog ? undefined : session?.sessionID || sessionId;
2681
2533
  const dialogState = chatLog
2682
2534
  ? undefined
@@ -2715,6 +2567,7 @@ const MemoriWidget = ({
2715
2567
  if (!sessionID && !!minAge && !birth) {
2716
2568
  setShowAgeVerification(true);
2717
2569
  setClickedStart(false);
2570
+ return;
2718
2571
  }
2719
2572
  // Handle authentication
2720
2573
  else if (
@@ -2730,41 +2583,46 @@ const MemoriWidget = ({
2730
2583
  }
2731
2584
  // Create new session if needed
2732
2585
  else if (!sessionID || initialSessionExpired) {
2733
- setClickedStart(false);
2734
- const session = await fetchSession({
2735
- memoriID: memori.engineMemoriID!,
2736
- password: secret || memoriPwd || memori.secretToken,
2737
- tag: personification?.tag,
2738
- pin: personification?.pin,
2739
- continueFromChatLogID: chatLog?.chatLogID,
2740
- initialContextVars: {
2741
- LANG: userLang,
2742
- PATHNAME: window.location.pathname?.toUpperCase(),
2743
- ROUTE:
2744
- window.location.pathname?.split('/')?.pop()?.toUpperCase() || '',
2745
- ...((!chatLog
2746
- ? initialContextVars
2747
- : chatLog.lines[chatLog.lines.length - 1].contextVars) || {}),
2748
- },
2749
- initialQuestion: chatLog ? undefined : initialQuestion,
2750
- birthDate: birth,
2751
- additionalInfo: {
2752
- ...(additionalInfo || {}),
2753
- loginToken:
2754
- userToken ??
2755
- loginToken ??
2756
- additionalInfo?.loginToken ??
2757
- authToken,
2758
- language: (
2759
- userLang ??
2760
- memori.culture?.split('-')?.[0] ??
2761
- 'IT'
2762
- ).toLowerCase(),
2763
- timeZoneOffset: new Date().getTimezoneOffset().toString(),
2764
- },
2765
- });
2586
+ if (sessionStartingRef.current) {
2587
+ return;
2588
+ }
2589
+ sessionStartingRef.current = true;
2590
+ try {
2591
+ const session = await fetchSession({
2592
+ memoriID: memori.engineMemoriID!,
2593
+ password: secret || memoriPwd || memori.secretToken,
2594
+ tag: personification?.tag,
2595
+ pin: personification?.pin,
2596
+ continueFromChatLogID: chatLog?.chatLogID,
2597
+ initialContextVars: {
2598
+ LANG: userLang,
2599
+ PATHNAME: window.location.pathname?.toUpperCase(),
2600
+ ROUTE:
2601
+ window.location.pathname?.split('/')?.pop()?.toUpperCase() ||
2602
+ '',
2603
+ ...((!chatLog
2604
+ ? initialContextVars
2605
+ : chatLog.lines[chatLog.lines.length - 1].contextVars) || {}),
2606
+ },
2607
+ initialQuestion: chatLog ? undefined : initialQuestion,
2608
+ birthDate: birth,
2609
+ additionalInfo: {
2610
+ ...(additionalInfo || {}),
2611
+ loginToken:
2612
+ userToken ??
2613
+ loginToken ??
2614
+ additionalInfo?.loginToken ??
2615
+ authToken,
2616
+ language: (
2617
+ userLang ??
2618
+ memori.culture?.split('-')?.[0] ??
2619
+ 'IT'
2620
+ ).toLowerCase(),
2621
+ timeZoneOffset: new Date().getTimezoneOffset().toString(),
2622
+ },
2623
+ });
2766
2624
 
2767
- if (session?.dialogState) {
2625
+ if (session?.dialogState) {
2768
2626
  // reset history
2769
2627
  if (!chatLog) {
2770
2628
  setHistory([]);
@@ -2773,6 +2631,7 @@ const MemoriWidget = ({
2773
2631
  await translateAndSpeak(session.dialogState, userLang);
2774
2632
  // No need for additional handleSpeak call since translateAndSpeak already handles it
2775
2633
  setHasUserActivatedSpeak(true);
2634
+ setClickedStart(false);
2776
2635
  } else {
2777
2636
  const messages = chatLog.lines.map(
2778
2637
  (l, i) =>
@@ -2820,8 +2679,8 @@ const MemoriWidget = ({
2820
2679
  };
2821
2680
  })
2822
2681
  );
2823
- } catch (e) {
2824
- console.error('[onClickStart] Error translating messages:', e);
2682
+ } catch {
2683
+ // ignore translation errors
2825
2684
  }
2826
2685
  }
2827
2686
 
@@ -2834,12 +2693,18 @@ const MemoriWidget = ({
2834
2693
  true
2835
2694
  ).finally(() => {
2836
2695
  setHasUserActivatedSpeak(true);
2696
+ setClickedStart(false);
2837
2697
  });
2838
2698
  }
2839
- } else if (session?.resultCode === 0) {
2840
- await onClickStart((session as any) || undefined);
2841
- } else {
2842
- setLoading(false);
2699
+ } else if (session?.resultCode === 0) {
2700
+ sessionStartingRef.current = false;
2701
+ await onClickStart((session as any) || undefined);
2702
+ } else {
2703
+ setLoading(false);
2704
+ setClickedStart(false);
2705
+ }
2706
+ } finally {
2707
+ sessionStartingRef.current = false;
2843
2708
  }
2844
2709
 
2845
2710
  return;
@@ -2853,7 +2718,6 @@ const MemoriWidget = ({
2853
2718
  if (response.resultCode !== 0 || !currentState) {
2854
2719
  const { chatLogs } = await getSessionChatLogs(sessionID!, sessionID!);
2855
2720
  setSessionId(undefined);
2856
- setClickedStart(false);
2857
2721
  await onClickStart(undefined, true, chatLogs?.[0]);
2858
2722
  return;
2859
2723
  }
@@ -2879,11 +2743,11 @@ const MemoriWidget = ({
2879
2743
 
2880
2744
  if (session && session.resultCode === 0) {
2881
2745
  await translateAndSpeak(session.currentState, userLang);
2746
+ setClickedStart(false);
2882
2747
  } else {
2883
2748
  throw new Error('No session');
2884
2749
  }
2885
- } catch (e) {
2886
- console.error('[onClickStart] Error changing tag:', e);
2750
+ } catch {
2887
2751
  reopenSession(
2888
2752
  true,
2889
2753
  memori?.secretToken,
@@ -2902,6 +2766,7 @@ const MemoriWidget = ({
2902
2766
  birth
2903
2767
  ).then(() => {
2904
2768
  setHasUserActivatedSpeak(true);
2769
+ setClickedStart(false);
2905
2770
  });
2906
2771
  }
2907
2772
  }
@@ -2924,6 +2789,7 @@ const MemoriWidget = ({
2924
2789
 
2925
2790
  if (session && session.resultCode === 0) {
2926
2791
  await translateAndSpeak(session.currentState, userLang);
2792
+ setClickedStart(false);
2927
2793
  } else {
2928
2794
  throw new Error('No session');
2929
2795
  }
@@ -2946,6 +2812,7 @@ const MemoriWidget = ({
2946
2812
  birth
2947
2813
  ).then(() => {
2948
2814
  setHasUserActivatedSpeak(true);
2815
+ setClickedStart(false);
2949
2816
  });
2950
2817
  }
2951
2818
  }
@@ -2992,14 +2859,14 @@ const MemoriWidget = ({
2992
2859
  ).text,
2993
2860
  }))
2994
2861
  );
2995
- } catch (e) {
2996
- console.error('[onClickStart] Error translating messages:', e);
2862
+ } catch {
2863
+ // ignore translation errors
2997
2864
  }
2998
2865
  }
2999
2866
 
3000
2867
  setHistory(translatedMessages);
3001
- } catch (e) {
3002
- console.error('[onClickStart] Error retrieving chat logs:', e);
2868
+ } catch {
2869
+ // ignore chat log retrieval errors
3003
2870
  }
3004
2871
 
3005
2872
  if (
@@ -3008,6 +2875,7 @@ const MemoriWidget = ({
3008
2875
  ) {
3009
2876
  // we have a history, don't push message
3010
2877
  setHasUserActivatedSpeak(true);
2878
+ setClickedStart(false);
3011
2879
  await translateAndSpeak(
3012
2880
  currentState,
3013
2881
  userLang,
@@ -3017,19 +2885,12 @@ const MemoriWidget = ({
3017
2885
  !!translatedMessages?.length
3018
2886
  );
3019
2887
  } else {
3020
- console.log('[onClickStart] Starting with initial question');
3021
2888
  // remove default initial message
3022
2889
  translatedMessages = [];
3023
2890
  setHistory([]);
3024
2891
 
3025
2892
  // we have no chat history, we start by initial question
3026
2893
  const placeSpec = getPlaceSpecForEnterText(position);
3027
- console.debug(
3028
- '[EnterText] onClickStart: posting initial question',
3029
- {
3030
- sessionId: sessionID,
3031
- }
3032
- );
3033
2894
  const response = await postEnterTextAsync({
3034
2895
  sessionId: sessionID!,
3035
2896
  text: initialQuestion,
@@ -3038,11 +2899,6 @@ const MemoriWidget = ({
3038
2899
  }),
3039
2900
  ...(placeSpec !== undefined && { place: placeSpec }),
3040
2901
  });
3041
- console.debug('[EnterText] onClickStart: HTTP response', {
3042
- resultCode: response.resultCode,
3043
- correlationID: readCorrelationID(response),
3044
- });
3045
-
3046
2902
  // Handle 500 error from EnterTextAsync
3047
2903
  if (response.resultCode === 500 && response.resultMessage) {
3048
2904
  setHistory(h => [
@@ -3061,24 +2917,11 @@ const MemoriWidget = ({
3061
2917
 
3062
2918
  const onClickStartCorrelationID = readCorrelationID(response);
3063
2919
  if (response.resultCode === 0 && onClickStartCorrelationID) {
3064
- console.info(
3065
- '[EnterText] onClickStart: accepted, showing typing indicator',
3066
- {
3067
- correlationID: onClickStartCorrelationID,
3068
- }
3069
- );
3070
2920
  setMemoriTyping(true);
3071
2921
  try {
3072
2922
  const natsEvent = await waitForEnterTextNatsResponse(
3073
2923
  onClickStartCorrelationID
3074
2924
  );
3075
- console.info(
3076
- '[EnterText] onClickStart: NATS response received',
3077
- {
3078
- correlationID: onClickStartCorrelationID,
3079
- resultCode: natsEvent.resultCode,
3080
- }
3081
- );
3082
2925
  if (natsEvent.resultCode === 0 && natsEvent.currentState) {
3083
2926
  await translateAndSpeak(
3084
2927
  natsEvent.currentState,
@@ -3086,17 +2929,15 @@ const MemoriWidget = ({
3086
2929
  undefined,
3087
2930
  false
3088
2931
  );
2932
+ setClickedStart(false);
3089
2933
  }
3090
- } catch (e) {
3091
- console.error('[EnterText] onClickStart: NATS wait failed', e);
2934
+ } catch (err) {
2935
+ logWidgetError('onClickStart NATS wait failed', err);
3092
2936
  setMemoriTyping(false);
3093
2937
  setTypingText(undefined);
3094
2938
  }
3095
2939
  } else if (response.resultCode === 0) {
3096
- console.error(
3097
- '[EnterText] onClickStart: HTTP 200 but missing correlationID',
3098
- response
3099
- );
2940
+ logWidgetError('onClickStart enter-text missing correlationID', response);
3100
2941
  }
3101
2942
  }
3102
2943
  }
@@ -3108,16 +2949,23 @@ const MemoriWidget = ({
3108
2949
 
3109
2950
  // everything is fine, just translate dialog state and activate chat
3110
2951
  await translateAndSpeak(dialogState!, userLang);
2952
+ setClickedStart(false);
3111
2953
  }
3112
2954
  },
3113
2955
  [memoriPwd, memori, memoriTokens, birthDate, sessionId, userLang, position]
3114
2956
  );
3115
2957
 
3116
2958
  useEffect(() => {
3117
- if (!clickedStart && autoStart && selectedLayout !== 'HIDDEN_CHAT') {
2959
+ if (
2960
+ !clickedStart &&
2961
+ !sessionStartingRef.current &&
2962
+ !sessionId &&
2963
+ autoStart &&
2964
+ selectedLayout !== 'HIDDEN_CHAT'
2965
+ ) {
3118
2966
  onClickStart();
3119
2967
  }
3120
- }, [clickedStart, autoStart, selectedLayout]);
2968
+ }, [clickedStart, autoStart, selectedLayout, sessionId]);
3121
2969
 
3122
2970
  useEffect(() => {
3123
2971
  const targetNode =
@@ -3174,11 +3022,9 @@ const MemoriWidget = ({
3174
3022
 
3175
3023
  if (resp.resultCode === 0) {
3176
3024
  setExperts(experts);
3177
- } else {
3178
- console.warn('Error fetching experts', resp);
3179
3025
  }
3180
- } catch (err) {
3181
- console.warn(err);
3026
+ } catch {
3027
+ // ignore expert fetch errors
3182
3028
  }
3183
3029
  }, [sessionId, memori?.enableBoardOfExperts]);
3184
3030
  useEffect(() => {
@@ -3207,7 +3053,6 @@ const MemoriWidget = ({
3207
3053
  // Without either owner identifier we cannot call the API, so we fail closed
3208
3054
  // instead of silently letting the session start unverified.
3209
3055
  if (!ownerUserID && !ownerUserName) {
3210
- console.warn('Cannot verify credits: missing owner identifier');
3211
3056
  if (options?.notify) {
3212
3057
  handleNotEnoughCredits();
3213
3058
  } else {
@@ -3231,7 +3076,6 @@ const MemoriWidget = ({
3231
3076
  setHasEnoughCredits(true);
3232
3077
  return true;
3233
3078
  } else {
3234
- console.warn('Not enough credits. Required:', resp.required);
3235
3079
  if (options?.notify) {
3236
3080
  handleNotEnoughCredits();
3237
3081
  } else {
@@ -3239,9 +3083,8 @@ const MemoriWidget = ({
3239
3083
  }
3240
3084
  return false;
3241
3085
  }
3242
- } catch (e) {
3243
- let err = e as Error;
3244
- console.debug(err);
3086
+ } catch (err) {
3087
+ logWidgetError('checkCredits failed', err);
3245
3088
  return true;
3246
3089
  }
3247
3090
  },