@iblai/web-utils 1.11.0 → 1.11.3

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.js CHANGED
@@ -11315,6 +11315,23 @@ const chatSlice = createSlice({
11315
11315
  [state.activeTab]: action.payload,
11316
11316
  };
11317
11317
  },
11318
+ prependOlderMessages: (state, action) => {
11319
+ var _a;
11320
+ const olderMessages = action.payload;
11321
+ if (!olderMessages || olderMessages.length === 0) {
11322
+ return;
11323
+ }
11324
+ const existing = (_a = state.chats[state.activeTab]) !== null && _a !== void 0 ? _a : [];
11325
+ const existingIds = new Set(existing.map((message) => message.id));
11326
+ const deduped = olderMessages.filter((message) => !existingIds.has(message.id));
11327
+ if (deduped.length === 0) {
11328
+ return;
11329
+ }
11330
+ state.chats = {
11331
+ ...state.chats,
11332
+ [state.activeTab]: [...deduped, ...existing],
11333
+ };
11334
+ },
11318
11335
  resetChats: (state) => {
11319
11336
  state.chats = defaultChatState;
11320
11337
  },
@@ -11363,7 +11380,7 @@ const chatSlice = createSlice({
11363
11380
  }
11364
11381
  },
11365
11382
  // Force-flush buffered reasoning to currentStreamingMessage
