impact-chatbot 2.3.38 → 2.3.40

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.
@@ -1,3 +1,11 @@
1
+ export declare const stepFormStreamControl: {
2
+ isStreaming: boolean;
3
+ abort: any;
4
+ sessionId: string;
5
+ chatId: string;
6
+ agentId: string;
7
+ baseUrl: string;
8
+ };
1
9
  declare const ButtonContent: ({ bodyText, isFormDisabled, isStepFormSubmit, isFormValid }: {
2
10
  bodyText: any;
3
11
  isFormDisabled?: boolean;
@@ -7,9 +7,10 @@
7
7
  * @param {Array} props.formData - Array of raw widget_data items from step_form chunk
8
8
  * @param {number} props.messageIndex - Index for form state persistence keys
9
9
  */
10
- declare const StepFormContent: ({ formData, messageIndex, isFormDisabled }: {
10
+ declare const StepFormContent: ({ formData, messageIndex, isFormDisabled, showSavedFilters }: {
11
11
  formData: any;
12
12
  messageIndex?: number;
13
13
  isFormDisabled?: boolean;
14
+ showSavedFilters?: boolean;
14
15
  }) => import("react/jsx-runtime").JSX.Element;
15
16
  export default StepFormContent;
@@ -1,9 +1,10 @@
1
- declare const Steps: ({ steps, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, isRestreaming }: {
1
+ declare const Steps: ({ steps, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, activeFormIntent, isRestreaming }: {
2
2
  steps: any;
3
3
  questions?: any[];
4
4
  questionsStepsMap?: {};
5
5
  stepFormDataMap?: {};
6
6
  isFormDisabled?: boolean;
7
+ activeFormIntent?: any;
7
8
  isRestreaming?: boolean;
8
9
  }) => import("react/jsx-runtime").JSX.Element;
9
10
  export default Steps;
package/dist/index.cjs.js CHANGED
@@ -29,6 +29,7 @@ var material = require('@mui/material');
29
29
  var utils = require('core/Utils/functions/utils');
30
30
  var impactUiV3 = require('impact-ui-v3');
31
31
  var isArray$1 = require('lodash/isArray');
32
+ var chatbotServices = require('core/commonComponents/smartBot/services/chatbot-services');
32
33
  var AgGridComponent = require('core/Utils/agGrid');
33
34
  var agGridColumnFormatter = require('core/Utils/agGrid/column-formatter');
34
35
  var CoreChart = require('core/Utils/core-charts');
@@ -36,7 +37,6 @@ var makeStyles = require('@mui/styles/makeStyles');
36
37
  var ChevronRightIcon$1 = require('@mui/icons-material/ChevronRight');
37
38
  var FormatListBulletedOutlinedIcon = require('@mui/icons-material/FormatListBulletedOutlined');
38
39
  var PsychologyOutlinedIcon = require('@mui/icons-material/PsychologyOutlined');
39
- var chatbotServices = require('core/commonComponents/smartBot/services/chatbot-services');
40
40
  var SaveOutlinedIcon = require('@mui/icons-material/SaveOutlined');
41
41
  var RangePicker = require('core/commonComponents/dateRangePicker');
42
42
  var NoFilterSetSavedIcon = require('core/coreAssets/chatbot/noFilterSetSaved.svg');
@@ -5285,6 +5285,17 @@ const AxiosSource = (url, opts, messageToStoreRef) => {
5285
5285
  }
5286
5286
  };
5287
5287
 
5288
+ // Module-level control object for step-form SSE stream.
5289
+ // StreamedContent imports this to show/hide the stop icon during the second init stream.
5290
+ const stepFormStreamControl = {
5291
+ isStreaming: false,
5292
+ abort: null,
5293
+ // Session info — set by StreamedContent when step_form arrives
5294
+ sessionId: "",
5295
+ chatId: "",
5296
+ agentId: "",
5297
+ baseUrl: "",
5298
+ };
5288
5299
  const useStyles$5 = styles.makeStyles((theme) => ({
5289
5300
  buttonContainer: {
5290
5301
  display: 'flex',
@@ -5345,11 +5356,11 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5345
5356
  sendButton.click();
5346
5357
  };
5347
5358
  const callInitApiStream = (userInput) => {
5348
- // Get session/chat IDs from localStorage — set by StreamedContent on stream completion
5349
- const sessionId = localStorage.getItem("stepForm_sessionId") || "";
5350
- const chatId = localStorage.getItem("stepForm_chatId") || "";
5351
- const agentId = localStorage.getItem("stepForm_agentId") || "";
5352
- const baseUrl = localStorage.getItem("stepForm_baseUrl") || "";
5359
+ // Prefer module-level values (set synchronously by StreamedContent), fall back to sessionStorage
5360
+ const sessionId = stepFormStreamControl.sessionId || sessionStorage.getItem("stepForm_sessionId") || "";
5361
+ const chatId = stepFormStreamControl.chatId || sessionStorage.getItem("stepForm_chatId") || "";
5362
+ const agentId = stepFormStreamControl.agentId || sessionStorage.getItem("stepForm_agentId") || "";
5363
+ const baseUrl = stepFormStreamControl.baseUrl || sessionStorage.getItem("stepForm_baseUrl") || "";
5353
5364
  const payload = {
5354
5365
  agent_id: agentId,
5355
5366
  session_id: sessionId,
@@ -5363,8 +5374,25 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5363
5374
  : `${api.BASE_API}/core/chatbot/agent/init`;
5364
5375
  // Collect all chunks, dispatch once when stream ends
5365
5376
  const chunksRef = [];
5366
- // Signal that streaming has started
5377
+ // Expose stream control BEFORE Redux dispatch so SmartBot index.jsx can show stop icon
5378
+ stepFormStreamControl.isStreaming = true;
5379
+ stepFormStreamControl.abort = () => {
5380
+ if (sourceRef.current) {
5381
+ sourceRef.current.close();
5382
+ sourceRef.current = null;
5383
+ }
5384
+ stepFormStreamControl.isStreaming = false;
5385
+ stepFormStreamControl.abort = null;
5386
+ // Stop the agent flow on the backend (same as StreamedContent.abortStreaming)
5387
+ if (sessionId) {
5388
+ chatbotServices.stopAgentFlow({ session_id: sessionId }, baseUrl);
5389
+ }
5390
+ dispatch(smartBotActions.setStepFormStreamData({ status: "error", chunks: [...chunksRef] }));
5391
+ };
5392
+ // Signal that streaming has started (after setting stepFormStreamControl so useEffect sees the flag)
5367
5393
  dispatch(smartBotActions.setStepFormStreamData({ status: "streaming_start", chunks: [] }));
5394
+ // Fire DOM event so SmartBot can show stop icon (Redux gets cleared by TabularContent before parent effects run)
5395
+ window.dispatchEvent(new CustomEvent("stepFormStreamStart"));
5368
5396
  sourceRef.current = AxiosSource(endPoint, {
5369
5397
  method: "POST",
5370
5398
  headers: {
@@ -5384,11 +5412,21 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5384
5412
  chunksRef.push(data);
5385
5413
  // If this chunk also carries [DONE], dispatch collected chunks now
5386
5414
  if (data?.message === "[DONE]") {
5415
+ stepFormStreamControl.isStreaming = false;
5416
+ stepFormStreamControl.abort = null;
5417
+ window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5387
5418
  dispatch(smartBotActions.setStepFormStreamData({ status: "done", chunks: [...chunksRef] }));
5388
5419
  }
5389
5420
  }
5390
5421
  else if (data?.status === "completed" || data?.message === "[DONE]") {
5391
5422
  // Stream ended — dispatch all collected chunks at once
5423
+ stepFormStreamControl.isStreaming = false;
5424
+ stepFormStreamControl.abort = null;
5425
+ window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5426
+ // Signal tab switch to agent_response when status is "completed"
5427
+ if (data?.status === "completed") {
5428
+ window.dispatchEvent(new CustomEvent("stepFormStreamCompleted"));
5429
+ }
5392
5430
  dispatch(smartBotActions.setStepFormStreamData({ status: "done", chunks: [...chunksRef] }));
5393
5431
  }
5394
5432
  else if (data?.message) {
@@ -5401,6 +5439,9 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5401
5439
  });
5402
5440
  sourceRef.current.addEventListener("error", () => {
5403
5441
  // On error, still dispatch whatever we collected
5442
+ stepFormStreamControl.isStreaming = false;
5443
+ stepFormStreamControl.abort = null;
5444
+ window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5404
5445
  dispatch(smartBotActions.setStepFormStreamData({ status: "error", chunks: chunksRef }));
5405
5446
  });
5406
5447
  };
@@ -5454,7 +5495,7 @@ const TableContent = ({ bodyText }) => {
5454
5495
  }, [row_data]);
5455
5496
  const serverSideManualCallBack = async (manualbody, pageIndex, params) => {
5456
5497
  try {
5457
- const baseUrl = localStorage.getItem("stepForm_baseUrl") || "";
5498
+ const baseUrl = sessionStorage.getItem("stepForm_baseUrl") || "";
5458
5499
  const response = await getTableRecords(baseUrl, table_name, pageIndex + 1, page_size);
5459
5500
  return {
5460
5501
  data: response?.data?.data || [],
@@ -6012,7 +6053,7 @@ const ImageContent = ({ bodyText }) => {
6012
6053
  * @param {Array} props.formData - Array of raw widget_data items from step_form chunk
6013
6054
  * @param {number} props.messageIndex - Index for form state persistence keys
6014
6055
  */
6015
- const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false }) => {
6056
+ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true }) => {
6016
6057
  const dispatch = reactRedux.useDispatch();
6017
6058
  const savedFilterSets = reactRedux.useSelector((state) => state.smartBotReducer.savedFilterSets);
6018
6059
  const persistedFormValues = reactRedux.useSelector((state) => state.smartBotReducer.persistedFormValues);
@@ -6183,7 +6224,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false })
6183
6224
  });
6184
6225
  if (formFields.length === 0 && buttonItems.length === 0)
6185
6226
  return null;
6186
- return (jsxRuntime.jsxs("div", { className: "step-form-content", children: [filterSetOptions.length > 0 && (jsxRuntime.jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsxRuntime.jsx(impactUiV3.Select, { currentOptions: filterSetCurrentOptions, setCurrentOptions: setFilterSetCurrentOptions, label: "Saved Filter Sets", labelOrientation: "top", isRequired: false, isDisabled: savedFilterDisabled, handleChange: (selected) => onFilterSetChange(selected), isCloseWhenClickOutside: true, setIsOpen: setIsFilterSetOpen, isOpen: isFilterSetOpen, selectedOptions: selectedFilterSet, setSelectedOptions: setSelectedFilterSet, initialOptions: filterSetOptions, isMulti: false, isClearable: true }) })), filterSetOptions.length > 0 && (jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #E0E0E0", margin: "12px 0" } })), jsxRuntime.jsx("div", { style: {
6227
+ return (jsxRuntime.jsxs("div", { className: "step-form-content", children: [showSavedFilters && filterSetOptions.length > 0 && (jsxRuntime.jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsxRuntime.jsx(impactUiV3.Select, { currentOptions: filterSetCurrentOptions, setCurrentOptions: setFilterSetCurrentOptions, label: "Saved Filter Sets", labelOrientation: "top", isRequired: false, isDisabled: savedFilterDisabled, handleChange: (selected) => onFilterSetChange(selected), isCloseWhenClickOutside: true, setIsOpen: setIsFilterSetOpen, isOpen: isFilterSetOpen, selectedOptions: selectedFilterSet, setSelectedOptions: setSelectedFilterSet, initialOptions: filterSetOptions, isMulti: false, isClearable: true }) })), showSavedFilters && filterSetOptions.length > 0 && (jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #E0E0E0", margin: "12px 0" } })), jsxRuntime.jsx("div", { style: {
6187
6228
  ...(isFilterSelected && !isFormDisabled ? { pointerEvents: "none", opacity: 0.5 } : {}),
6188
6229
  }, children: formFields }), buttonItems] }));
6189
6230
  };
@@ -6256,8 +6297,8 @@ const useStyles$3 = makeStyles((theme) => ({
6256
6297
  "&.completed": {
6257
6298
  width: pxToRem(10),
6258
6299
  height: pxToRem(10),
6259
- background: colours.greyscale250,
6260
- border: `${pxToRem(3)} solid ${colours.greyscale150}`,
6300
+ background: "#4CAF50",
6301
+ border: `${pxToRem(3)} solid #C8E6C9`,
6261
6302
  boxSizing: "content-box",
6262
6303
  },
6263
6304
  "&.in-progress": {
@@ -6405,9 +6446,11 @@ const getQuestionStatus$1 = (questionSteps) => {
6405
6446
  /**
6406
6447
  * Renders a single progress bar item (main point + sub-items)
6407
6448
  */
6408
- const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, isFormDisabled }) => {
6409
- const status = getQuestionStatus$1(questionSteps);
6410
- const [isExpanded, setIsExpanded] = React.useState(status === "in-progress" || status === "error");
6449
+ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, isFormDisabled, isRestreaming = false }) => {
6450
+ const baseStatus = getQuestionStatus$1(questionSteps);
6451
+ // When restreaming and this is the last item, show as in-progress
6452
+ const status = (isRestreaming && isLast) ? "in-progress" : baseStatus;
6453
+ const [isExpanded, setIsExpanded] = React.useState(true);
6411
6454
  const dotClass = status === "completed"
6412
6455
  ? "completed"
6413
6456
  : status === "in-progress"
@@ -6431,11 +6474,8 @@ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData,
6431
6474
  if (status === "in-progress" || status === "error" || formData) {
6432
6475
  setIsExpanded(true);
6433
6476
  }
6434
- else if (status === "completed" && !formData) {
6435
- setIsExpanded(false);
6436
- }
6437
6477
  }, [status, formData]);
6438
- return (jsxRuntime.jsxs("div", { className: classes.progressItem, children: [jsxRuntime.jsxs("div", { className: classes.progressTrack, children: [jsxRuntime.jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsxRuntime.jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxRuntime.jsxs("div", { className: classes.progressContent, children: [jsxRuntime.jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsxRuntime.jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsxRuntime.jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxRuntime.jsxs("div", { className: classes.reasoningLabel, children: [jsxRuntime.jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsxRuntime.jsx("div", { className: classes.progressSubItems, style: { opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxRuntime.jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsxRuntime.jsx("div", { className: classes.stepFormContainer, children: jsxRuntime.jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled }) }))] })] }));
6478
+ return (jsxRuntime.jsxs("div", { className: classes.progressItem, children: [jsxRuntime.jsxs("div", { className: classes.progressTrack, children: [jsxRuntime.jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsxRuntime.jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxRuntime.jsxs("div", { className: classes.progressContent, children: [jsxRuntime.jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsxRuntime.jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsxRuntime.jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxRuntime.jsxs("div", { className: classes.reasoningLabel, children: [jsxRuntime.jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsxRuntime.jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxRuntime.jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsxRuntime.jsx("div", { className: classes.stepFormContainer, children: jsxRuntime.jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }) }))] })] }));
6439
6479
  };
6440
6480
  const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, }) => {
6441
6481
  const classes = useStyles$3();
@@ -6485,7 +6525,7 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
6485
6525
  step_status: "not-completed",
6486
6526
  },
6487
6527
  ];
6488
- return (jsxRuntime.jsx("div", { className: classes.progressBarContainer, children: jsxRuntime.jsx(ProgressBarItem$1, { question: fallbackQuestion, questionSteps: fallbackSteps, isLast: true, classes: classes, formData: null, isFormDisabled: isFormDisabled }) }));
6528
+ return (jsxRuntime.jsx("div", { className: classes.progressBarContainer, children: jsxRuntime.jsx(ProgressBarItem$1, { question: fallbackQuestion, questionSteps: fallbackSteps, isLast: true, classes: classes, formData: null, isFormDisabled: isFormDisabled, showSavedFilters: true }) }));
6489
6529
  }
6490
6530
  return (jsxRuntime.jsx("div", { className: classes.progressBarContainer, children: questions.map((question, index) => {
6491
6531
  const questionData = questionsStepsMap[question];
@@ -6496,8 +6536,10 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
6496
6536
  step_status: "not-completed",
6497
6537
  },
6498
6538
  ];
6499
- const formData = stepFormDataMap[question] || null;
6500
- return (jsxRuntime.jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: isFormDisabled }, index));
6539
+ const formEntry = stepFormDataMap[question] || null;
6540
+ const formData = formEntry ? (Array.isArray(formEntry) ? formEntry : formEntry.widgets) : null;
6541
+ const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
6542
+ return (jsxRuntime.jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }, index));
6501
6543
  }) }));
6502
6544
  };
6503
6545
 
@@ -6751,6 +6793,7 @@ const StreamedContent = ({ botData }) => {
6751
6793
  session_id: data?.session_id || "",
6752
6794
  },
6753
6795
  }));
