impact-chatbot 2.3.51 → 2.3.53

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.esm.js CHANGED
@@ -18,13 +18,14 @@ import remarkBreaks from 'remark-breaks';
18
18
  import remarkGfm from 'remark-gfm';
19
19
  import DOMPurify from 'dompurify';
20
20
  import { setSelectedFilters, setFilterConfiguration, getFilterUserConfiguration } from 'core/actions/filterAction';
21
- import { setChatbotContext, setStepFormStreamData, setPersistedFormValues, clearPersistedFormValues, setCurrentAgentChatId, setThinkingContext, setHierarchyKeyValue, setSavedFilterSets } from 'core/actions/smartBotActions';
21
+ import { setChatbotContext, setStepFormStreamData, setThinkingContext, setPersistedFormValues, clearPersistedFormValues, setCurrentAgentChatId, setHierarchyKeyValue, setSavedFilterSets } from 'core/actions/smartBotActions';
22
22
  import { useNavigate, useLocation } from 'react-router-dom-v5-compat';
23
23
  import RefreshIcon from '@mui/icons-material/Refresh';
24
24
  import styled from 'styled-components';
25
25
  import { CircularProgress, Typography, Grid } from '@mui/material';
26
26
  import { fetchBaseUrl, replaceSpecialCharacter as replaceSpecialCharacter$1, fetchLegacyAgentScreen } from 'core/Utils/functions/utils';
27
27
  import { Button, Modal, Slider, Select, DatePicker, DateRangePicker, Checkbox, RadioButtonGroup, Input, Tabs, Loader, Tooltip, ChatBotComponent } from 'impact-ui-v3';
28
+ import axios from 'axios';
28
29
  import isArray$2 from 'lodash/isArray';
29
30
  import { stopAgentFlow } from 'core/commonComponents/smartBot/services/chatbot-services';
30
31
  import AgGridComponent from 'core/Utils/agGrid';
@@ -1277,12 +1278,70 @@ const ThinkingIndicator = (props) => {
1277
1278
  return (jsx("div", { children: jsx("div", { children: thinkingContentState ? (jsx("div", { children: jsx(TextRenderer, { text: thinkingContentState, thinking: true }) })) : (jsxs("div", { className: classes.thinkingSpinner, children: [jsx("span", { className: classes.thinkingDot }), jsx("span", { className: classes.thinkingDot }), jsx("span", { className: classes.thinkingDot })] })) }) }));
1278
1279
  };
1279
1280
 
1281
+ /**
1282
+ * Formats elapsed seconds into "Xm:Ys" display string.
1283
+ * e.g. 0 -> "0m:00s", 65 -> "1m:05s", 130 -> "2m:10s"
1284
+ */
1285
+ const formatElapsedTime = (totalSeconds) => {
1286
+ const minutes = Math.floor(totalSeconds / 60);
1287
+ const seconds = totalSeconds % 60;
1288
+ return `${minutes}m:${String(seconds).padStart(2, '0')}s`;
1289
+ };
1280
1290
  const ThinkinHeaderInfo = (props) => {
1281
1291
  const thinkingContext = useSelector((state) => {
1282
1292
  return state.smartBotReducer.thinkingContext;
1283
1293
  });
1284
- const { thinkingHeaderMessage } = thinkingContext;
1285
- return (jsx("div", { className: "thinkin-header-info", children: thinkingHeaderMessage }));
1294
+ const { streamStartTime, isStreamCompleted, finalElapsedSeconds, thinkingHeaderMessage } = thinkingContext;
1295
+ const [elapsed, setElapsed] = useState(0);
1296
+ const intervalRef = useRef(null);
1297
+ // Once this instance sees "completed", freeze it permanently so a future
1298
+ // chat's streamStartTime doesn't cause it to start ticking again.
1299
+ const frozenRef = useRef(false);
1300
+ const frozenTextRef = useRef(null);
1301
+ useEffect(() => {
1302
+ // If already frozen, ignore all future Redux changes
1303
+ if (frozenRef.current)
1304
+ return;
1305
+ // Clear any existing interval
1306
+ if (intervalRef.current) {
1307
+ clearInterval(intervalRef.current);
1308
+ intervalRef.current = null;
1309
+ }
1310
+ if (isStreamCompleted && typeof finalElapsedSeconds === 'number') {
1311
+ // Freeze this instance — it will never tick again
1312
+ frozenRef.current = true;
1313
+ frozenTextRef.current = `Completed in ${formatElapsedTime(finalElapsedSeconds)}`;
1314
+ setElapsed(finalElapsedSeconds);
1315
+ }
1316
+ else if (streamStartTime && !isStreamCompleted) {
1317
+ // Live timer — update every second
1318
+ const tick = () => {
1319
+ const now = Date.now();
1320
+ const diffSeconds = Math.floor((now - streamStartTime) / 1000);
1321
+ setElapsed(diffSeconds);
1322
+ };
1323
+ tick(); // immediate first tick
1324
+ intervalRef.current = setInterval(tick, 1000);
1325
+ }
1326
+ return () => {
1327
+ if (intervalRef.current) {
1328
+ clearInterval(intervalRef.current);
1329
+ intervalRef.current = null;
1330
+ }
1331
+ };
1332
+ }, [streamStartTime, isStreamCompleted, finalElapsedSeconds]);
1333
+ // Determine display text
1334
+ let displayText = thinkingHeaderMessage || '';
1335
+ if (frozenRef.current && frozenTextRef.current) {
1336
+ displayText = frozenTextRef.current;
1337
+ }
1338
+ else if (streamStartTime && !isStreamCompleted) {
1339
+ displayText = `Working for ${formatElapsedTime(elapsed)}`;
1340
+ }
1341
+ else if (isStreamCompleted && typeof finalElapsedSeconds === 'number') {
1342
+ displayText = `Completed in ${formatElapsedTime(finalElapsedSeconds)}`;
1343
+ }
1344
+ return (jsx("div", { className: "thinkin-header-info", children: displayText }));
1286
1345
  };
