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