6796
+ return;
6754
6797
  }
6755
6798
  if (data?.message || data?.status === "step" || data?.status === "step_form" || data?.status === "thinking" || data?.status === "questions") {
6756
6799
  if (data.status === "questions") {
@@ -6877,15 +6920,27 @@ const StreamedContent = ({ botData }) => {
6877
6920
  ],
6878
6921
  },
6879
6922
  };
6880
- stepFormDataMapRef.current[currentIntent] = [...formWidgetData, stepFormSubmitButton];
6923
+ stepFormDataMapRef.current[currentIntent] = {
6924
+ widgets: [...formWidgetData, stepFormSubmitButton],
6925
+ showSavedFilters: data.show_saved_filters !== false,
6926
+ };
6881
6927
  setStepFormDataMap(lodash.cloneDeep(stepFormDataMapRef.current));
6882
6928
  }
6883
6929
  setStepChange((prev) => !prev);
6884
6930
  // Persist IDs immediately when step_form arrives (AxiosEventSource already set them)
6885
- localStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
6886
- localStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
6887
- localStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
6888
- localStorage.setItem("stepForm_baseUrl", baseUrl || "");
6931
+ const _sid = messageToStoreRef.current.sessionId || "";
6932
+ const _cid = messageToStoreRef.current.uniqueChatId || "";
6933
+ const _aid = botData.inputBody?.agent_id || "";
6934
+ const _burl = baseUrl || "";
6935
+ sessionStorage.setItem("stepForm_sessionId", _sid);
6936
+ sessionStorage.setItem("stepForm_chatId", _cid);
6937
+ sessionStorage.setItem("stepForm_agentId", _aid);
6938
+ sessionStorage.setItem("stepForm_baseUrl", _burl);
6939
+ // Also set on module-level control object (survives async timing issues)
6940
+ stepFormStreamControl.sessionId = _sid;
6941
+ stepFormStreamControl.chatId = _cid;
6942
+ stepFormStreamControl.agentId = _aid;
6943
+ stepFormStreamControl.baseUrl = _burl;
6889
6944
  // If this is the [DONE] chunk, mark streaming as complete
