impact-chatbot 2.3.64 → 2.3.66

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
@@ -315,7 +315,7 @@ const useBotConfiguration = (setRefreshLoader, setEnableRefreshAction, dispatch)
315
315
  */
316
316
  const parseResponse = (data, type, agentId = "", currentMode = "", disableTimeAndName = false, sessionId = "", utilityData = {}, inputBody = null, utilityObject = {}) => {
317
317
  const timeString = disableTimeAndName ? "" : moment().format("DD-MM-YYYY HH:mm:ss");
318
- const userName = disableTimeAndName ? "" : "Alan";
318
+ const userName = disableTimeAndName ? "" : "Iris";
319
319
  switch (type || data?.type) {
320
320
  case "text":
321
321
  return {
@@ -1392,7 +1392,7 @@ const useAgentFlow = (dateFormat, chatDataRef, currentMode, setShowChatPlacehold
1392
1392
  hasDirectActionType: false,
1393
1393
  };
1394
1394
  const loaderData = {
1395
- userName: "Alan",
1395
+ userName: "Iris",
1396
1396
  timeStamp: currentTimeString,
1397
1397
  userType: "loader",
1398
1398
  };
@@ -1958,7 +1958,7 @@ const useAgentFlow = (dateFormat, chatDataRef, currentMode, setShowChatPlacehold
1958
1958
  const failResponseText = {
1959
1959
  timeStamp: getCurrentDateTimeString(),
1960
1960
  userType: "bot",
1961
- userName: "Alan",
1961
+ userName: "Iris",
1962
1962
  bodyText: error?.response?.data?.data?.error?.response
1963
1963
  ? error?.response?.data?.data?.error?.response
1964
1964
  : "Sorry, chatbot is not available now",
@@ -2202,7 +2202,7 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2202
2202
  return {
2203
2203
  timeStamp: timeString,
2204
2204
  userType: "bot",
2205
- userName: "Alan",
2205
+ userName: "Iris",
2206
2206
  headerTitle: headerTitle,
2207
2207
  bodyType: "chips",
2208
2208
  bodyText: screens.map((screen) => ({
@@ -2256,7 +2256,7 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2256
2256
  flow_type: flowType,
2257
2257
  };
2258
2258
  const loaderData = {
2259
- userName: "Alan",
2259
+ userName: "Iris",
2260
2260
  timeStamp: currentTimeString,
2261
2261
  userType: "loader",
2262
2262
  };
@@ -2290,7 +2290,7 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2290
2290
  const failResponseText = {
2291
2291
  timeStamp: getCurrentDateTimeString(),
2292
2292
  userType: "bot",
2293
- userName: "Alan",
2293
+ userName: "Iris",
2294
2294
  bodyText: options.data.data.message,
2295
2295
  enableLikes: false,
2296
2296
  headerTitle: "",
@@ -2309,7 +2309,7 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2309
2309
  const failResponseText = {
2310
2310
  timeStamp: getCurrentDateTimeString(),
2311
2311
  userType: "bot",
2312
- userName: "Alan",
2312
+ userName: "Iris",
2313
2313
  bodyText: "Failed to fetch user screens. Please try again later.",
2314
2314
  headerTitle: "",
2315
2315
  enableLikes: false,
@@ -2381,7 +2381,7 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2381
2381
  hasDirectActionType: fetchQuestions,
2382
2382
  };
2383
2383
  const loaderData = {
2384
- userName: "Alan",
2384
+ userName: "Iris",
2385
2385
  timeStamp: currentTimeString,
2386
2386
  userType: "loader",
2387
2387
  };
@@ -2501,7 +2501,7 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2501
2501
  const failResponseText = {
2502
2502
  timeStamp: getCurrentDateTimeString(),
2503
2503
  userType: "bot",
2504
- userName: "Alan",
2504
+ userName: "Iris",
2505
2505
  bodyText: error?.response?.data?.data?.error?.response
2506
2506
  ? error?.response?.data?.data?.error?.response
2507
2507
  : "Sorry, chatbot is not available now",
@@ -2712,10 +2712,10 @@ const useChatSession = (chatDataRef, setFlowType, setScreenName, setUserInput, s
2712
2712
  {
2713
2713
  timeStamp: getCurrentDateTimeString(),
2714
2714
  userType: "bot",
2715
- userName: "Alan",
2715
+ userName: "Iris",
2716
2716
  headerTitle: `Hi ${getUserName()}!`,
2717
2717
  bodyType: "text",
2718
- bodyText: `I am Alan, your virtual assistant. I am here to help you on anything you are looking for in IA Smart Platform`,
2718
+ bodyText: `I am Iris, your virtual assistant. I am here to help you on anything you are looking for in IA Smart Platform`,
2719
2719
  },
2720
2720
  ];
2721
2721
  // chatDataRef.current[currentMode].conversations[
@@ -4881,7 +4881,7 @@ const ChatPlaceholder = (props) => {
4881
4881
  agentId: card.agentId || card.id
4882
4882
  }));
4883
4883
  const dataToMap = legacyAgentScreen || displayQuestions ? transformedCardList : rectangleData;
4884
- return (jsxs("div", { className: classes.placeholderContainer, children: [jsx("div", { className: classes.centerIconContainer, children: jsx(SvgCenter3D, { className: classes.centerIcon }) }), jsxs("div", { className: classes.headingContainer, children: [jsx(Typography, { variant: "h1", className: classes.heading, children: "Alan's Capabilities" }), jsx("span", { className: classes.alphaTag, children: "Beta" })] }), jsx(Typography, { variant: "body1", className: classes.headingHelperText, children: "Discover potential issues & opportunities Alan can help you with!" }), jsx("div", { className: classes.rectanglesContainer, children: dataToMap.map((item, index) => (jsx(Rectangle, { type: item.type, icon: item.icon, title: item.title, description: item.description, onClick: () => handleRectangleClick(item?.agentId, item?.title), hoverable: legacyAgentScreen || displayQuestions }, index))) })] }));
4884
+ return (jsxs("div", { className: classes.placeholderContainer, children: [jsx("div", { className: classes.centerIconContainer, children: jsx(SvgCenter3D, { className: classes.centerIcon }) }), jsxs("div", { className: classes.headingContainer, children: [jsx(Typography, { variant: "h1", className: classes.heading, children: "Iris's Capabilities" }), jsx("span", { className: classes.alphaTag, children: "Beta" })] }), jsx(Typography, { variant: "body1", className: classes.headingHelperText, children: "Discover potential issues & opportunities Iris can help you with!" }), jsx("div", { className: classes.rectanglesContainer, children: dataToMap.map((item, index) => (jsx(Rectangle, { type: item.type, icon: item.icon, title: item.title, description: item.description, onClick: () => handleRectangleClick(item?.agentId, item?.title), hoverable: legacyAgentScreen || displayQuestions }, index))) })] }));
4885
4885
  };
4886
4886
 
4887
4887
  const dateFormat = "DD-MM-YYYY HH:mm:ss";
@@ -7127,15 +7127,43 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
7127
7127
  const chatbotFilterOptions = useSelector((state) => state.smartBotReducer.chatbotFilterOptions);
7128
7128
  const dimensionHierarchies = useSelector((state) => state.userRoleManagementService?.dimensionHierarchies);
7129
7129
  const [isFormSubmitted, setIsFormSubmitted] = useState(false);
7130
+ const [isTimedOut, setIsTimedOut] = useState(false);
7131
+ const timeoutRef = useRef(null);
7132
+ // 30-minute inactivity timeout: disable form and switch to agent_response tab
7133
+ const FORM_TIMEOUT_MS = 30 * 60 * 1000;
7134
+ useEffect(() => {
7135
+ if (isFormDisabled || isFormSubmitted || isTimedOut)
7136
+ return;
7137
+ const startTime = Date.now();
7138
+ timeoutRef.current = setTimeout(() => {
7139
+ setIsTimedOut(true);
7140
+ const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
7141
+ window.dispatchEvent(new CustomEvent("stepFormTimeout", { detail: { elapsedSeconds } }));
7142
+ }, FORM_TIMEOUT_MS);
7143
+ return () => {
7144
+ if (timeoutRef.current) {
7145
+ clearTimeout(timeoutRef.current);
7146
+ timeoutRef.current = null;
7147
+ }
7148
+ };
7149
+ }, [isFormDisabled, isFormSubmitted, isTimedOut]);
7150
+ // Clear timeout when form is submitted
7151
+ useEffect(() => {
7152
+ if (isFormSubmitted && timeoutRef.current) {
7153
+ clearTimeout(timeoutRef.current);
7154
+ timeoutRef.current = null;
7155
+ }
7156
+ }, [isFormSubmitted]);
7130
7157
  useEffect(() => {
7131
7158
  if (stepFormStreamData?.status === "streaming_start") {
7132
7159
  setIsFormSubmitted(true);
7133
7160
  }
7134
7161
  }, [stepFormStreamData]);
7135
- // Reset isFormSubmitted when parent signals the form should be enabled (new step_form from restream)
7162
+ // Reset isFormSubmitted and isTimedOut when parent signals the form should be enabled (new step_form from restream)
7136
7163
  useEffect(() => {
7137
7164
  if (!isFormDisabled) {
7138
7165
  setIsFormSubmitted(false);
7166
+ setIsTimedOut(false);
7139
7167
  }
7140
7168
  }, [isFormDisabled]);
7141
7169
  const [isFilterSetOpen, setIsFilterSetOpen] = useState(false);
@@ -7206,8 +7234,8 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
7206
7234
  return val && (Array.isArray(val) ? val.length > 0 : !!val);
7207
7235
  });
7208
7236
  }, [persistedFormValues, messageIndex]);
7209
- const formFieldsDisabled = isFormDisabled || isFilterSelected || isFormSubmitted;
7210
- const savedFilterDisabled = isFormDisabled || isFormFieldUsed || isFormSubmitted;
7237
+ const formFieldsDisabled = isFormDisabled || isFilterSelected || isFormSubmitted || isTimedOut;
7238
+ const savedFilterDisabled = isFormDisabled || isFormFieldUsed || isFormSubmitted || isTimedOut;
7211
7239
  const requiredFieldsFilled = useMemo(() => {
7212
7240
  if (!formData || !Array.isArray(formData))
7213
7241
  return false;
@@ -7795,7 +7823,40 @@ const AgentResponse$1 = (props) => {
7795
7823
 
7796
7824
  const StepsResponseTab = (props) => {
7797
7825
  const { steps, setSteps, stepsDone, setStepsDone, finalStepDone, setFinalStepDone, content, isStreaming, stepChange, currentMode, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, streamingWidgetData, isRetrying, } = props;
7826
+ const dispatch = useDispatch();
7827
+ const thinkingContext = useSelector((state) => state.smartBotReducer.thinkingContext);
7828
+ const streamStartTimeRef = useRef(thinkingContext?.streamStartTime);
7829
+ // Keep streamStartTime ref in sync with Redux for use in event handler closures
7830
+ useEffect(() => {
7831
+ streamStartTimeRef.current = thinkingContext?.streamStartTime;
7832
+ }, [thinkingContext?.streamStartTime]);
7798
7833
  const [tabValue, setTabValue] = useState("steps");
7834
+ const [timeoutMessage, setTimeoutMessage] = useState("");
7835
+ // Switch to agent_response tab on form inactivity timeout (30 min)
7836
+ useEffect(() => {
7837
+ const handleStepFormTimeout = () => {
7838
+ setTimeoutMessage("This session timed out due to inactivity. Please start a new message to continue.");
7839
+ setTabValue("agent_response");
7840
+ dispatch(setMinimizedStreamData(null));
7841
+ const elapsed = streamStartTimeRef.current
7842
+ ? Math.floor((Date.now() - streamStartTimeRef.current) / 1000)
7843
+ : null;
7844
+ const mins = elapsed != null ? Math.floor(elapsed / 60) : 0;
7845
+ const secs = elapsed != null ? elapsed % 60 : 0;
7846
+ const timedOutLabel = `Worked for ${mins}m:${String(secs).padStart(2, '0')}s`;
7847
+ dispatch(setThinkingContext({
7848
+ streamStartTime: null,
7849
+ isStreamCompleted: true,
7850
+ finalElapsedSeconds: elapsed,
7851
+ thinkingHeaderMessage: timedOutLabel,
7852
+ thinkingContent: "",
7853
+ }));
7854
+ };
7855
+ window.addEventListener("stepFormTimeout", handleStepFormTimeout);
7856
+ return () => {
7857
+ window.removeEventListener("stepFormTimeout", handleStepFormTimeout);
7858
+ };
7859
+ }, []);
7799
7860
  // When retry countdown starts, switch to agent_response to show it.
7800
7861
  // When retry actually fires (isRetrying goes false + isStreaming goes true), switch back to steps.
7801
7862
  useEffect(() => {
@@ -7824,7 +7885,7 @@ const StepsResponseTab = (props) => {
7824
7885
  },
7825
7886
  ], tabPanels: [
7826
7887
  jsx(Steps$1, { steps: steps, setSteps: setSteps, done: stepsDone, setDone: setStepsDone, setTabValue: setTabValue, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, stepChange: stepChange, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: isFormDisabled }),
7827
- jsx(AgentResponse$1, { content: content, isStreaming: isStreaming, streamingWidgetData: streamingWidgetData }),
7888
+ jsxs(Fragment, { children: [jsx(AgentResponse$1, { content: content, isStreaming: isStreaming, streamingWidgetData: streamingWidgetData }), timeoutMessage && (jsx("div", { style: { marginTop: "8px", padding: "0 8px" }, children: jsx(TextRenderer, { text: timeoutMessage, thinking: "" }) }))] }),
7828
7889
  ], value: tabValue }) }));
7829
7890
  };
7830
7891
 
@@ -8652,6 +8713,7 @@ const StreamedContent = ({ botData }) => {
8652
8713
  // Check if this is a user-initiated abort (should not trigger retry)
8653
8714
  const isUserAbort = event.reason === "Network request aborted";
8654
8715
  event.statusCode === 503;
8716
+ const isAgentUnavailable = event.statusCode === 502 || event.statusCode === 404;
8655
8717
  if (isThinking) {
8656
8718
  setIsThinking(false);
8657
8719
  const endTime = Date.now();
@@ -8662,8 +8724,50 @@ const StreamedContent = ({ botData }) => {
8662
8724
  thinkingStartTimeRef.current = finalThinkingTime;
8663
8725
  messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
8664
8726
  }
8727
+ // Agent unavailable (502/404) — show specific message, no retry
8728
+ if (isAgentUnavailable) {
8729
+ setWasStreamingAborted(true);
8730
+ wasStreamingAbortedRef.current = true;
8731
+ const currentSteps = stepRef.current;
8732
+ if (currentSteps.length > 0) {
8733
+ const lastStep = currentSteps[currentSteps.length - 1];
8734
+ if (lastStep.step_status === "not-completed") {
8735
+ lastStep.step_status = "completed";
8736
+ }
8737
+ stepRef.current = [...currentSteps];
8738
+ setSteps([...currentSteps]);
8739
+ }
8740
+ const agentUnavailableMessage = "Agent isn't available right now. Please contact your administrator or try again later.";
8741
+ const hasExistingWidgetsOnUnavail = messageToStoreRef.current.appendedData &&
8742
+ (isArray(messageToStoreRef.current.appendedData)
8743
+ ? messageToStoreRef.current.appendedData.length > 0
8744
+ : Object.keys(messageToStoreRef.current.appendedData).length > 0);
8745
+ if (hasExistingWidgetsOnUnavail) {
8746
+ const errorWidget = { type: "text", response: agentUnavailableMessage };
8747
+ if (isArray(messageToStoreRef.current.appendedData)) {
8748
+ messageToStoreRef.current.appendedData.push(errorWidget);
8749
+ }
8750
+ else {
8751
+ messageToStoreRef.current.appendedData = [messageToStoreRef.current.appendedData, errorWidget];
8752
+ }
8753
+ }
8754
+ else {
8755
+ messageToStoreRef.current.chatData.response = agentUnavailableMessage;
8756
+ }
8757
+ setContent(agentUnavailableMessage);
8758
+ dispatch(setMinimizedStreamData({
8759
+ isStreaming: false,
8760
+ stepHeader: questionsRef.current[questionsRef.current.length - 1] || "Agent unavailable",
8761
+ stepSubHeader: "Connection closed",
8762
+ stepStatus: "completed",
8763
+ streamStartTime: streamStartTimeRef.current,
8764
+ actionCount: questionsRef.current.length || 1,
8765
+ }));
8766
+ setStepsDone(true);
8767
+ setIsStreamingDone(true);
8768
+ }
8665
8769
  // Check if we can auto-retry (abrupt close or 503, but not user abort)
8666
- if (!isUserAbort && retryCountRef.current < MAX_RETRY_COUNT) {
8770
+ else if (!isUserAbort && retryCountRef.current < MAX_RETRY_COUNT) {
8667
8771
  // Still have retries left — start countdown instead of showing final error
8668
8772
  setStepsDone(true); // Switch to agent_response tab to show countdown
8669
8773
  const retryMessage = "The service is temporarily unavailable because of an unusual load. Please wait a moment and try again.";
@@ -8683,8 +8787,26 @@ const StreamedContent = ({ botData }) => {
8683
8787
  stepRef.current = [...currentSteps];
8684
8788
  setSteps([...currentSteps]);
8685
8789
  }
8686
- const finalMessage = "Please reach out to IA for this, as this didn't work even after retry";
8687
- messageToStoreRef.current.chatData.response = finalMessage;
8790
+ // Append the error message at the bottom of any existing content.
8791
+ // If widgets already exist in appendedData, append as the last widget
8792
+ // so it renders AFTER the already-received content (not at the top).
8793
+ const finalMessage = "The service is temporarily unavailable because of an unusual load. Please wait a moment and try again.";
8794
+ const hasExistingWidgetsOnErr = messageToStoreRef.current.appendedData &&
8795
+ (isArray(messageToStoreRef.current.appendedData)
8796
+ ? messageToStoreRef.current.appendedData.length > 0
8797
+ : Object.keys(messageToStoreRef.current.appendedData).length > 0);
8798
+ if (hasExistingWidgetsOnErr) {
8799
+ const errorWidget = { type: "text", response: finalMessage };
8800
+ if (isArray(messageToStoreRef.current.appendedData)) {
8801
+ messageToStoreRef.current.appendedData.push(errorWidget);
8802
+ }
8803
+ else {
8804
+ messageToStoreRef.current.appendedData = [messageToStoreRef.current.appendedData, errorWidget];
8805
+ }
8806
+ }
8807
+ else {
8808
+ messageToStoreRef.current.chatData.response = finalMessage;
8809
+ }
8688
8810
  setContent(finalMessage);
8689
8811
  dispatch(setMinimizedStreamData({
8690
8812
  isStreaming: false,
@@ -8726,9 +8848,10 @@ const StreamedContent = ({ botData }) => {
8726
8848
  startRetryCountdown();
8727
8849
  }
8728
8850
  else {
8729
- // Retries exhausted — show final elegant message
8851
+ // Retries exhausted — show final message
8730
8852
  setWasStreamingAborted(true);
8731
8853
  wasStreamingAbortedRef.current = true;
8854
+ // Mark the last in-progress step as completed
8732
8855
  const currentSteps = stepRef.current;
8733
8856
  if (currentSteps.length > 0) {
8734
8857
  const lastStep = currentSteps[currentSteps.length - 1];
@@ -8738,8 +8861,26 @@ const StreamedContent = ({ botData }) => {
8738
8861
  stepRef.current = [...currentSteps];
8739
8862
  setSteps([...currentSteps]);
8740
8863
  }
8741
- const finalMessage = "Please reach out to IA for this, as this didn't work even after retry";
8742
- messageToStoreRef.current.chatData.response = finalMessage;
8864
+ // Append the error message at the bottom of any existing content.
8865
+ // If widgets already exist in appendedData, append as the last widget
8866
+ // so it renders AFTER the already-received content (not at the top).
8867
+ const finalMessage = "The service is temporarily unavailable because of an unusual load. Please wait a moment and try again.";
8868
+ const hasExistingWidgets = messageToStoreRef.current.appendedData &&
8869
+ (isArray(messageToStoreRef.current.appendedData)
8870
+ ? messageToStoreRef.current.appendedData.length > 0
8871
+ : Object.keys(messageToStoreRef.current.appendedData).length > 0);
8872
+ if (hasExistingWidgets) {
8873
+ const errorWidget = { type: "text", response: finalMessage };
8874
+ if (isArray(messageToStoreRef.current.appendedData)) {
8875
+ messageToStoreRef.current.appendedData.push(errorWidget);
8876
+ }
8877
+ else {
8878
+ messageToStoreRef.current.appendedData = [messageToStoreRef.current.appendedData, errorWidget];
8879
+ }
8880
+ }
8881
+ else {
8882
+ messageToStoreRef.current.chatData.response = finalMessage;
8883
+ }
8743
8884
  setContent(finalMessage);
8744
8885
  dispatch(setMinimizedStreamData({
8745
8886
  isStreaming: false,
@@ -8944,19 +9085,19 @@ const StreamedContent = ({ botData }) => {
8944
9085
  // [
8945
9086
  // {
8946
9087
  // header: "Finding relevant information",
8947
- // sub_header: "Alan is working to identify relevant information to user answer user query",
9088
+ // sub_header: "Iris is working to identify relevant information to user answer user query",
8948
9089
  // step_status: "not-completed",
8949
9090
  // },
8950
9091
  // ];
8951
9092
  // [
8952
9093
  // {
8953
9094
  // header: "Finding relevant information",
8954
- // sub_header: "Alan is working to identify relevant information to user answer user query",
9095
+ // sub_header: "Iris is working to identify relevant information to user answer user query",
8955
9096
  // step_status: "completed",
8956
9097
  // },
8957
9098
  // {
8958
9099
  // header: "Output Generation",
8959
- // sub_header: "Alan is finalizing response to user query",
9100
+ // sub_header: "Iris is finalizing response to user query",
8960
9101
  // step_status: "not-completed",
8961
9102
  // },
8962
9103
  // ];
@@ -9196,7 +9337,7 @@ const StreamedContent = ({ botData }) => {
9196
9337
  * @returns {JSX.Element} Rendered content with optional blinking cursor
9197
9338
  */
9198
9339
  const renderContent = () => {
9199
- return (jsxs("div", { className: classes.streamContainer, children: [jsx(StepsResponseTab, { steps: steps, stepChange: stepChange, setSteps: setSteps, stepsDone: stepsDone, setStepsDone: setStepsDone, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, content: content, isStreaming: isStreaming, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: botData?.isFormDisabled || false, streamingWidgetData: streamingWidgetData, isRetrying: isRetrying }), isRetrying && (jsx("div", { className: classes.retryContainer, children: jsxs("span", { className: classes.retryMessage, children: ["Auto re-trying in ", retryCountdown, "s"] }) }))] }));
9340
+ return (jsxs("div", { className: classes.streamContainer, children: [jsx(StepsResponseTab, { steps: steps, stepChange: stepChange, setSteps: setSteps, stepsDone: stepsDone, setStepsDone: setStepsDone, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, content: content, isStreaming: isStreaming, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: botData?.isFormDisabled || false, streamingWidgetData: streamingWidgetData, isRetrying: isRetrying }), isRetrying && (jsx("div", { className: classes.retryContainer, children: jsx(TextRenderer, { text: `Auto re-trying in ${retryCountdown}s`, thinking: "" }) }))] }));
9200
9341
  };
9201
9342
  if (currentMode === "agent") {
9202
9343
  return renderContent();
@@ -9467,6 +9608,12 @@ let activeTabularInstanceId = null;
9467
9608
  const TabularContent = ({ steps: initialSteps, currentTabValue, children, questions: initialQuestions = [], questionsStepsMap: initialQuestionsStepsMap = {}, stepFormDataMap: initialStepFormDataMap = {}, isFormDisabled = false, sessionId: propSessionId = "" }) => {
9468
9609
  const dispatch = useDispatch();
9469
9610
  const stepFormStreamData = useSelector((state) => state.smartBotReducer.stepFormStreamData);
9611
+ const thinkingContext = useSelector((state) => state.smartBotReducer.thinkingContext);
9612
+ const streamStartTimeRef = useRef(thinkingContext?.streamStartTime);
9613
+ // Keep streamStartTime ref in sync with Redux for use in event handler closures
9614
+ useEffect(() => {
9615
+ streamStartTimeRef.current = thinkingContext?.streamStartTime;
9616
+ }, [thinkingContext?.streamStartTime]);
9470
9617
  const [tabValue, setTabValue] = useState(currentTabValue);
9471
9618
  // Local state — initialized from props, updated by SSE chunks
9472
9619
  const [stepsState, setStepsState] = useState(() => {
@@ -9489,6 +9636,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
9489
9636
  const [hasNewStepFormFromRestream, setHasNewStepFormFromRestream] = useState(false);
9490
9637
  const [activeFormIntent, setActiveFormIntent] = useState(null);
9491
9638
  const [retryCountdown, setRetryCountdown] = useState(0);
9639
+ const [timeoutMessage, setTimeoutMessage] = useState("");
9492
9640
  // Stable unique instance ID for this TabularContent mount
9493
9641
  const instanceIdRef = useRef(null);
9494
9642
  if (instanceIdRef.current === null) {
@@ -9513,6 +9661,32 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
9513
9661
  window.removeEventListener("stepFormStreamCompleted", handleStepFormCompleted);
9514
9662
  };
9515
9663
  }, []);
9664
+ // Switch to agent_response tab on form inactivity timeout (30 min)
9665
+ useEffect(() => {
9666
+ const handleStepFormTimeout = () => {
9667
+ setTimeoutMessage("This session timed out due to inactivity. Please start a new message to continue.");
9668
+ setStepFormSubmitted(true);
9669
+ setTabValue("agent_response");
9670
+ dispatch(setMinimizedStreamData(null));
9671
+ const elapsed = streamStartTimeRef.current
9672
+ ? Math.floor((Date.now() - streamStartTimeRef.current) / 1000)
9673
+ : null;
9674
+ const mins = elapsed != null ? Math.floor(elapsed / 60) : 0;
9675
+ const secs = elapsed != null ? elapsed % 60 : 0;
9676
+ const timedOutLabel = `Worked for ${mins}m:${String(secs).padStart(2, '0')}s`;
9677
+ dispatch(setThinkingContext({
9678
+ streamStartTime: null,
9679
+ isStreamCompleted: true,
9680
+ finalElapsedSeconds: elapsed,
9681
+ thinkingHeaderMessage: timedOutLabel,
9682
+ thinkingContent: "",
9683
+ }));
9684
+ };
9685
+ window.addEventListener("stepFormTimeout", handleStepFormTimeout);
9686
+ return () => {
9687
+ window.removeEventListener("stepFormTimeout", handleStepFormTimeout);
9688
+ };
9689
+ }, []);
9516
9690
  // Render a widget item from SSE data
9517
9691
  const renderWidget = (item, index) => {
9518
9692
  try {
@@ -9852,7 +10026,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
9852
10026
  },
9853
10027
  ], tabPanels: [
9854
10028
  jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: (isFormDisabled && !isRestreaming) || stepFormSubmitted, activeFormIntent: hasNewStepFormFromRestream ? activeFormIntent : null, isRestreaming: isRestreaming }),
9855
- jsxs(AgentResponse, { children: [children, renderedWidgets.length > 0 && (jsx("div", { className: "restream-widget-content", children: renderedWidgets })), retryCountdown > 0 && (jsx("div", { style: { marginTop: "8px" }, children: jsxs("span", { style: { fontFamily: "Manrope", fontSize: "13px", fontWeight: 500, color: "#374151" }, children: ["Auto re-trying in ", retryCountdown, "s"] }) }))] }),
10029
+ jsxs(AgentResponse, { children: [children, renderedWidgets.length > 0 && (jsx("div", { className: "restream-widget-content", children: renderedWidgets })), retryCountdown > 0 && (jsx("div", { style: { marginTop: "8px" }, children: jsx(TextRenderer, { text: `Auto re-trying in ${retryCountdown}s`, thinking: "" }) })), timeoutMessage && (jsx("div", { style: { marginTop: "8px" }, children: jsx(TextRenderer, { text: timeoutMessage, thinking: "" }) }))] }),
9856
10030
  ], value: tabValue }) }));
9857
10031
  };
9858
10032
  /** Reset the active instance tracker (call when a new conversation starts from the input field) */
@@ -12902,7 +13076,7 @@ let singleConversationNewData = [
12902
13076
  {
12903
13077
  header: "Creating Plan of Action",
12904
13078
  step_status: "completed",
12905
- sub_header: "Alan is working to determine the best approach to answer user query",
13079
+ sub_header: "Iris is working to determine the best approach to answer user query",
12906
13080
  current_intent: "List the products which are about to change status in next 10 days"
12907
13081
  },
12908
13082
  {
@@ -14826,7 +15000,7 @@ const SmartBot = (props) => {
14826
15000
  try {
14827
15001
  // if (localStorage.getItem("isStreaming") === "true") {
14828
15002
  // displaySnackMessages(
14829
- // "Alan is processing request in another tab, This request can be processed once Alan is available",
15003
+ // "Iris is processing request in another tab, This request can be processed once Iris is available",
14830
15004
  // "warning"
14831
15005
  // );
14832
15006
  // return;
@@ -15168,7 +15342,7 @@ const SmartBot = (props) => {
15168
15342
  :
15169
15343
  jsx(ChatbotSaveFilterComponent$1, { savedFilterSets: savedFilterSets, partialClose: partialClose, chatBotWidth: chatBotWidth }), inputText: userInput, threadList: ["Home"], hideMenuArrow: hideMenu, newChatScreen: newChatScreen, isModuleListLoading: modulesLoading, suggestionBanner: {
15170
15344
  freeTextHeading: "Try adding more details :",
15171
- freeTextContent: "Alan works better when you provide more context and pointed questions",
15345
+ freeTextContent: "Iris works better when you provide more context and pointed questions",
15172
15346
  }, isStopIcon: isStop, onStopIconClick: onStopIconClick, footerText: "AI-generated responses may contain errors\u2014please verify important information", showSuggestionBanner: showSavedFilters ? false : showSuggestionBanner, onCloseSuggestionBanner: () => {
15173
15347
  setShowSuggestionBanner(false);
15174
15348
  }, landingScreen: isLandingScreen, onLikeClick: (params, params2) => {