@iblai/web-utils 1.6.9 → 1.7.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/dist/index.d.ts +3 -1
- package/dist/index.esm.js +132 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +132 -7
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/web-utils/src/hooks/chat/use-advanced-chat.d.ts +2 -1
- package/dist/web-utils/src/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9859,6 +9859,7 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
9859
9859
|
is_advertising: !!((_d = tenantMetadata === null || tenantMetadata === void 0 ? void 0 : tenantMetadata.metadata) === null || _d === void 0 ? void 0 : _d.is_advertising),
|
|
9860
9860
|
is_enterprise: tenant.is_enterprise,
|
|
9861
9861
|
show_paywall: tenant.show_paywall,
|
|
9862
|
+
enable_monetization: tenant.enable_monetization,
|
|
9862
9863
|
});
|
|
9863
9864
|
const rbacPermissions = await loadPlatformPermissions(tenant.key);
|
|
9864
9865
|
onLoadPlatformPermissions === null || onLoadPlatformPermissions === void 0 ? void 0 : onLoadPlatformPermissions(rbacPermissions);
|
|
@@ -11040,8 +11041,16 @@ const chatSlice = createSlice({
|
|
|
11040
11041
|
state.chats = action.payload;
|
|
11041
11042
|
},
|
|
11042
11043
|
appendMessageToActiveTab: (state) => {
|
|
11043
|
-
const
|
|
11044
|
-
if
|
|
11044
|
+
const activeMessages = state.chats[state.activeTab];
|
|
11045
|
+
// Defensive: if the active tab has no messages yet (e.g. a stale
|
|
11046
|
+
// `setNewMessages([])` raced ahead of the user-message dispatch),
|
|
11047
|
+
// skip the lookup that would throw on `undefined.id` and rely on
|
|
11048
|
+
// the no-last-message branch below to append the streaming message.
|
|
11049
|
+
const lastMessageInActiveTabMessages = activeMessages && activeMessages.length > 0
|
|
11050
|
+
? activeMessages[activeMessages.length - 1]
|
|
11051
|
+
: undefined;
|
|
11052
|
+
if (!lastMessageInActiveTabMessages ||
|
|
11053
|
+
lastMessageInActiveTabMessages.id !== state.currentStreamingMessage.id) {
|
|
11045
11054
|
const temp = {
|
|
11046
11055
|
id: state.currentStreamingMessage.id,
|
|
11047
11056
|
role: "assistant",
|
|
@@ -13550,7 +13559,7 @@ function useMentorSettings({ mentorId, tenantKey, isPublicRoute = false, mainTen
|
|
|
13550
13559
|
};
|
|
13551
13560
|
}
|
|
13552
13561
|
|
|
13553
|
-
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, onOAuthRequired, onOAuthResolved, isOffline = false, onOfflineWithoutLocalLLM, isPublicRoute, }) {
|
|
13562
|
+
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, onOAuthRequired, onOAuthResolved, isOffline = false, onOfflineWithoutLocalLLM, isPublicRoute, initialPrompt, }) {
|
|
13554
13563
|
var _a, _b, _c, _d;
|
|
13555
13564
|
const dispatch = useDispatch();
|
|
13556
13565
|
const [createSessionId, { isLoading: isLoadingSessionIds }] = dataLayer.useCreateSessionIdMutation();
|
|
@@ -13605,10 +13614,41 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13605
13614
|
onOfflineWithoutLocalLLM,
|
|
13606
13615
|
});
|
|
13607
13616
|
const [isLoadingChats, setIsLoadingChats] = React.useState(true);
|
|
13617
|
+
// Tracks whether the optional `initialPrompt` prop has already been
|
|
13618
|
+
// auto-submitted for this hook instance. Set to `true` the moment the
|
|
13619
|
+
// effect decides to act (either to send or because the prompt is already
|
|
13620
|
+
// the most recent user message) so subsequent re-renders never re-fire.
|
|
13621
|
+
const initialPromptInjectedRef = React.useRef(false);
|
|
13622
|
+
// Tracks whether a `startNewChat()` call is already mid-flight. The
|
|
13623
|
+
// auto-start `useEffect` below re-runs whenever any of its deps change
|
|
13624
|
+
// (`shouldStartNewChat` in particular toggles after mount in many
|
|
13625
|
+
// consumers), and the existing `!cachedSessionId?.[mentorId]` guard is
|
|
13626
|
+
// not enough on its own because `cachedSessionId` only updates AFTER
|
|
13627
|
+
// `createSessionId` resolves. Without this ref, dep churn during the
|
|
13628
|
+
// pending API call triggers a second `startNewChat`, producing two
|
|
13629
|
+
// sessions, two `getChats` calls, and an extra `setNewMessages([])`
|
|
13630
|
+
// that wipes anything dispatched (like `initialPrompt`'s
|
|
13631
|
+
// `addUserMessage`) between the two `getChats` resolutions.
|
|
13632
|
+
const startNewChatInFlightRef = React.useRef(false);
|
|
13633
|
+
// Synchronous mirror of `isLoadingChats`. The state setter is async, so a
|
|
13634
|
+
// consumer effect running in the SAME render cycle as `getChats()`
|
|
13635
|
+
// invocation sees a stale `isLoadingChats=false` in its closure even
|
|
13636
|
+
// though `setIsLoadingChats(true)` has been scheduled. The ref flips
|
|
13637
|
+
// immediately (before `getChats` hits its first `await`), giving the
|
|
13638
|
+
// `initialPrompt` injection effect a reliable "fetch in progress" signal
|
|
13639
|
+
// it can read synchronously inside its body.
|
|
13640
|
+
const isLoadingChatsRef = React.useRef(true);
|
|
13608
13641
|
const [getSessionChats] = dataLayer.useLazyGetSessionIdQuery();
|
|
13609
13642
|
const [getSharedSessionChats] = dataLayer.useLazyGetSharedSessionIdQuery();
|
|
13610
13643
|
const getChats = React.useCallback(async () => {
|
|
13611
13644
|
var _a, _b, _c, _d;
|
|
13645
|
+
// Mark the fetch as in-flight so consumers gated on `isLoadingChats`
|
|
13646
|
+
// (e.g. the `initialPrompt` injection effect) defer until the resulting
|
|
13647
|
+
// `setNewMessages` has landed. The state setter alone is not enough —
|
|
13648
|
+
// it's async and the consumer effect may run in the same render cycle
|
|
13649
|
+
// with the stale closure — so flip the synchronous ref FIRST.
|
|
13650
|
+
isLoadingChatsRef.current = true;
|
|
13651
|
+
setIsLoadingChats(true);
|
|
13612
13652
|
let data;
|
|
13613
13653
|
try {
|
|
13614
13654
|
if (showingSharedChat) {
|
|
@@ -13693,6 +13733,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13693
13733
|
}
|
|
13694
13734
|
finally {
|
|
13695
13735
|
setIsLoadingChats(false);
|
|
13736
|
+
isLoadingChatsRef.current = false;
|
|
13696
13737
|
}
|
|
13697
13738
|
}, [
|
|
13698
13739
|
showingSharedChat,
|
|
@@ -13704,21 +13745,30 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13704
13745
|
getSessionChats,
|
|
13705
13746
|
dispatch,
|
|
13706
13747
|
]);
|
|
13748
|
+
// Depend on the indexed string session id, not the whole `cachedSessionId`
|
|
13749
|
+
// object. Consumers (e.g. `useLocalStorage`) often re-emit a new object
|
|
13750
|
+
// reference on every render even when the underlying value is unchanged,
|
|
13751
|
+
// which would otherwise cause this effect to re-fire `getChats()` per
|
|
13752
|
+
// render — and each `setNewMessages` would wipe any user message
|
|
13753
|
+
// dispatched in between (the URL `initialPrompt` race).
|
|
13754
|
+
const currentMentorSessionId = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId];
|
|
13707
13755
|
React.useEffect(() => {
|
|
13708
|
-
if (
|
|
13709
|
-
dispatch(chatActions.updateSessionIds(
|
|
13756
|
+
if (currentMentorSessionId) {
|
|
13757
|
+
dispatch(chatActions.updateSessionIds(currentMentorSessionId));
|
|
13710
13758
|
// Skip fetching previous chats when offline
|
|
13711
13759
|
if (!isOffline) {
|
|
13712
13760
|
getChats();
|
|
13713
13761
|
}
|
|
13714
13762
|
else {
|
|
13715
13763
|
setIsLoadingChats(false);
|
|
13764
|
+
isLoadingChatsRef.current = false;
|
|
13716
13765
|
}
|
|
13717
13766
|
}
|
|
13718
13767
|
else {
|
|
13719
13768
|
setIsLoadingChats(false);
|
|
13769
|
+
isLoadingChatsRef.current = false;
|
|
13720
13770
|
}
|
|
13721
|
-
}, [
|
|
13771
|
+
}, [currentMentorSessionId, isOffline]);
|
|
13722
13772
|
const startNewChat = React.useCallback(async () => {
|
|
13723
13773
|
// Reset all chat state
|
|
13724
13774
|
if (!showingSharedChat) {
|
|
@@ -13781,10 +13831,15 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13781
13831
|
errorHandler,
|
|
13782
13832
|
]);
|
|
13783
13833
|
React.useEffect(() => {
|
|
13834
|
+
if (startNewChatInFlightRef.current)
|
|
13835
|
+
return;
|
|
13784
13836
|
if (!showingSharedChat || mentorSettings.allowAnonymous) {
|
|
13785
13837
|
if (mentorSettings.allowAnonymous !== undefined &&
|
|
13786
13838
|
!(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId])) {
|
|
13787
|
-
|
|
13839
|
+
startNewChatInFlightRef.current = true;
|
|
13840
|
+
startNewChat().finally(() => {
|
|
13841
|
+
startNewChatInFlightRef.current = false;
|
|
13842
|
+
});
|
|
13788
13843
|
}
|
|
13789
13844
|
}
|
|
13790
13845
|
}, [shouldStartNewChat, showingSharedChat, mentorSettings.allowAnonymous]);
|
|
@@ -13795,6 +13850,76 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13795
13850
|
resetConnection();
|
|
13796
13851
|
}
|
|
13797
13852
|
}, [sessionIds, activeTab, sessionId, resetConnection]);
|
|
13853
|
+
// Auto-submit `initialPrompt` exactly once per mount after the chat
|
|
13854
|
+
// lifecycle has stabilized. Matches the existing proactive-prompt
|
|
13855
|
+
// precedent in `changeTab` (sendMessage(tab, content)) but is gated on
|
|
13856
|
+
// URL-driven deep-link signals instead of tab transitions.
|
|
13857
|
+
React.useEffect(() => {
|
|
13858
|
+
var _a;
|
|
13859
|
+
if (initialPromptInjectedRef.current)
|
|
13860
|
+
return;
|
|
13861
|
+
const trimmedPrompt = initialPrompt === null || initialPrompt === void 0 ? void 0 : initialPrompt.trim();
|
|
13862
|
+
if (!trimmedPrompt)
|
|
13863
|
+
return;
|
|
13864
|
+
// Bail while any state would make auto-submission unsafe or premature.
|
|
13865
|
+
if (isPreviewMode)
|
|
13866
|
+
return;
|
|
13867
|
+
if (showingSharedChat)
|
|
13868
|
+
return;
|
|
13869
|
+
if (isOffline)
|
|
13870
|
+
return;
|
|
13871
|
+
// Two-layer guard: the state catches re-runs after `getChats` settles
|
|
13872
|
+
// (which schedule a new render). The ref catches the in-render race
|
|
13873
|
+
// where this effect runs in the same cycle that `getChats` was invoked
|
|
13874
|
+
// — the state setter is async and the closure has a stale `false`.
|
|
13875
|
+
if (isLoadingChats)
|
|
13876
|
+
return;
|
|
13877
|
+
if (isLoadingChatsRef.current)
|
|
13878
|
+
return;
|
|
13879
|
+
if (!sessionIds[activeTab])
|
|
13880
|
+
return;
|
|
13881
|
+
if (streaming)
|
|
13882
|
+
return;
|
|
13883
|
+
if (isPending)
|
|
13884
|
+
return;
|
|
13885
|
+
// Dedup: scan back through the loaded history for the most recent
|
|
13886
|
+
// user message and compare its content. If it matches, this session
|
|
13887
|
+
// already has the prompt as a user turn (typical case: reload of a
|
|
13888
|
+
// `?prompt=` URL — the cached history ends with the assistant reply,
|
|
13889
|
+
// so the matching user message is one step back).
|
|
13890
|
+
const messages = chats[activeTab];
|
|
13891
|
+
let lastUserMessage;
|
|
13892
|
+
if (messages && messages.length > 0) {
|
|
13893
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
13894
|
+
if (((_a = messages[i]) === null || _a === void 0 ? void 0 : _a.role) === "user") {
|
|
13895
|
+
lastUserMessage = messages[i];
|
|
13896
|
+
break;
|
|
13897
|
+
}
|
|
13898
|
+
}
|
|
13899
|
+
}
|
|
13900
|
+
if (lastUserMessage &&
|
|
13901
|
+
typeof lastUserMessage.content === "string" &&
|
|
13902
|
+
lastUserMessage.content === trimmedPrompt) {
|
|
13903
|
+
initialPromptInjectedRef.current = true;
|
|
13904
|
+
return;
|
|
13905
|
+
}
|
|
13906
|
+
// Mark BEFORE dispatching: sendMessage triggers state updates that may
|
|
13907
|
+
// re-run this effect, and we want the guard active before any re-fire.
|
|
13908
|
+
initialPromptInjectedRef.current = true;
|
|
13909
|
+
sendMessage(activeTab, trimmedPrompt);
|
|
13910
|
+
}, [
|
|
13911
|
+
initialPrompt,
|
|
13912
|
+
isPreviewMode,
|
|
13913
|
+
showingSharedChat,
|
|
13914
|
+
isOffline,
|
|
13915
|
+
isLoadingChats,
|
|
13916
|
+
sessionIds,
|
|
13917
|
+
activeTab,
|
|
13918
|
+
chats,
|
|
13919
|
+
streaming,
|
|
13920
|
+
isPending,
|
|
13921
|
+
sendMessage,
|
|
13922
|
+
]);
|
|
13798
13923
|
async function changeTab(tab) {
|
|
13799
13924
|
var _a, _b, _c, _d;
|
|
13800
13925
|
// while responding to a message, do not change the tab
|