6890
6945
  if (data.message === "[DONE]") {
6891
6946
  setIsStreamingDone(true);
@@ -6895,7 +6950,6 @@ const StreamedContent = ({ botData }) => {
6895
6950
  }
6896
6951
  }
6897
6952
  else if (data.message !== "[DONE]") {
6898
- setStepsDone(true);
6899
6953
  if (!thinkingDoneRef?.current && currentMode === "agent") {
6900
6954
  thinkingDoneRef.current = true;
6901
6955
  setThinkDone(true);
@@ -6922,6 +6976,10 @@ const StreamedContent = ({ botData }) => {
6922
6976
  });
6923
6977
  }
6924
6978
  else {
6979
+ // message === "[DONE]" with status "completed" — switch to agent_response tab
6980
+ if (data.status === "completed") {
6981
+ setStepsDone(true);
6982
+ }
6925
6983
  setIsStreamingDone(true);
6926
6984
  const doneState = streamStateMap.get(streamKey);
6927
6985
  if (doneState)
@@ -7039,10 +7097,15 @@ const StreamedContent = ({ botData }) => {
7039
7097
  dispatch(smartBotActions.setCurrentAgentChatId(messageToStoreRef.current.uniqueChatId));
7040
7098
  }
7041
7099
  // Persist IDs for step form restream (ButtonContent reads these)
7042
- localStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
7043
- localStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
7044
- localStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
7045
- localStorage.setItem("stepForm_baseUrl", baseUrl || "");
7100
+ sessionStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
7101
+ sessionStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
7102
+ sessionStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
7103
+ sessionStorage.setItem("stepForm_baseUrl", baseUrl || "");
7104
+ // Also sync module-level control object
7105
+ stepFormStreamControl.sessionId = messageToStoreRef.current.sessionId || "";
7106
+ stepFormStreamControl.chatId = messageToStoreRef.current.uniqueChatId || "";
7107
+ stepFormStreamControl.agentId = botData.inputBody?.agent_id || "";
7108
+ stepFormStreamControl.baseUrl = baseUrl || "";
7046
7109
  let appendedDataLength = 0;
7047
7110
  // Use appendedDataFromLastChunk for field number calculation like host app
7048
7111
  if (isArray(messageToStoreRef.current.appendedDataFromLastChunk)) {
@@ -7097,7 +7160,7 @@ const StreamedContent = ({ botData }) => {
7097
7160
  newChatData: chatDataInfoRef,
7098
7161
  isTabEnabled: true,
7099
7162
  steps: lodash.cloneDeep(stepRef.current),
7100
- currentTabValue: "agent_response",
7163
+ currentTabValue: stepsDone ? "agent_response" : undefined,
7101
7164
  questions: lodash.cloneDeep(questionsRef.current),
7102
7165
  questionsStepsMap: lodash.cloneDeep(questionsStepsMapRef.current),
7103
7166
  stepFormDataMap: lodash.cloneDeep(stepFormDataMapRef.current),
@@ -7183,7 +7246,7 @@ const StreamedContent = ({ botData }) => {
7183
7246
  newChatData: chatDataInfoRef,
7184
7247
  isTabEnabled: true,
7185
7248
  steps: lodash.cloneDeep(stepRef.current),
7186
- currentTabValue: "agent_response",
7249
+ currentTabValue: stepsDone ? "agent_response" : undefined,
7187
7250
  questions: lodash.cloneDeep(questionsRef.current),
7188
7251
  questionsStepsMap: lodash.cloneDeep(questionsStepsMapRef.current),
7189
7252
  stepFormDataMap: lodash.cloneDeep(stepFormDataMapRef.current),
@@ -7395,8 +7458,8 @@ const useStyles$2 = makeStyles((theme) => ({
7395
7458
  "&.completed": {
7396
7459
  width: pxToRem(10),
7397
7460
  height: pxToRem(10),
7398
- background: colours.greyscale250,
7399
- border: `${pxToRem(3)} solid ${colours.greyscale150}`,
7461
+ background: "#4CAF50",
7462
+ border: `${pxToRem(3)} solid #C8E6C9`,
7400
7463
  boxSizing: "content-box",
7401
7464
  },
7402
7465
  "&.in-progress": {
@@ -7538,11 +7601,11 @@ const getQuestionStatus = (questionSteps) => {
7538
7601
  /**
7539
7602
  * Renders a single progress bar item (main point + sub-items)
7540
7603
  */
7541
- const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, isFormDisabled, isRestreaming = false }) => {
7604
+ const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, isFormDisabled, isRestreaming = false, showSavedFilters = true }) => {
7542
7605
  const baseStatus = getQuestionStatus(questionSteps);
7543
7606
  // When restreaming and this is the last item, show as in-progress
7544
7607
  const status = (isRestreaming && isLast) ? "in-progress" : baseStatus;
7545
- const [isExpanded, setIsExpanded] = React.useState(status === "in-progress" || status === "error");
7608
+ const [isExpanded, setIsExpanded] = React.useState(true);
7546
7609
  const dotClass = status === "completed"
7547
7610
  ? "completed"
7548
7611
  : status === "in-progress"
@@ -7567,9 +7630,9 @@ const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, i
7567
7630
  setIsExpanded(true);
7568
7631
  }
7569
7632
  }, [status, formData]);
7570
- return (jsxRuntime.jsxs("div", { className: classes.progressItem, children: [jsxRuntime.jsxs("div", { className: classes.progressTrack, children: [jsxRuntime.jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsxRuntime.jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxRuntime.jsxs("div", { className: classes.progressContent, children: [jsxRuntime.jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsxRuntime.jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsxRuntime.jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxRuntime.jsxs("div", { className: classes.reasoningLabel, children: [jsxRuntime.jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsxRuntime.jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxRuntime.jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsxRuntime.jsx("div", { className: classes.stepFormContainer, children: jsxRuntime.jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled }) }))] })] }));
7633
+ return (jsxRuntime.jsxs("div", { className: classes.progressItem, children: [jsxRuntime.jsxs("div", { className: classes.progressTrack, children: [jsxRuntime.jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsxRuntime.jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxRuntime.jsxs("div", { className: classes.progressContent, children: [jsxRuntime.jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsxRuntime.jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsxRuntime.jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxRuntime.jsxs("div", { className: classes.reasoningLabel, children: [jsxRuntime.jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsxRuntime.jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxRuntime.jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsxRuntime.jsx("div", { className: classes.stepFormContainer, children: jsxRuntime.jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }) }))] })] }));
7571
7634
  };
7572
- const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, isRestreaming = false }) => {
7635
+ const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, activeFormIntent = null, isRestreaming = false }) => {
7573
7636
  const classes = useStyles$2();
7574
7637
  React.useState(false);
7575
7638
  const hasQuestions = questions.length > 0;
@@ -7589,8 +7652,15 @@ const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap
7589
7652
  step_status: "completed",
7590
7653
  },
7591
7654
  ];
7592
- const formData = stepFormDataMap[question] || null;
7593
- return (jsxRuntime.jsx(ProgressBarItem, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: isFormDisabled, isRestreaming: isRestreaming }, index));
7655
+ const formEntry = stepFormDataMap[question] || null;
7656
+ // Support both old array format and new object format { widgets, showSavedFilters }
7657
+ const formData = formEntry ? (Array.isArray(formEntry) ? formEntry : formEntry.widgets) : null;
7658
+ const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
7659
+ // If activeFormIntent is set, only the matching form is enabled; all others stay disabled
7660
+ const formDisabledForThis = activeFormIntent
7661
+ ? question !== activeFormIntent
7662
+ : isFormDisabled;
7663
+ return (jsxRuntime.jsx(ProgressBarItem, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: formDisabledForThis, isRestreaming: isRestreaming, showSavedFilters: showSavedFilters }, index));
7594
7664
  }) }));