1287
1346
 
1288
1347
  // import { exampleGraphData } from "../examples/GraphExample";
@@ -4052,7 +4111,7 @@ const useChatState = () => {
4052
4111
  const [chatId, setChatId] = useState("");
4053
4112
  const [isStop, setIsStop] = useState(false);
4054
4113
  const [functionsState, setFunctionsState] = useState({});
4055
- const [thinkingHeaderMessage, setThinkingHeaderMessage] = useState("Planning next moves...");
4114
+ const [thinkingHeaderMessage, setThinkingHeaderMessage] = useState("Working… 0m:00s");
4056
4115
  const [legacyAgentScreen, setLegacyAgentScreen] = useState(false);
4057
4116
  const [uniqueChatId, setUniqueChatId] = useState("");
4058
4117
  const [fieldNumber, setFieldNumber] = useState(0);
@@ -5277,9 +5336,9 @@ const AxiosSource = (url, opts, messageToStoreRef) => {
5277
5336
  headers: opts.headers,
5278
5337
  data: opts.body,
5279
5338
  signal: controller.signal,
5280
- responseType: "stream",
5339
+ responseType: "text",
5281
5340
  onDownloadProgress: (progressEvent) => {
5282
- const response = progressEvent.currentTarget;
5341
+ const response = progressEvent.currentTarget || progressEvent.target;
5283
5342
  // Emit 'open' event when the connection is first established
5284
5343
  if (!progressEvent.loaded) {
5285
5344
  eventTarget.dispatchEvent(new Event("open", {
@@ -5314,8 +5373,9 @@ const AxiosSource = (url, opts, messageToStoreRef) => {
5314
5373
  })
5315
5374
  .catch((error) => {
5316
5375
  let reason = "Network request failed";
5376
+ console.error("[AxiosSource] Request failed:", error);
5317
5377
  // Determine specific error reasons
5318
- if (axiosInstance.isCancel(error)) {
5378
+ if (axios.isCancel(error)) {
5319
5379
  reason = "Network request aborted";
5320
5380
  }
5321
5381
  else if (error.code === "ECONNABORTED") {
@@ -5386,6 +5446,7 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5386
5446
  status: "",
5387
5447
  });
5388
5448
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
5449
+ const thinkingContext = useSelector((state) => state.smartBotReducer.thinkingContext);
5389
5450
  const handleButtonClick = (button) => {
5390
5451
  if (isStepFormSubmit) {
5391
5452
  // Build the user_input from chatbotContext
@@ -5400,7 +5461,6 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5400
5461
  : typeof value === 'number' ? value : String(value);
5401
5462
  }
5402
5463
  }
5403
- console.log("[ButtonContent] step form submit, calling init API with userInput:", userInput);
5404
5464
  dispatch(setChatbotContext({}));
5405
5465
  // Call the init API via SSE directly
5406
5466
  callInitApiStream(userInput);
@@ -5459,6 +5519,9 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5459
5519
  dispatch(setStepFormStreamData({ status: "streaming_start", chunks: [], sessionId }));
5460
5520
  // Fire DOM event so SmartBot can show stop icon (Redux gets cleared by TabularContent before parent effects run)
5461
5521
  window.dispatchEvent(new CustomEvent("stepFormStreamStart"));
5522
+ // Capture start time for computing elapsed on completion.
5523
+ // Timer keeps running from the original streamStartTime (set when first API was hit).
5524
+ const stepFormStreamStartTime = Date.now();
5462
5525
  sourceRef.current = AxiosSource(endPoint, {
5463
5526
  method: "POST",
5464
5527
  headers: {
@@ -5473,7 +5536,6 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5473
5536
  sourceRef.current.addEventListener("message", (event) => {
5474
5537
  try {
5475
5538
  const data = JSON.parse(event.data);
5476
- console.log("[ButtonContent] SSE chunk:", data);
5477
5539
  // Always keep stepFormStreamControl.sessionId in sync with the latest chunk's session_id
5478
5540
  if (data?.session_id) {
5479
5541
  stepFormStreamControl.sessionId = data.session_id;
@@ -5514,6 +5576,22 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5514
5576
  stepFormStreamControl.isStreaming = false;
5515
5577
  stepFormStreamControl.abort = null;
5516
5578
  window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5579
+ // Stop the timer only when status:"completed" is received
5580
+ if (data?.status === "completed") {
5581
+ // Use the original streamStartTime from Redux (set when first API was hit)
5582
+ const originalStartTime = thinkingContext?.streamStartTime || stepFormStreamStartTime;
5583
+ const totalElapsed = Math.floor((Date.now() - originalStartTime) / 1000);
5584
+ const sfMin = Math.floor(totalElapsed / 60);
5585
+ const sfSec = totalElapsed % 60;
5586
+ const sfWorkedLabel = `Completed in ${sfMin}m:${String(sfSec).padStart(2, '0')}s`;
5587
+ dispatch(setThinkingContext({
5588
+ streamStartTime: originalStartTime,
5589
+ isStreamCompleted: true,
5590
+ finalElapsedSeconds: totalElapsed,
5591
+ thinkingHeaderMessage: sfWorkedLabel,
5592
+ thinkingContent: "",
5593
+ }));
5594
+ }
5517
5595
  // Signal tab switch to agent_response when status is "completed",
5518
5596
  // but only if the response doesn't contain a new step_form that needs user interaction
5519
5597
  const hasStepForm = chunksRef.some((c) => c.status === "step_form");
@@ -6972,24 +7050,6 @@ function clearTabNotification() {
6972
7050
  * This survives the cloneDeep replacement of botData in SmartBot's useEffect.
6973
7051
  */
6974
7052
  const streamStateMap = new Map();
6975
- /**
6976
- * Formats thinking time to display minutes when appropriate
6977
- * @param {number} seconds - Time in seconds
6978
- * @returns {string} Formatted time string
6979
- */
6980
- const formatThinkingTime = (seconds) => {
6981
- if (seconds < 60) {
6982
- return `${seconds} second${seconds !== 1 ? 's' : ''}`;
6983
- }
6984
- const minutes = Math.floor(seconds / 60);
6985
- const remainingSeconds = seconds % 60;
6986
- if (remainingSeconds === 0) {
6987
- return `${minutes} minute${minutes !== 1 ? 's' : ''}`;
6988
- }
6989
- else {
6990
- return `${minutes} min ${remainingSeconds} sec`;
6991
- }
6992
- };
6993
7053
  /**
6994
7054
  * StreamedContent Component
6995
7055
  * Handles real-time streaming of chat messages with a typing-like effect
@@ -7053,7 +7113,8 @@ const StreamedContent = ({ botData }) => {
7053
7113
  useRef(""); // Tracks the last received message
7054
7114
  const thinkingStartTimeRef = useRef(null);
7055
7115
  const thinkingTimeFinalRef = useRef(0);
7056
- const thinkingHeaderMessageRef = useRef("Planning next moves.....");
7116
+ const thinkingHeaderMessageRef = useRef("Working for 0m:00s");
7117
+ const streamStartTimeRef = useRef(null);
7057
7118
  const thinkingDoneRef = useRef(false);
7058
7119
  const setThinkingContentRef = useRef(setThinkingContent); // Store current setThinkingContent function
7059
7120
  const streamTimeoutRef = useRef(null); // Ref for stream timeout
@@ -7119,6 +7180,17 @@ const StreamedContent = ({ botData }) => {
7119
7180
  ? botData?.utilityObject?.method
7120
7181
  : "PUT";
7121
7182
  delete botData.inputBody.chat_input;
7183
+ // Start the timer immediately when the API is called
7184
+ if (!streamStartTimeRef.current) {
7185
+ streamStartTimeRef.current = Date.now();
7186
+ dispatch(setThinkingContext({
7187
+ streamStartTime: streamStartTimeRef.current,
7188
+ isStreamCompleted: false,
7189
+ finalElapsedSeconds: null,
7190
+ thinkingHeaderMessage: "Working for 0m:00s",
7191
+ thinkingContent: "",
7192
+ }));
7193
+ }
7122
7194
  // Initialize SSE connection with API endpoint
7123
7195
  sourceRef.current = AxiosSource(endPoint, {
7124
7196
  method: method,
@@ -7207,7 +7279,7 @@ const StreamedContent = ({ botData }) => {
7207
7279
  setQuestionsStepsMap(cloneDeep(initialMap));
7208
7280
  }
7209
7281
  else if (data.status === "thinking") {
7210
- messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = "Planning next moves";
7282
+ messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = (jsx(ThinkinHeaderInfo, { thinkingHeaderMessage: "Working for 0m:00s" }));
7211
7283
  // Start thinking if not already started
7212
7284
  if (!isThinking) {
7213
7285
  setIsThinking(true);
@@ -7218,6 +7290,9 @@ const StreamedContent = ({ botData }) => {
7218
7290
  thinkingContentRef.current = thinkingContentRef.current + data.message;
7219
7291
  messageToStoreRef.current.chatData.thinkingResponse.thinkingStream = newValue;
7220
7292
  dispatch(setThinkingContext({
7293
+ streamStartTime: streamStartTimeRef.current,
7294
+ isStreamCompleted: false,
7295
+ finalElapsedSeconds: null,
7221
7296
  thinkingHeaderMessage: thinkingHeaderMessageRef.current,
7222
7297
  thinkingContent: thinkingContentRef.current,
7223
7298
  }));
@@ -7350,7 +7425,8 @@ const StreamedContent = ({ botData }) => {
7350
7425
  stepFormStreamControl.baseUrl = _burl;
7351
7426
  // If this is the [DONE] chunk, mark streaming as complete
7352
7427
  if (data.message === "[DONE]") {
7353
- setStepsDone(true);
7428
+ // Do NOT set stepsDone here — step_form [DONE] is not status:"completed".
7429
+ // stepsDone should only be true when status:"completed" arrives.
7354
7430
  setIsStreamingDone(true);
7355
7431
  const doneState = streamStateMap.get(streamKey);
7356
7432
  if (doneState)
@@ -7379,10 +7455,13 @@ const StreamedContent = ({ botData }) => {
7379
7455
  // Store thinking time in messageToStoreRef for persistence
7380
7456
  messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
7381
7457
  thinkingTimeFinalRef.current = finalThinkingTime;
7382
- setThinkingHeaderMessage(`Thought for ${formatThinkingTime(finalThinkingTime)}`);
7383
- thinkingHeaderMessageRef.current = `Thought for ${formatThinkingTime(finalThinkingTime)}`;
7458
+ // Keep timer running — do NOT set "Worked for" here.
7459
+ // Timer continues showing "Working for Xm:Ys" until status:"completed" arrives.
7384
7460
  dispatch(setThinkingContext({
7385
- thinkingHeaderMessage: `Thinking Completed`,
7461
+ streamStartTime: streamStartTimeRef.current,
7462
+ isStreamCompleted: false,
7463
+ finalElapsedSeconds: null,
7464
+ thinkingHeaderMessage: thinkingHeaderMessageRef.current,
7386
7465
  thinkingContent: thinkingContentRef.current,
7387
7466
  }));
7388
7467
  }
@@ -7496,11 +7575,31 @@ const StreamedContent = ({ botData }) => {
7496
7575
  if (currentMode === "agent") {
7497
7576
  setIsStop(false);
7498
7577
  // Use thinkingTime state instead of thinkingTimeFinalRef.current to ensure we have the correct value
7499
- thinkingTime || thinkingTimeFinalRef.current || 1;
7500
- messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = `Thinking Completed`;
7501
- // messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = `Thought for ${formatThinkingTime(
7502
- // finalThinkingTime
7503
- // )}`;
7578
+ const finalThinkingTime = thinkingTime || thinkingTimeFinalRef.current || 1;
7579
+ const completedElapsed = streamStartTimeRef.current
7580
+ ? Math.floor((Date.now() - streamStartTimeRef.current) / 1000)
7581
+ : finalThinkingTime;
7582
+ const compMin = Math.floor(completedElapsed / 60);
7583
+ const compSec = completedElapsed % 60;
7584
+ const workedForLabel = `Completed in ${compMin}m:${String(compSec).padStart(2, '0')}s`;
7585
+ // Only stop the timer if we got status:"completed" (stepsDone=true).
7586
+ // If stream ended with step_form [DONE], keep timer running for the next restream.
7587
+ if (stepsDone) {
7588
+ // Completed — use a static string so this chat's heading won't
7589
+ // re-animate when a future chat dispatches a new streamStartTime.
7590
+ messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = workedForLabel;
7591
+ dispatch(setThinkingContext({
7592
+ streamStartTime: streamStartTimeRef.current,
7593
+ isStreamCompleted: true,
7594
+ finalElapsedSeconds: completedElapsed,
7595
+ thinkingHeaderMessage: workedForLabel,
7596
+ thinkingContent: thinkingContentRef.current,
7597
+ }));
7598
+ }
7599
+ else {
7600
+ // step_form case: keep heading as the live ThinkinHeaderInfo component so the timer keeps ticking
7601
+ messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = (jsx(ThinkinHeaderInfo, { thinkingHeaderMessage: "Working for 0m:00s" }));
7602
+ }
7504
7603
  let actualResponse = cloneDeep(messageToStoreRef.current.chatData.thinkingResponse.thinkingStream);
7505
7604
  messageToStoreRef.current.chatData.thinkingResponse.thinkingContent = actualResponse;
7506
7605
  parseResponse(messageToStoreRef.current.chatData, "text");
@@ -7741,6 +7840,20 @@ const StreamedContent = ({ botData }) => {
7741
7840
  setShowThoughtDropdown(true);
7742
7841
  messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
7743
7842
  }
7843
+ // Stop the timer on abort
7844
+ const abortElapsed = streamStartTimeRef.current
7845
+ ? Math.floor((Date.now() - streamStartTimeRef.current) / 1000)
7846
+ : 0;
7847
+ const abortMin = Math.floor(abortElapsed / 60);
7848
+ const abortSec = abortElapsed % 60;
7849
+ const abortLabel = `Completed in ${abortMin}m:${String(abortSec).padStart(2, '0')}s`;
7850
+ dispatch(setThinkingContext({
7851
+ streamStartTime: streamStartTimeRef.current,
7852
+ isStreamCompleted: true,
7853
+ finalElapsedSeconds: abortElapsed,
7854
+ thinkingHeaderMessage: abortLabel,
7855
+ thinkingContent: thinkingContentRef.current,
7856
+ }));
7744
7857
  // If no content yet, show aborted message
7745
7858
  // if (isEmpty(messageToStoreRef.current.chatData?.response)) {
7746
7859
  messageToStoreRef.current.chatData.response =
@@ -7789,14 +7902,12 @@ const StreamedContent = ({ botData }) => {
7789
7902
  };
7790
7903
  }, [isStreaming, isStreamingDone]);
7791
7904
  /**
7792
- * Auto-abort previous stream when starting a new one
7905
+ * Auto-abort previous stream when starting a new one.
7906
+ * NOTE: This is intentionally removed. In axios 0.32.0, signal/abort is properly
7907
+ * supported, and this effect was firing on mount causing immediate cancellation.
7908
+ * Stream abort on "new chat" is already handled by handleNewChatClick calling
7909
+ * functionsState.abortStreaming(). The streamStateMap logic handles all other cases.
7793
7910
  */
7794
- useEffect(() => {
7795
- // If we already have a source and it's streaming, abort it before starting new one
7796
- if (sourceRef.current && isStreaming) {
7797
- sourceRef.current.close();
7798
- }
7799
- }, [botData.inputBody]); // Trigger when new input is provided
7800
7911
  /**
7801
7912
  * Set up timeout for auto-abort (optional - can be configured)
7802
7913
  */
@@ -11628,7 +11739,7 @@ const useConversationManagement = (chatDataRef, currentMode, activeConversationI
11628
11739
  thinkingStream: item.data,
11629
11740
  thinkingContent: item.data,
11630
11741
  thinkingTime: 1,
11631
- thinkingHeading: "Thinking Completed",
11742
+ thinkingHeading: "Completed in 0m:00s",
11632
11743
  };
11633
11744
  }
11634
11745
  else if (item.chatType === "steps") {
@@ -11823,7 +11934,9 @@ const useConversationManagement = (chatDataRef, currentMode, activeConversationI
11823
11934
  thinkingResponse: msg.thinkingResponse ? {
11824
11935
  thinkingStream: msg.thinkingResponse.thinkingStream,
11825
11936
  thinkingTime: msg.thinkingResponse.thinkingTime,
11826
- thinkingHeading: msg.thinkingResponse.thinkingHeading,
11937
+ thinkingHeading: typeof msg.thinkingResponse.thinkingHeading === 'string'
11938
+ ? msg.thinkingResponse.thinkingHeading
11939
+ : "Completed in 0m:00s",
11827
11940
  } : undefined,
11828
11941
  }
11829
11942
  }))
@@ -12488,10 +12601,14 @@ const SmartBot = (props) => {
12488
12601
  message.isFormDisabled = index !== lastBotMessageIndex;
12489
12602
  message.messageIndex = index;
12490
12603
  let originalUtilityObject = message.utilityObject;
12604
+ let originalThinkingResponse = message.thinkingResponse;
12491
12605
  let newMessage = cloneDeep(message);
12492
12606
  if (originalUtilityObject) {
12493
12607
  newMessage.utilityObject = originalUtilityObject;
12494
12608
  }
12609
+ if (originalThinkingResponse) {
12610
+ newMessage.thinkingResponse = originalThinkingResponse;
12611
+ }
12495
12612
  message.jsx = (jsx(BotMessage, { botData: newMessage, state: loadingState, handleLikeDislike: handleLikeDislike, props: properties }));
12496
12613
  let actualProps = {
12497
12614
  botData: newMessage,
@@ -12506,6 +12623,15 @@ const SmartBot = (props) => {
12506
12623
  });
12507
12624
  // Create a deep clone and remove JSX properties to avoid circular references
12508
12625
  let newChat = cloneDeep(chatDataInfoRef?.current[currentMode]);
12626
+ // Restore thinkingResponse (may contain JSX components like ThinkinHeaderInfo)
12627
+ // which cloneDeep serializes into plain objects
12628
+ const originalMessages = chatDataInfoRef?.current[currentMode]?.conversations?.[activeConversationId]?.messages || [];
12629
+ const clonedMessages = newChat?.conversations?.[activeConversationId]?.messages || [];
12630
+ originalMessages.forEach((origMsg, idx) => {
12631
+ if (origMsg.thinkingResponse && clonedMessages[idx]) {
12632
+ clonedMessages[idx].thinkingResponse = origMsg.thinkingResponse;
12633
+ }
12634
+ });
12509
12635
  setConversation(newChat);
12510
12636
  }
12511
12637
  else if (showModal) {
@@ -12599,7 +12725,10 @@ const SmartBot = (props) => {
12599
12725
  // if(!isEmpty(userInput)) {
12600
12726
  dispatch(setThinkingContext({
12601
12727
  thinkingContent: "",
12602
- thinkingHeaderMessage: "Planning next moves.....",
12728
+ thinkingHeaderMessage: "Working for 0m:00s",
12729
+ streamStartTime: Date.now(),
12730
+ isStreamCompleted: false,
12731
+ finalElapsedSeconds: null,
12603
12732
  }));
12604
12733
  // }
12605
12734
  prepareDataAndSendToAgent(data, true, {
@@ -12814,7 +12943,10 @@ const SmartBot = (props) => {
12814
12943
  setShowChatPlaceholder(true);
12815
12944
  dispatch(setThinkingContext({
12816
12945
  thinkingContent: "",
12817
- thinkingHeaderMessage: "Planning next moves.....",
12946
+ thinkingHeaderMessage: "Working for 0m:00s",
12947
+ streamStartTime: null,
12948
+ isStreamCompleted: false,
12949
+ finalElapsedSeconds: null,
12818
12950
  }));
12819
12951
  setInitValue(true);
12820
12952
  setSessionId("");