@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.d.ts
CHANGED
|
@@ -761,6 +761,7 @@ interface Tenant {
|
|
|
761
761
|
is_advertising?: boolean;
|
|
762
762
|
is_enterprise?: boolean;
|
|
763
763
|
show_paywall?: boolean;
|
|
764
|
+
enable_monetization?: boolean;
|
|
764
765
|
}
|
|
765
766
|
|
|
766
767
|
/**
|
|
@@ -1438,8 +1439,9 @@ type Props$7 = {
|
|
|
1438
1439
|
isOffline?: boolean;
|
|
1439
1440
|
onOfflineWithoutLocalLLM?: () => void;
|
|
1440
1441
|
isPublicRoute?: boolean;
|
|
1442
|
+
initialPrompt?: string;
|
|
1441
1443
|
};
|
|
1442
|
-
declare function useAdvancedChat({ tenantKey, mentorId, username, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, onOAuthRequired, onOAuthResolved, isOffline, onOfflineWithoutLocalLLM, isPublicRoute, }: Props$7): {
|
|
1444
|
+
declare function useAdvancedChat({ tenantKey, mentorId, username, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, onOAuthRequired, onOAuthResolved, isOffline, onOfflineWithoutLocalLLM, isPublicRoute, initialPrompt, }: Props$7): {
|
|
1443
1445
|
messages: Message$1[];
|
|
1444
1446
|
isStreaming: boolean;
|
|
1445
1447
|
status: ChatStatus;
|
package/dist/index.esm.js
CHANGED
|
@@ -9839,6 +9839,7 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
9839
9839
|
is_advertising: !!((_d = tenantMetadata === null || tenantMetadata === void 0 ? void 0 : tenantMetadata.metadata) === null || _d === void 0 ? void 0 : _d.is_advertising),
|
|
9840
9840
|
is_enterprise: tenant.is_enterprise,
|
|
9841
9841
|
show_paywall: tenant.show_paywall,
|
|
9842
|
+
enable_monetization: tenant.enable_monetization,
|
|
9842
9843
|
});
|
|
9843
9844
|
const rbacPermissions = await loadPlatformPermissions(tenant.key);
|
|
9844
9845
|
onLoadPlatformPermissions === null || onLoadPlatformPermissions === void 0 ? void 0 : onLoadPlatformPermissions(rbacPermissions);
|
|
@@ -11020,8 +11021,16 @@ const chatSlice = createSlice({
|
|
|
11020
11021
|
state.chats = action.payload;
|
|
11021
11022
|
},
|
|
11022
11023
|
appendMessageToActiveTab: (state) => {
|
|
11023
|
-
const
|
|
11024
|
-
if
|
|
11024
|
+
const activeMessages = state.chats[state.activeTab];
|
|
11025
|
+
// Defensive: if the active tab has no messages yet (e.g. a stale
|
|
11026
|
+
// `setNewMessages([])` raced ahead of the user-message dispatch),
|
|
11027
|
+
// skip the lookup that would throw on `undefined.id` and rely on
|
|
11028
|
+
// the no-last-message branch below to append the streaming message.
|
|
11029
|
+
const lastMessageInActiveTabMessages = activeMessages && activeMessages.length > 0
|
|
11030
|
+
? activeMessages[activeMessages.length - 1]
|
|
11031
|
+
: undefined;
|
|
11032
|
+
if (!lastMessageInActiveTabMessages ||
|
|
11033
|
+
lastMessageInActiveTabMessages.id !== state.currentStreamingMessage.id) {
|
|
11025
11034
|
const temp = {
|
|
11026
11035
|
id: state.currentStreamingMessage.id,
|
|
11027
11036
|
role: "assistant",
|
|
@@ -13530,7 +13539,7 @@ function useMentorSettings({ mentorId, tenantKey, isPublicRoute = false, mainTen
|
|
|
13530
13539
|
};
|
|
13531
13540
|
}
|
|
13532
13541
|
|
|
13533
|
-
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, onOAuthRequired, onOAuthResolved, isOffline = false, onOfflineWithoutLocalLLM, isPublicRoute, }) {
|
|
13542
|
+
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, }) {
|
|
13534
13543
|
var _a, _b, _c, _d;
|
|
13535
13544
|
const dispatch = useDispatch();
|
|
13536
13545
|
const [createSessionId, { isLoading: isLoadingSessionIds }] = useCreateSessionIdMutation();
|
|
@@ -13585,10 +13594,41 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13585
13594
|
onOfflineWithoutLocalLLM,
|
|
13586
13595
|
});
|
|
13587
13596
|
const [isLoadingChats, setIsLoadingChats] = useState(true);
|
|
13597
|
+
// Tracks whether the optional `initialPrompt` prop has already been
|
|
13598
|
+
// auto-submitted for this hook instance. Set to `true` the moment the
|
|
13599
|
+
// effect decides to act (either to send or because the prompt is already
|
|
13600
|
+
// the most recent user message) so subsequent re-renders never re-fire.
|
|
13601
|
+
const initialPromptInjectedRef = React__default.useRef(false);
|
|
13602
|
+
// Tracks whether a `startNewChat()` call is already mid-flight. The
|
|
13603
|
+
// auto-start `useEffect` below re-runs whenever any of its deps change
|
|
13604
|
+
// (`shouldStartNewChat` in particular toggles after mount in many
|
|
13605
|
+
// consumers), and the existing `!cachedSessionId?.[mentorId]` guard is
|
|
13606
|
+
// not enough on its own because `cachedSessionId` only updates AFTER
|
|
13607
|
+
// `createSessionId` resolves. Without this ref, dep churn during the
|
|
13608
|
+
// pending API call triggers a second `startNewChat`, producing two
|
|
13609
|
+
// sessions, two `getChats` calls, and an extra `setNewMessages([])`
|
|
13610
|
+
// that wipes anything dispatched (like `initialPrompt`'s
|
|
13611
|
+
// `addUserMessage`) between the two `getChats` resolutions.
|
|
13612
|
+
const startNewChatInFlightRef = React__default.useRef(false);
|
|
13613
|
+
// Synchronous mirror of `isLoadingChats`. The state setter is async, so a
|
|
13614
|
+
// consumer effect running in the SAME render cycle as `getChats()`
|
|
13615
|
+
// invocation sees a stale `isLoadingChats=false` in its closure even
|
|
13616
|
+
// though `setIsLoadingChats(true)` has been scheduled. The ref flips
|
|
13617
|
+
// immediately (before `getChats` hits its first `await`), giving the
|
|
13618
|
+
// `initialPrompt` injection effect a reliable "fetch in progress" signal
|
|
13619
|
+
// it can read synchronously inside its body.
|
|
13620
|
+
const isLoadingChatsRef = React__default.useRef(true);
|
|
13588
13621
|
const [getSessionChats] = useLazyGetSessionIdQuery();
|
|
13589
13622
|
const [getSharedSessionChats] = useLazyGetSharedSessionIdQuery();
|
|
13590
13623
|
const getChats = React__default.useCallback(async () => {
|
|
13591
13624
|
var _a, _b, _c, _d;
|
|
13625
|
+
// Mark the fetch as in-flight so consumers gated on `isLoadingChats`
|
|
13626
|
+
// (e.g. the `initialPrompt` injection effect) defer until the resulting
|
|
13627
|
+
// `setNewMessages` has landed. The state setter alone is not enough —
|
|
13628
|
+
// it's async and the consumer effect may run in the same render cycle
|
|
13629
|
+
// with the stale closure — so flip the synchronous ref FIRST.
|
|
13630
|
+
isLoadingChatsRef.current = true;
|
|
13631
|
+
setIsLoadingChats(true);
|
|
13592
13632
|
let data;
|
|
13593
13633
|
try {
|
|
13594
13634
|
if (showingSharedChat) {
|
|
@@ -13673,6 +13713,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13673
13713
|
}
|
|
13674
13714
|
finally {
|
|
13675
13715
|
setIsLoadingChats(false);
|
|
13716
|
+
isLoadingChatsRef.current = false;
|
|
13676
13717
|
}
|
|
13677
13718
|
}, [
|
|
13678
13719
|
showingSharedChat,
|
|
@@ -13684,21 +13725,30 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13684
13725
|
getSessionChats,
|
|
13685
13726
|
dispatch,
|
|
13686
13727
|
]);
|
|
13728
|
+
// Depend on the indexed string session id, not the whole `cachedSessionId`
|
|
13729
|
+
// object. Consumers (e.g. `useLocalStorage`) often re-emit a new object
|
|
13730
|
+
// reference on every render even when the underlying value is unchanged,
|
|
13731
|
+
// which would otherwise cause this effect to re-fire `getChats()` per
|
|
13732
|
+
// render — and each `setNewMessages` would wipe any user message
|
|
13733
|
+
// dispatched in between (the URL `initialPrompt` race).
|
|
13734
|
+
const currentMentorSessionId = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId];
|
|
13687
13735
|
useEffect(() => {
|
|
13688
|
-
if (
|
|
13689
|
-
dispatch(chatActions.updateSessionIds(
|
|
13736
|
+
if (currentMentorSessionId) {
|
|
13737
|
+
dispatch(chatActions.updateSessionIds(currentMentorSessionId));
|
|
13690
13738
|
// Skip fetching previous chats when offline
|
|
13691
13739
|
if (!isOffline) {
|
|
13692
13740
|
getChats();
|
|
13693
13741
|
}
|
|
13694
13742
|
else {
|
|
13695
13743
|
setIsLoadingChats(false);
|
|
13744
|
+
isLoadingChatsRef.current = false;
|
|
13696
13745
|
}
|
|
13697
13746
|
}
|
|
13698
13747
|
else {
|
|
13699
13748
|
setIsLoadingChats(false);
|
|
13749
|
+
isLoadingChatsRef.current = false;
|
|
13700
13750
|
}
|
|
13701
|
-
}, [
|
|
13751
|
+
}, [currentMentorSessionId, isOffline]);
|
|
13702
13752
|
const startNewChat = React__default.useCallback(async () => {
|
|
13703
13753
|
// Reset all chat state
|
|
13704
13754
|
if (!showingSharedChat) {
|
|
@@ -13761,10 +13811,15 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13761
13811
|
errorHandler,
|
|
13762
13812
|
]);
|
|
13763
13813
|
React__default.useEffect(() => {
|
|
13814
|
+
if (startNewChatInFlightRef.current)
|
|
13815
|
+
return;
|
|
13764
13816
|
if (!showingSharedChat || mentorSettings.allowAnonymous) {
|
|
13765
13817
|
if (mentorSettings.allowAnonymous !== undefined &&
|
|
13766
13818
|
!(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId])) {
|
|
13767
|
-
|
|
13819
|
+
startNewChatInFlightRef.current = true;
|
|
13820
|
+
startNewChat().finally(() => {
|
|
13821
|
+
startNewChatInFlightRef.current = false;
|
|
13822
|
+
});
|
|
13768
13823
|
}
|
|
13769
13824
|
}
|
|
13770
13825
|
}, [shouldStartNewChat, showingSharedChat, mentorSettings.allowAnonymous]);
|
|
@@ -13775,6 +13830,76 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13775
13830
|
resetConnection();
|
|
13776
13831
|
}
|
|
13777
13832
|
}, [sessionIds, activeTab, sessionId, resetConnection]);
|
|
13833
|
+
// Auto-submit `initialPrompt` exactly once per mount after the chat
|
|
13834
|
+
// lifecycle has stabilized. Matches the existing proactive-prompt
|
|
13835
|
+
// precedent in `changeTab` (sendMessage(tab, content)) but is gated on
|
|
13836
|
+
// URL-driven deep-link signals instead of tab transitions.
|
|
13837
|
+
React__default.useEffect(() => {
|
|
13838
|
+
var _a;
|
|
13839
|
+
if (initialPromptInjectedRef.current)
|
|
13840
|
+
return;
|
|
13841
|
+
const trimmedPrompt = initialPrompt === null || initialPrompt === void 0 ? void 0 : initialPrompt.trim();
|
|
13842
|
+
if (!trimmedPrompt)
|
|
13843
|
+
return;
|
|
13844
|
+
// Bail while any state would make auto-submission unsafe or premature.
|
|
13845
|
+
if (isPreviewMode)
|
|
13846
|
+
return;
|
|
13847
|
+
if (showingSharedChat)
|
|
13848
|
+
return;
|
|
13849
|
+
if (isOffline)
|
|
13850
|
+
return;
|
|
13851
|
+
// Two-layer guard: the state catches re-runs after `getChats` settles
|
|
13852
|
+
// (which schedule a new render). The ref catches the in-render race
|
|
13853
|
+
// where this effect runs in the same cycle that `getChats` was invoked
|
|
13854
|
+
// — the state setter is async and the closure has a stale `false`.
|
|
13855
|
+
if (isLoadingChats)
|
|
13856
|
+
return;
|
|
13857
|
+
if (isLoadingChatsRef.current)
|
|
13858
|
+
return;
|
|
13859
|
+
if (!sessionIds[activeTab])
|
|
13860
|
+
return;
|
|
13861
|
+
if (streaming)
|
|
13862
|
+
return;
|
|
13863
|
+
if (isPending)
|
|
13864
|
+
return;
|
|
13865
|
+
// Dedup: scan back through the loaded history for the most recent
|
|
13866
|
+
// user message and compare its content. If it matches, this session
|
|
13867
|
+
// already has the prompt as a user turn (typical case: reload of a
|
|
13868
|
+
// `?prompt=` URL — the cached history ends with the assistant reply,
|
|
13869
|
+
// so the matching user message is one step back).
|
|
13870
|
+
const messages = chats[activeTab];
|
|
13871
|
+
let lastUserMessage;
|
|
13872
|
+
if (messages && messages.length > 0) {
|
|
13873
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
13874
|
+
if (((_a = messages[i]) === null || _a === void 0 ? void 0 : _a.role) === "user") {
|
|
13875
|
+
lastUserMessage = messages[i];
|
|
13876
|
+
break;
|
|
13877
|
+
}
|
|
13878
|
+
}
|
|
13879
|
+
}
|
|
13880
|
+
if (lastUserMessage &&
|
|
13881
|
+
typeof lastUserMessage.content === "string" &&
|
|
13882
|
+
lastUserMessage.content === trimmedPrompt) {
|
|
13883
|
+
initialPromptInjectedRef.current = true;
|
|
13884
|
+
return;
|
|
13885
|
+
}
|
|
13886
|
+
// Mark BEFORE dispatching: sendMessage triggers state updates that may
|
|
13887
|
+
// re-run this effect, and we want the guard active before any re-fire.
|
|
13888
|
+
initialPromptInjectedRef.current = true;
|
|
13889
|
+
sendMessage(activeTab, trimmedPrompt);
|
|
13890
|
+
}, [
|
|
13891
|
+
initialPrompt,
|
|
13892
|
+
isPreviewMode,
|
|
13893
|
+
showingSharedChat,
|
|
13894
|
+
isOffline,
|
|
13895
|
+
isLoadingChats,
|
|
13896
|
+
sessionIds,
|
|
13897
|
+
activeTab,
|
|
13898
|
+
chats,
|
|
13899
|
+
streaming,
|
|
13900
|
+
isPending,
|
|
13901
|
+
sendMessage,
|
|
13902
|
+
]);
|
|
13778
13903
|
async function changeTab(tab) {
|
|
13779
13904
|
var _a, _b, _c, _d;
|
|
13780
13905
|
// while responding to a message, do not change the tab
|