7595
7665
  };
7596
7666
 
@@ -7622,6 +7692,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7622
7692
  const [isRestreaming, setIsRestreaming] = React.useState(false);
7623
7693
  const [stepFormSubmitted, setStepFormSubmitted] = React.useState(false);
7624
7694
  const [hasNewStepFormFromRestream, setHasNewStepFormFromRestream] = React.useState(false);
7695
+ const [activeFormIntent, setActiveFormIntent] = React.useState(null);
7625
7696
  // Refs for accumulating state during streaming (avoids stale closures)
7626
7697
  const stepsRef = React.useRef(stepsState);
7627
7698
  const questionsRef = React.useRef(questionsState);
@@ -7630,6 +7701,16 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7630
7701
  const handleChangeTabValue = (_event, newValue) => {
7631
7702
  setTabValue(newValue);
7632
7703
  };
7704
+ // Switch to agent_response tab when ButtonContent's nth init stream completes with status "completed"
7705
+ React.useEffect(() => {
7706
+ const handleStepFormCompleted = () => {
7707
+ setTabValue("agent_response");
7708
+ };
7709
+ window.addEventListener("stepFormStreamCompleted", handleStepFormCompleted);
7710
+ return () => {
7711
+ window.removeEventListener("stepFormStreamCompleted", handleStepFormCompleted);
7712
+ };
7713
+ }, []);
7633
7714
  // Render a widget item from SSE data