11366
- flushReasoningBuffer: (state, _action) => {
11383
+ flushReasoningBuffer: (state) => {
11367
11384
  if (state.streamingReasoningContentBuffer.length > 0) {
11368
11385
  state.currentStreamingMessage.reasoningContent +=
11369
11386
  state.streamingReasoningContentBuffer;
@@ -11376,7 +11393,7 @@ const chatSlice = createSlice({
11376
11393
  state.currentStreamingMessage.isReasoning = action.payload;
11377
11394
  },
11378
11395
  // Sets isReasoning = false (triggers UI collapse)
11379
- setReasoningComplete: (state, _action) => {
11396
+ setReasoningComplete: (state) => {
11380
11397
  state.currentStreamingMessage.isReasoning = false;
11381
11398
  },
11382
11399
  // Appends tool call entry
@@ -11523,7 +11540,7 @@ const chatSlice = createSlice({
11523
11540
  }
11524
11541
  },
11525
11542
  // Force flush any buffered content (called on artifact end or when UI needs update)
11526
- flushStreamingArtifactBuffer: (state, _action) => {
11543
+ flushStreamingArtifactBuffer: (state) => {
11527
11544
  if (state.currentStreamingArtifact &&
11528
11545
  state.streamingArtifactContentBuffer.length > 0) {
11529
11546
  state.currentStreamingArtifact.content +=
@@ -11532,7 +11549,7 @@ const chatSlice = createSlice({
11532
11549
  state.lastArtifactContentFlushTime = Date.now();
11533
11550
  }
11534
11551
  },
11535
- ensureStreamingAssistantMessage: (state, _action) => {
11552
+ ensureStreamingAssistantMessage: (state) => {
11536
11553
  const streamingId = state.currentStreamingMessage.id;
11537
11554
  if (!streamingId) {
11538
11555
  return;
@@ -11672,7 +11689,7 @@ const chatSlice = createSlice({
11672
11689
  action.payload.fullContent || state.currentStreamingArtifact.content;
11673
11690
  }
11674
11691
  },
11675
- clearStreamingArtifact: (state, _action) => {
11692
+ clearStreamingArtifact: (state) => {
11676
11693
  // Clear buffer along with artifact
11677
11694
  state.streamingArtifactContentBuffer = "";
11678
11695
  state.lastArtifactContentFlushTime = 0;
@@ -13903,6 +13920,281 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
13903
13920
  };
13904
13921
  };
13905
13922
 
13923
+ const INITIAL_CHAT_PAGE = 1;
13924
+ function normalizeSessionResult(result) {
13925
+ var _a, _b, _c, _d, _e, _f;
13926
+ const artifactVersions = (_a = result.artifact_versions) === null || _a === void 0 ? void 0 : _a.map((av) => {
13927
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
13928
+ return ({
13929
+ id: av.id,
13930
+ artifact: {
13931
+ id: (_a = av.artifact) === null || _a === void 0 ? void 0 : _a.id,
13932
+ title: (_b = av.artifact) === null || _b === void 0 ? void 0 : _b.title,
13933
+ content: (_c = av.artifact) === null || _c === void 0 ? void 0 : _c.content,
13934
+ file_extension: (_d = av.artifact) === null || _d === void 0 ? void 0 : _d.file_extension,
13935
+ llm_name: (_e = av.artifact) === null || _e === void 0 ? void 0 : _e.llm_name,
13936
+ llm_provider: (_f = av.artifact) === null || _f === void 0 ? void 0 : _f.llm_provider,
13937
+ date_created: (_g = av.artifact) === null || _g === void 0 ? void 0 : _g.date_created,
13938
+ date_updated: (_h = av.artifact) === null || _h === void 0 ? void 0 : _h.date_updated,
13939
+ metadata: (_j = av.artifact) === null || _j === void 0 ? void 0 : _j.metadata,
13940
+ username: (_k = av.artifact) === null || _k === void 0 ? void 0 : _k.username,
13941
+ session_id: (_l = av.artifact) === null || _l === void 0 ? void 0 : _l.session_id,
13942
+ current_version_number: (_m = av.artifact) === null || _m === void 0 ? void 0 : _m.current_version_number,
13943
+ version_count: (_o = av.artifact) === null || _o === void 0 ? void 0 : _o.version_count,
13944
+ },
13945
+ title: av.title,
13946
+ content: av.content,
13947
+ session_id: av.session_id,
13948
+ content_length: av.content_length,
13949
+ is_current: av.is_current,
13950
+ chat_message: av.chat_message,
13951
+ version_number: av.version_number,
13952
+ date_created: av.date_created,
13953
+ created_by: av.created_by,
13954
+ change_summary: av.change_summary,
13955
+ });
13956
+ });
13957
+ const fileAttachments = ((_b = result.files) === null || _b === void 0 ? void 0 : _b.map((file) => ({
13958
+ fileId: String(file.id),
13959
+ fileName: file.name,
13960
+ fileType: file.content_type,
13961
+ fileSize: file.file_size,
13962
+ uploadUrl: file.url,
13963
+ }))) || [];
13964
+ // Extract additional_kwargs - check both direct and nested paths
13965
+ const additionalKwargs = result.additional_kwargs || ((_d = (_c = result.message) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.additional_kwargs);
13966
+ // Extract reasoning content from additional_kwargs
13967
+ const reasoningSummaries = (_e = additionalKwargs === null || additionalKwargs === void 0 ? void 0 : additionalKwargs.reasoning) === null || _e === void 0 ? void 0 : _e.summary;
13968
+ const reasoningContent = Array.isArray(reasoningSummaries)
13969
+ ? reasoningSummaries
13970
+ .map((s) => s.text)
13971
+ .filter(Boolean)
13972
+ .join("\n\n")
13973
+ : undefined;
13974
+ // Extract tool calls from additional_kwargs
13975
+ const toolOutputs = additionalKwargs === null || additionalKwargs === void 0 ? void 0 : additionalKwargs.tool_outputs;
13976
+ const toolCalls = Array.isArray(toolOutputs)
13977
+ ? toolOutputs.map((tool) => {
13978
+ var _a;
13979
+ return ({
13980
+ id: tool.id || "",
13981
+ name: tool.type || "",
13982
+ log: ((_a = tool.action) === null || _a === void 0 ? void 0 : _a.query) || "",
13983
+ result: tool.status || "",
13984
+ });
13985
+ })
13986
+ : undefined;
13987
+ return {
13988
+ ...result,
13989
+ role: result.type === "human" ? "user" : "assistant",
13990
+ visible: true,
13991
+ id: result.id || new Date().getTime(),
13992
+ content: typeof result.content === "object" && result.content.length > 0
13993
+ ? (_f = result.content.find((item) => item.text)) === null || _f === void 0 ? void 0 : _f.text
13994
+ : result.content,
13995
+ // Add transformed artifact versions
13996
+ artifactVersions: artifactVersions || undefined,
13997
+ fileAttachments: fileAttachments.length > 0 ? fileAttachments : undefined,
13998
+ reasoningContent: reasoningContent || undefined,
13999
+ toolCalls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined,
14000
+ };
14001
+ }
14002
+ function normalizeSessionResults(results) {
14003
+ return (results === null || results === void 0 ? void 0 : results.map(normalizeSessionResult).reverse()) || [];
14004
+ }
14005
+ /**
14006
+ * A session re-fetch can omit `additional_kwargs`, dropping reasoning/tool-call
14007
+ * data that is already in memory. Carry those fields forward from the matching
14008
+ * existing message (by content) onto the freshly-fetched message in place.
14009
+ */
14010
+ function mergeReasoningAndToolCalls(incoming, existing) {
14011
+ if (existing.length === 0 || incoming.length === 0)
14012
+ return;
14013
+ const existingByContent = new Map();
14014
+ for (const m of existing) {
14015
+ if (m.reasoningContent || (m.toolCalls && m.toolCalls.length > 0)) {
14016
+ existingByContent.set(m.content, m);
14017
+ }
14018
+ }
14019
+ if (existingByContent.size === 0)
14020
+ return;
14021
+ for (const msg of incoming) {
14022
+ const match = existingByContent.get(msg.content);
14023
+ if (!match)
14024
+ continue;
14025
+ if (!msg.reasoningContent && match.reasoningContent) {
14026
+ msg.reasoningContent = match.reasoningContent;
14027
+ }
14028
+ if ((!msg.toolCalls || msg.toolCalls.length === 0) &&
14029
+ match.toolCalls &&
14030
+ match.toolCalls.length > 0) {
14031
+ msg.toolCalls = match.toolCalls;
14032
+ }
14033
+ }
14034
+ }
14035
+
14036
+ function useChatHistory({ tenantKey, mentorId, username, cachedSessionId, isOffline = false, }) {
14037
+ const dispatch = useDispatch();
14038
+ const chats = useSelector(selectChats);
14039
+ const activeTab = useSelector(selectActiveTab);
14040
+ const showingSharedChat = useSelector(selectShowingSharedChat);
14041
+ const [isLoadingChats, setIsLoadingChats] = React.useState(true);
14042
+ // Synchronous mirror of `isLoadingChats`. The state setter is async, so a
14043
+ // consumer effect running in the SAME render cycle as `getChats()`
14044
+ // invocation sees a stale `isLoadingChats=false` in its closure even
14045
+ // though `setIsLoadingChats(true)` has been scheduled. The ref flips
14046
+ // immediately (before `getChats` hits its first `await`), giving the
14047
+ // `initialPrompt` injection effect a reliable "fetch in progress" signal
14048
+ // it can read synchronously inside its body.
14049
+ const isLoadingChatsRef = React.useRef(true);
14050
+ const [hasMore, setHasMore] = React.useState(false);
14051
+ const [isLoadingOlderMessages, setIsLoadingOlderMessages] = React.useState(false);
14052
+ const currentPageRef = React.useRef(INITIAL_CHAT_PAGE);
14053
+ const isLoadingOlderRef = React.useRef(false);
14054
+ const [getSessionChats] = dataLayer.useLazyGetSessionIdQuery();
14055
+ const [getSharedSessionChats] = dataLayer.useLazyGetSharedSessionIdQuery();
14056
+ const fetchChatPage = React.useCallback((sessionId, page) => {
14057
+ if (showingSharedChat) {
14058
+ return getSharedSessionChats({
14059
+ sessionId,
14060
+ org: tenantKey,
14061
+ page,
14062
+ pageSize: dataLayer.CHAT_HISTORY_PAGE_SIZE,
14063
+ });
14064
+ }
14065
+ if (!username || username === ANONYMOUS_USERNAME) {
14066
+ return undefined;
14067
+ }
14068
+ return getSessionChats({
14069
+ sessionId,
14070
+ org: tenantKey,
14071
+ userId: username,
14072
+ page,
14073
+ pageSize: dataLayer.CHAT_HISTORY_PAGE_SIZE,
14074
+ });
14075
+ }, [
14076
+ showingSharedChat,
14077
+ getSharedSessionChats,
14078
+ getSessionChats,
14079
+ tenantKey,
14080
+ username,
14081
+ ]);
14082
+ const getChats = React.useCallback(async () => {
14083
+ var _a, _b, _c, _d;
14084
+ // Mark the fetch as in-flight so consumers gated on `isLoadingChats`
14085
+ // (e.g. the `initialPrompt` injection effect) defer until the resulting
14086
+ // `setNewMessages` has landed. The state setter alone is not enough —
14087
+ // it's async and the consumer effect may run in the same render cycle
14088
+ // with the stale closure — so flip the synchronous ref FIRST.
14089
+ isLoadingChatsRef.current = true;
14090
+ setIsLoadingChats(true);
14091
+ let data;
14092
+ try {
14093
+ data = await fetchChatPage((_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : "", INITIAL_CHAT_PAGE);
14094
+ let previousChats = [];
14095
+ try {
14096
+ previousChats = normalizeSessionResults((_b = data === null || data === void 0 ? void 0 : data.data) === null || _b === void 0 ? void 0 : _b.results);
14097
+ }
14098
+ catch (error) {
14099
+ console.error(JSON.stringify(error));
14100
+ }
14101
+ const nextPage = (_d = (_c = data === null || data === void 0 ? void 0 : data.data) === null || _c === void 0 ? void 0 : _c.next) !== null && _d !== void 0 ? _d : null;
14102
+ currentPageRef.current = INITIAL_CHAT_PAGE;
14103
+ setHasMore(nextPage !== null);
14104
+ mergeReasoningAndToolCalls(previousChats, chats[activeTab] || []);
14105
+ dispatch(chatActions.setNewMessages(previousChats));
14106
+ }
14107
+ catch (error) {
14108
+ console.error(JSON.stringify(error));
14109
+ }
14110
+ finally {
14111
+ setIsLoadingChats(false);
14112
+ isLoadingChatsRef.current = false;
14113
+ }
14114
+ }, [fetchChatPage, cachedSessionId, mentorId, dispatch]);
14115
+ const loadOlderMessages = React.useCallback(async () => {
14116
+ var _a, _b, _c;
14117
+ if (isLoadingOlderRef.current)
14118
+ return;
14119
+ if (!hasMore)
14120
+ return;
14121
+ if (isOffline)
14122
+ return;
14123
+ if (!showingSharedChat && (!username || username === ANONYMOUS_USERNAME)) {
14124
+ return;
14125
+ }
14126
+ const activeSessionId = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId];
14127
+ if (!activeSessionId)
14128
+ return;
14129
+ isLoadingOlderRef.current = true;
14130
+ setIsLoadingOlderMessages(true);
14131
+ const nextPage = currentPageRef.current + 1;
14132
+ try {
14133
+ const data = await fetchChatPage(activeSessionId, nextPage);
14134
+ let olderChats = [];
14135
+ try {
14136
+ olderChats = normalizeSessionResults((_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.results);
14137
+ }
14138
+ catch (error) {
14139
+ console.error(JSON.stringify(error));
14140
+ }
14141
+ if (olderChats.length > 0) {
14142
+ dispatch(chatActions.prependOlderMessages(olderChats));
14143
+ }
14144
+ currentPageRef.current = nextPage;
14145
+ setHasMore(((_c = (_b = data === null || data === void 0 ? void 0 : data.data) === null || _b === void 0 ? void 0 : _b.next) !== null && _c !== void 0 ? _c : null) !== null);
14146
+ }
14147
+ catch (error) {
14148
+ console.error(JSON.stringify(error));
14149
+ }
14150
+ finally {
14151
+ isLoadingOlderRef.current = false;
14152
+ setIsLoadingOlderMessages(false);
14153
+ }
14154
+ }, [
14155
+ hasMore,
14156
+ isOffline,
14157
+ showingSharedChat,
14158
+ username,
14159
+ cachedSessionId,
14160
+ mentorId,
14161
+ fetchChatPage,
14162
+ dispatch,
14163
+ ]);
14164
+ // Depend on the indexed string session id, not the whole `cachedSessionId`
14165
+ // object. Consumers (e.g. `useLocalStorage`) often re-emit a new object
14166
+ // reference on every render even when the underlying value is unchanged,
14167
+ // which would otherwise cause this effect to re-fire `getChats()` per
14168
+ // render — and each `setNewMessages` would wipe any user message
14169
+ // dispatched in between (the URL `initialPrompt` race).
14170
+ const currentMentorSessionId = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId];
14171
+ React.useEffect(() => {
14172
+ if (currentMentorSessionId) {
14173
+ dispatch(chatActions.updateSessionIds(currentMentorSessionId));
14174
+ // Skip fetching previous chats when offline
14175
+ if (!isOffline) {
14176
+ getChats();
14177
+ }
14178
+ else {
14179
+ setIsLoadingChats(false);
14180
+ isLoadingChatsRef.current = false;
14181
+ }
14182
+ }
14183
+ else {
14184
+ setIsLoadingChats(false);
14185
+ isLoadingChatsRef.current = false;
14186
+ }
14187
+ }, [currentMentorSessionId, isOffline]);
14188
+ return {
14189
+ getChats,
14190
+ loadOlderMessages,
14191
+ hasMore,
14192
+ isLoadingOlderMessages,
14193
+ isLoadingChats,
14194
+ isLoadingChatsRef,
14195
+ };
14196
+ }
14197
+
13906
14198
  function useMentorSettings({ mentorId, tenantKey, isPublicRoute = false, mainTenantKey, }) {
13907
14199
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
13908
14200
  const username = useUsername();
@@ -14078,7 +14370,13 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
14078
14370
  isOffline,
14079
14371
  onOfflineWithoutLocalLLM,
14080
14372
  });
14081
- const [isLoadingChats, setIsLoadingChats] = React.useState(true);
14373
+ const { getChats, loadOlderMessages, hasMore, isLoadingOlderMessages, isLoadingChats, isLoadingChatsRef, } = useChatHistory({
14374
+ tenantKey,
14375
+ mentorId,
14376
+ username,
14377
+ cachedSessionId,
14378
+ isOffline,
14379
+ });
14082
14380
  // Tracks whether the optional `initialPrompt` prop has already been
14083
14381
  // auto-submitted for this hook instance. Set to `true` the moment the
14084
14382
  // effect decides to act (either to send or because the prompt is already
@@ -14095,197 +14393,6 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
14095
14393
  // that wipes anything dispatched (like `initialPrompt`'s
14096
14394
  // `addUserMessage`) between the two `getChats` resolutions.
14097
14395
  const startNewChatInFlightRef = React.useRef(false);
14098
- // Synchronous mirror of `isLoadingChats`. The state setter is async, so a
14099
- // consumer effect running in the SAME render cycle as `getChats()`
14100
- // invocation sees a stale `isLoadingChats=false` in its closure even
14101
- // though `setIsLoadingChats(true)` has been scheduled. The ref flips
14102
- // immediately (before `getChats` hits its first `await`), giving the
14103
- // `initialPrompt` injection effect a reliable "fetch in progress" signal
14104
- // it can read synchronously inside its body.
14105
- const isLoadingChatsRef = React.useRef(true);
14106
- const [getSessionChats] = dataLayer.useLazyGetSessionIdQuery();
14107
- const [getSharedSessionChats] = dataLayer.useLazyGetSharedSessionIdQuery();
14108
- const getChats = React.useCallback(async () => {
14109
- var _a, _b, _c, _d;
14110
- // Mark the fetch as in-flight so consumers gated on `isLoadingChats`
14111
- // (e.g. the `initialPrompt` injection effect) defer until the resulting
14112
- // `setNewMessages` has landed. The state setter alone is not enough —
14113
- // it's async and the consumer effect may run in the same render cycle
14114
- // with the stale closure — so flip the synchronous ref FIRST.
14115
- isLoadingChatsRef.current = true;
14116
- setIsLoadingChats(true);
14117
- let data;
14118
- try {
14119
- if (showingSharedChat) {
14120
- data = await getSharedSessionChats({
14121
- sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : "",
14122
- org: tenantKey,
14123
- });
14124
- }
14125
- else if (!!username && username !== ANONYMOUS_USERNAME) {
14126
- data = await getSessionChats({
14127
- sessionId: (_b = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _b !== void 0 ? _b : "",
14128
- org: tenantKey,
14129
- // @ts-expect-error - userId is passed but not in generated API types
14130
- userId: username,
14131
- });
14132
- }
14133
- let previousChats = [];
14134
- try {
14135
- previousChats =
14136
- ((_d = (_c = data === null || data === void 0 ? void 0 : data.data) === null || _c === void 0 ? void 0 : _c.results) === null || _d === void 0 ? void 0 : _d.map((result) => {
14137
- var _a, _b, _c, _d, _e, _f;
14138
- const artifactVersions = (_a = result.artifact_versions) === null || _a === void 0 ? void 0 : _a.map((av) => {
14139
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
14140
- return ({
14141
- id: av.id,
14142
- artifact: {
14143
- id: (_a = av.artifact) === null || _a === void 0 ? void 0 : _a.id,
14144
- title: (_b = av.artifact) === null || _b === void 0 ? void 0 : _b.title,
14145
- content: (_c = av.artifact) === null || _c === void 0 ? void 0 : _c.content,
14146
- file_extension: (_d = av.artifact) === null || _d === void 0 ? void 0 : _d.file_extension,
14147
- llm_name: (_e = av.artifact) === null || _e === void 0 ? void 0 : _e.llm_name,
14148
- llm_provider: (_f = av.artifact) === null || _f === void 0 ? void 0 : _f.llm_provider,
14149
- date_created: (_g = av.artifact) === null || _g === void 0 ? void 0 : _g.date_created,
14150
- date_updated: (_h = av.artifact) === null || _h === void 0 ? void 0 : _h.date_updated,
14151
- metadata: (_j = av.artifact) === null || _j === void 0 ? void 0 : _j.metadata,
14152
- username: (_k = av.artifact) === null || _k === void 0 ? void 0 : _k.username,
14153
- session_id: (_l = av.artifact) === null || _l === void 0 ? void 0 : _l.session_id,
14154
- current_version_number: (_m = av.artifact) === null || _m === void 0 ? void 0 : _m.current_version_number,
14155
- version_count: (_o = av.artifact) === null || _o === void 0 ? void 0 : _o.version_count,
14156
- },
14157
- title: av.title,
14158
- content: av.content,
14159
- session_id: av.session_id,
14160
- content_length: av.content_length,
14161
- is_current: av.is_current,
14162
- chat_message: av.chat_message,
14163
- version_number: av.version_number,
14164
- date_created: av.date_created,
14165
- created_by: av.created_by,
14166
- change_summary: av.change_summary,
14167
- });
14168
- });
14169
- const fileAttachments = ((_b = result.files) === null || _b === void 0 ? void 0 : _b.map((file) => ({
14170
- fileId: String(file.id),
14171
- fileName: file.name,
14172
- fileType: file.content_type,
14173
- fileSize: file.file_size,
14174
- uploadUrl: file.url,
14175
- }))) || [];
14176
- // Extract additional_kwargs - check both direct and nested paths
14177
- const additionalKwargs = result.additional_kwargs ||
14178
- ((_d = (_c = result.message) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.additional_kwargs);
14179
- // Extract reasoning content from additional_kwargs
14180
- const reasoningSummaries = (_e = additionalKwargs === null || additionalKwargs === void 0 ? void 0 : additionalKwargs.reasoning) === null || _e === void 0 ? void 0 : _e.summary;
14181
- const reasoningContent = Array.isArray(reasoningSummaries)
14182
- ? reasoningSummaries
14183
- .map((s) => s.text)
14184
- .filter(Boolean)
14185
- .join("\n\n")
14186
- : undefined;
14187
- // Extract tool calls from additional_kwargs
14188
- const toolOutputs = additionalKwargs === null || additionalKwargs === void 0 ? void 0 : additionalKwargs.tool_outputs;
14189
- const toolCalls = Array.isArray(toolOutputs)
14190
- ? toolOutputs.map((tool) => {
14191
- var _a;
14192
- return ({
14193
- id: tool.id || "",
14194
- name: tool.type || "",
14195
- log: ((_a = tool.action) === null || _a === void 0 ? void 0 : _a.query) || "",
14196
- result: tool.status || "",
14197
- });
14198
- })
14199
- : undefined;
14200
- return {
14201
- ...result,
14202
- role: result.type === "human" ? "user" : "assistant",
14203
- visible: true,
14204
- id: result.id || new Date().getTime(),
14205
- content: typeof result.content === "object" &&
14206
- result.content.length > 0
14207
- ? (_f = result.content.find((item) => item.text)) === null || _f === void 0 ? void 0 : _f.text
14208
- : result.content,
14209
- // Add transformed artifact versions
14210
- artifactVersions: artifactVersions || undefined,
14211
- fileAttachments: fileAttachments.length > 0 ? fileAttachments : undefined,
14212
- reasoningContent: reasoningContent || undefined,
14213
- toolCalls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined,
14214
- };
14215
- }).reverse()) || [];
14216
- }
14217
- catch (error) {
14218
- console.error(JSON.stringify(error));
14219
- }
14220
- // Preserve reasoningContent and toolCalls from existing messages
14221
- // when the session API re-fetch doesn't include additional_kwargs.
14222
- const existingMessages = chats[activeTab] || [];
14223
- if (existingMessages.length > 0 && previousChats.length > 0) {
14224
- const existingByContent = new Map();
14225
- for (const m of existingMessages) {
14226
- if (m.reasoningContent || (m.toolCalls && m.toolCalls.length > 0)) {
14227
- existingByContent.set(m.content, m);
14228
- }
14229
- }
14230
- if (existingByContent.size > 0) {
14231
- for (const msg of previousChats) {
14232
- const existing = existingByContent.get(msg.content);
14233
- if (existing) {
14234
- if (!msg.reasoningContent && existing.reasoningContent) {
14235
- msg.reasoningContent = existing.reasoningContent;
14236
- }
14237
- if ((!msg.toolCalls || msg.toolCalls.length === 0) &&
14238
- existing.toolCalls &&
14239
- existing.toolCalls.length > 0) {
14240
- msg.toolCalls = existing.toolCalls;
14241
- }
14242
- }
14243
- }
14244
- }
14245
- }
14246
- dispatch(chatActions.setNewMessages(previousChats));
14247
- }
14248
- catch (error) {
14249
- console.error(JSON.stringify(error));
14250
- }
14251
- finally {
14252
- setIsLoadingChats(false);
14253
- isLoadingChatsRef.current = false;
14254
- }
14255
- }, [
14256
- showingSharedChat,
14257
- cachedSessionId,
14258
- mentorId,
14259
- tenantKey,
14260
- username,
14261
- getSharedSessionChats,
14262
- getSessionChats,
14263
- dispatch,
14264
- ]);
14265
- // Depend on the indexed string session id, not the whole `cachedSessionId`
14266
- // object. Consumers (e.g. `useLocalStorage`) often re-emit a new object
14267
- // reference on every render even when the underlying value is unchanged,
14268
- // which would otherwise cause this effect to re-fire `getChats()` per
14269
- // render — and each `setNewMessages` would wipe any user message
14270
- // dispatched in between (the URL `initialPrompt` race).
14271
- const currentMentorSessionId = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId];
14272
- React.useEffect(() => {
14273
- if (currentMentorSessionId) {
14274
- dispatch(chatActions.updateSessionIds(currentMentorSessionId));
14275
- // Skip fetching previous chats when offline
14276
- if (!isOffline) {
14277
- getChats();
14278
- }
14279
- else {
14280
- setIsLoadingChats(false);
14281
- isLoadingChatsRef.current = false;
14282
- }
14283
- }
14284
- else {
14285
- setIsLoadingChats(false);
14286
- isLoadingChatsRef.current = false;
14287
- }
14288
- }, [currentMentorSessionId, isOffline]);
14289
14396
  const startNewChat = React.useCallback(async () => {
14290
14397
  // Reset all chat state
14291
14398
  if (!showingSharedChat) {
@@ -14518,6 +14625,9 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
14518
14625
  resetConnection,
14519
14626
  isLoadingChats,
14520
14627
  refetchChats: getChats,
14628
+ loadOlderMessages,
14629
+ hasMore,
14630
+ isLoadingOlderMessages,
14521
14631
  };
14522
14632
  }
14523
14633