@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.
- package/CHANGELOG.md +13 -0
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +2 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +357 -73
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/helpers/credits.d.ts +3 -2
- package/dist/helpers/credits.js +4 -3
- package/dist/helpers/credits.js.map +1 -1
- package/dist/helpers/nats/getNatsConfig.d.ts +5 -0
- package/dist/helpers/nats/getNatsConfig.js +29 -0
- package/dist/helpers/nats/getNatsConfig.js.map +1 -0
- package/dist/helpers/nats/useNats.d.ts +12 -0
- package/dist/helpers/nats/useNats.js +72 -0
- package/dist/helpers/nats/useNats.js.map +1 -0
- package/dist/helpers/nats/useNatsSession.d.ts +27 -0
- package/dist/helpers/nats/useNatsSession.js +108 -0
- package/dist/helpers/nats/useNatsSession.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +2 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +357 -73
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/helpers/credits.d.ts +3 -2
- package/esm/helpers/credits.js +4 -3
- package/esm/helpers/credits.js.map +1 -1
- package/esm/helpers/nats/getNatsConfig.d.ts +5 -0
- package/esm/helpers/nats/getNatsConfig.js +25 -0
- package/esm/helpers/nats/getNatsConfig.js.map +1 -0
- package/esm/helpers/nats/useNats.d.ts +12 -0
- package/esm/helpers/nats/useNats.js +68 -0
- package/esm/helpers/nats/useNats.js.map +1 -0
- package/esm/helpers/nats/useNatsSession.d.ts +27 -0
- package/esm/helpers/nats/useNatsSession.js +103 -0
- package/esm/helpers/nats/useNatsSession.js.map +1 -0
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/package.json +3 -2
- package/src/components/MemoriWidget/MemoriWidget.tsx +475 -108
- package/src/components/layouts/layouts.stories.tsx +28 -34
- package/src/helpers/credits.ts +6 -3
- package/src/helpers/nats/getNatsConfig.ts +69 -0
- package/src/helpers/nats/useNats.ts +122 -0
- package/src/helpers/nats/useNatsSession.ts +210 -0
- package/src/index.stories.tsx +19 -3
- package/src/index.tsx +1 -0
- 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
|
|
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
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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: ((
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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)((
|
|
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
|
|
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(
|
|
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(
|
|
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
|
]);
|