7634
7715
  const renderWidget = (item, index) => {
7635
7716
  try {
@@ -7716,9 +7797,11 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7716
7797
  },
7717
7798
  ];
7718
7799
  }
7719
- const intentSteps = newQuestionsStepsMap[currentIntent];
7720
- if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
7721
- intentSteps[0].step_status = "completed";
7800
+ let intentSteps = newQuestionsStepsMap[currentIntent];
7801
+ // Remove placeholder if the real step has a header
7802
+ if (newStep.header && intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
7803
+ intentSteps = [];
7804
+ newQuestionsStepsMap[currentIntent] = intentSteps;
7722
7805
  }
7723
7806
  const existingStepIdx = intentSteps.findIndex((s) => s.header === newStep.header);
7724
7807
  if (existingStepIdx !== -1) {
@@ -7752,7 +7835,10 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7752
7835
  ],
7753
7836
  },
7754
7837
  };
7755
- newStepFormDataMap[currentIntent] = [...formWidgetData, submitButton];
7838
+ newStepFormDataMap[currentIntent] = {
7839
+ widgets: [...formWidgetData, submitButton],
7840
+ showSavedFilters: data.show_saved_filters !== false,
7841
+ };
7756
7842
  }
7757
7843
  }
7758
7844
  if (data.status === "widget") {
@@ -7779,10 +7865,16 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7779
7865
  setWidgetContent((prev) => [...prev, ...newWidgets]);
7780
7866
  }
7781
7867
  // If the response contains a new step_form, reset stepFormSubmitted and mark new form as active
7782
- const hasNewStepForm = chunks.some((c) => c.status === "step_form");
7783
- if (hasNewStepForm) {
7868
+ const lastStepFormChunk = [...chunks].reverse().find((c) => c.status === "step_form");
7869
+ if (lastStepFormChunk) {
7870
+ const formWidgetData = isArray$1(lastStepFormChunk.widget_data) ? lastStepFormChunk.widget_data : [lastStepFormChunk.widget_data];
7871
+ const latestIntent = lastStepFormChunk.current_intent || formWidgetData?.[0]?.current_intent;
7784
7872
  setStepFormSubmitted(false);
7785
7873
  setHasNewStepFormFromRestream(true);
7874
+ setActiveFormIntent(latestIntent || null);
7875
+ // Clear stale persisted form values and context so the new form starts fresh
7876
+ dispatch(smartBotActions.clearPersistedFormValues());
7877
+ dispatch(smartBotActions.setChatbotContext({}));
7786
7878
  }
7787
7879
  setIsRestreaming(false);
7788
7880
  }, [stepFormStreamData]);
@@ -7800,7 +7892,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7800
7892
  icon: jsxRuntime.jsx(PsychologyOutlinedIcon, { fontSize: "large" }),
7801
7893
  },
7802
7894
  ], tabPanels: [
7803
- jsxRuntime.jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: hasNewStepFormFromRestream ? false : ((isFormDisabled && !isRestreaming) || stepFormSubmitted), isRestreaming: isRestreaming }),
7895
+ jsxRuntime.jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: (isFormDisabled && !isRestreaming) || stepFormSubmitted, activeFormIntent: hasNewStepFormFromRestream ? activeFormIntent : null, isRestreaming: isRestreaming }),
7804
7896
  jsxRuntime.jsxs(AgentResponse, { children: [children, renderedWidgets.length > 0 && (jsxRuntime.jsx("div", { className: "restream-widget-content", children: renderedWidgets }))] }),
7805
7897
  ], value: tabValue }) }));
7806
7898
  };
@@ -11554,6 +11646,35 @@ const SmartBot = (props) => {
11554
11646
  setFieldNumber,
11555
11647
  setAdditionalArgs,
11556
11648
  });
11649
+ // Show/hide stop icon when step-form restream (second init API from ButtonContent) starts/ends.
11650
+ // Must live here (SmartBot) because StreamedContent unmounts after the first stream completes.
11651
+ React.useEffect(() => {
11652
+ const handleStepFormStreamStart = () => {
11653
+ setIsStop(true);
11654
+ const abortStepFormStream = () => {
11655
+ if (stepFormStreamControl.abort) {
11656
+ stepFormStreamControl.abort();
11657
+ }
11658
+ setIsStop(false);
11659
+ };
11660
+ setFunctionsState((prev) => ({
11661
+ ...prev,
11662
+ abortStreaming: abortStepFormStream,
11663
+ }));
11664
+ if (functionsRef?.current) {
11665
+ functionsRef.current.abortStreaming = abortStepFormStream;
11666
+ }
11667
+ };
11668
+ const handleStepFormStreamEnd = () => {
11669
+ setIsStop(false);
11670
+ };
11671
+ window.addEventListener("stepFormStreamStart", handleStepFormStreamStart);
11672
+ window.addEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
11673
+ return () => {
11674
+ window.removeEventListener("stepFormStreamStart", handleStepFormStreamStart);
11675
+ window.removeEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
11676
+ };
11677
+ }, []);
11557
11678
  const fetchCustomBotConfigurations = async () => {
11558
11679
  try {
11559
11680
  // const response = await fetchCustomBotConfig(baseUrl);