impact-chatbot 2.3.7 → 2.3.9
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.cjs.js +228 -230
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +228 -230
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -4504,7 +4504,7 @@ const ChatPlaceholder = (props) => {
|
|
|
4504
4504
|
getBaseUrl();
|
|
4505
4505
|
}, []);
|
|
4506
4506
|
const handleRectangleClick = (agentId, title) => {
|
|
4507
|
-
if (legacyAgentScreen) {
|
|
4507
|
+
if (legacyAgentScreen || displayQuestions) {
|
|
4508
4508
|
setCurrentAgentId(agentId);
|
|
4509
4509
|
const initiateAgentPayload = {
|
|
4510
4510
|
agent_id: agentId,
|
|
@@ -4553,7 +4553,7 @@ const ChatPlaceholder = (props) => {
|
|
|
4553
4553
|
agentId: card.agentId || card.id
|
|
4554
4554
|
}));
|
|
4555
4555
|
const dataToMap = legacyAgentScreen || displayQuestions ? transformedCardList : rectangleData;
|
|
4556
|
-
return (jsxs("div", { className: classes.placeholderContainer, children: [jsx("div", { className: classes.centerIconContainer, children: jsx(SvgCenter3D, { className: classes.centerIcon }) }), jsx(Typography, { variant: "h1", className: classes.heading, children: "Alan's Capabilities" }), 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 }, index))) })] }));
|
|
4556
|
+
return (jsxs("div", { className: classes.placeholderContainer, children: [jsx("div", { className: classes.centerIconContainer, children: jsx(SvgCenter3D, { className: classes.centerIcon }) }), jsx(Typography, { variant: "h1", className: classes.heading, children: "Alan's Capabilities" }), 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))) })] }));
|
|
4557
4557
|
};
|
|
4558
4558
|
|
|
4559
4559
|
const dateFormat = "DD-MM-YYYY HH:mm:ss";
|
|
@@ -5815,6 +5815,12 @@ const StepsResponseTab = (props) => {
|
|
|
5815
5815
|
], value: tabValue }) }));
|
|
5816
5816
|
};
|
|
5817
5817
|
|
|
5818
|
+
/**
|
|
5819
|
+
* Module-level Map to persist streaming state across component remounts (tab switches).
|
|
5820
|
+
* Keyed by a stable identifier derived from input payload + mode + conversation ID.
|
|
5821
|
+
* This survives the cloneDeep replacement of botData in SmartBot's useEffect.
|
|
5822
|
+
*/
|
|
5823
|
+
const streamStateMap = new Map();
|
|
5818
5824
|
/**
|
|
5819
5825
|
* Formats thinking time to display minutes when appropriate
|
|
5820
5826
|
* @param {number} seconds - Time in seconds
|
|
@@ -5897,9 +5903,13 @@ const StreamedContent = ({ botData }) => {
|
|
|
5897
5903
|
const thinkingDoneRef = useRef(false);
|
|
5898
5904
|
const setThinkingContentRef = useRef(setThinkingContent); // Store current setThinkingContent function
|
|
5899
5905
|
const streamTimeoutRef = useRef(null); // Ref for stream timeout
|
|
5900
|
-
|
|
5901
|
-
|
|
5906
|
+
// Stable key for the module-level streamStateMap (survives cloneDeep of botData)
|
|
5907
|
+
const streamKey = useRef(`${currentMode}_${activeConversationId}_${JSON.stringify(botData.inputBody)}`).current;
|
|
5908
|
+
// Look up existing stream state from the Map (persists across tab-switch remounts)
|
|
5909
|
+
const existingStreamState = streamStateMap.get(streamKey);
|
|
5910
|
+
const messageToStoreRef = useRef(existingStreamState?.messageStore || {
|
|
5902
5911
|
status: "",
|
|
5912
|
+
currentMode: currentMode,
|
|
5903
5913
|
chatData: {
|
|
5904
5914
|
response: "",
|
|
5905
5915
|
response_heading: "",
|
|
@@ -5910,12 +5920,11 @@ const StreamedContent = ({ botData }) => {
|
|
|
5910
5920
|
thinkingHeading: botData?.utilityObject?.thinkingResponse?.thinkingHeading
|
|
5911
5921
|
},
|
|
5912
5922
|
},
|
|
5913
|
-
currentMode: currentMode,
|
|
5914
5923
|
appendedData: {},
|
|
5915
5924
|
appendedDataFromLastChunk: {},
|
|
5916
5925
|
initValue: false,
|
|
5917
5926
|
sessionId: "",
|
|
5918
|
-
uniqueChatId: ""
|
|
5927
|
+
uniqueChatId: "",
|
|
5919
5928
|
});
|
|
5920
5929
|
useRef(new Set()); // Tracks processed message chunks to prevent duplicates
|
|
5921
5930
|
useRef(""); // Tracks current content before adding new chunk
|
|
@@ -5966,239 +5975,171 @@ const StreamedContent = ({ botData }) => {
|
|
|
5966
5975
|
: undefined,
|
|
5967
5976
|
timeout: 30000, // 30 second timeout
|
|
5968
5977
|
}, messageToStoreRef);
|
|
5978
|
+
// Persist source in module-level Map so the connection survives tab-switch unmounts
|
|
5979
|
+
const state = streamStateMap.get(streamKey);
|
|
5980
|
+
if (state) {
|
|
5981
|
+
state.source = sourceRef.current;
|
|
5982
|
+
state.initiated = true;
|
|
5983
|
+
}
|
|
5969
5984
|
// localStorage.setItem("isStreaming", "true");
|
|
5970
5985
|
// Handle incoming messages
|
|
5971
|
-
sourceRef.current
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5986
|
+
attachListeners(sourceRef.current);
|
|
5987
|
+
}
|
|
5988
|
+
catch (error) {
|
|
5989
|
+
console.error("Error processing stream:", error);
|
|
5990
|
+
setContent("Error streaming response. Please try again.");
|
|
5991
|
+
setIsStreaming(false);
|
|
5992
|
+
if (isThinking) {
|
|
5993
|
+
setIsThinking(false);
|
|
5994
|
+
const endTime = Date.now();
|
|
5995
|
+
const duration = Math.round((endTime - thinkingStartTimeRef.current) / 1000);
|
|
5996
|
+
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
5997
|
+
setThinkingTime(finalThinkingTime);
|
|
5998
|
+
setShowThoughtDropdown(true);
|
|
5999
|
+
// Store thinking time in messageToStoreRef for persistence
|
|
6000
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
/**
|
|
6005
|
+
* Attaches event listeners to an SSE source with generation-based stale detection.
|
|
6006
|
+
* Only the latest mount's listeners will actually update state.
|
|
6007
|
+
*/
|
|
6008
|
+
const attachListeners = (source) => {
|
|
6009
|
+
const state = streamStateMap.get(streamKey);
|
|
6010
|
+
const generation = state ? ++state.listenerGeneration : 0;
|
|
6011
|
+
source.addEventListener("message", (event) => {
|
|
6012
|
+
// Skip if this listener is from a stale (previous) mount
|
|
6013
|
+
const currState = streamStateMap.get(streamKey);
|
|
6014
|
+
if (!currState || currState.listenerGeneration !== generation)
|
|
6015
|
+
return;
|
|
6016
|
+
try {
|
|
6017
|
+
if (currentMode === "agent" && !isThinkingFromParent) {
|
|
6018
|
+
setIsThinkingFromParent(true);
|
|
6019
|
+
botData.utilityObject.isThinking = true;
|
|
6020
|
+
botData.utilityObject.thinkingResponse.isThinking = true;
|
|
6021
|
+
thinkingStartTimeRef.current = Date.now();
|
|
6022
|
+
}
|
|
6023
|
+
const data = JSON.parse(event.data);
|
|
6024
|
+
if (data?.message || data?.status === "step" || data?.status === "thinking" || data?.status === "questions") {
|
|
6025
|
+
if (data.status === "questions") {
|
|
6026
|
+
const incomingQuestions = data.widget_data?.[0]?.questions || [];
|
|
6027
|
+
questionsRef.current = incomingQuestions;
|
|
6028
|
+
setQuestions(incomingQuestions);
|
|
6029
|
+
const initialMap = {};
|
|
6030
|
+
incomingQuestions.forEach((q) => {
|
|
6031
|
+
initialMap[q] = [
|
|
6032
|
+
{
|
|
6033
|
+
header: "Processing Request",
|
|
6034
|
+
sub_header: "Analyzing the current request",
|
|
6035
|
+
step_status: "not-completed",
|
|
6036
|
+
},
|
|
6037
|
+
];
|
|
6038
|
+
});
|
|
6039
|
+
questionsStepsMapRef.current = initialMap;
|
|
6040
|
+
setQuestionsStepsMap(cloneDeep(initialMap));
|
|
5978
6041
|
}
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
if
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
6042
|
+
else if (data.status === "thinking") {
|
|
6043
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = "Planning next moves";
|
|
6044
|
+
// Start thinking if not already started
|
|
6045
|
+
if (!isThinking) {
|
|
6046
|
+
setIsThinking(true);
|
|
6047
|
+
}
|
|
6048
|
+
// Update thinking content in a more reliable way
|
|
6049
|
+
const newValue = (thinkingContentRef.current || "") + data.message;
|
|
6050
|
+
setThinkingContentRef.current(newValue);
|
|
6051
|
+
thinkingContentRef.current = thinkingContentRef.current + data.message;
|
|
6052
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingStream = newValue;
|
|
6053
|
+
dispatch(setThinkingContext({
|
|
6054
|
+
thinkingHeaderMessage: thinkingHeaderMessageRef.current,
|
|
6055
|
+
thinkingContent: thinkingContentRef.current,
|
|
6056
|
+
}));
|
|
6057
|
+
setThinkingStarted(true);
|
|
6058
|
+
setIsThinkingFromParent(false);
|
|
6059
|
+
}
|
|
6060
|
+
else if (data.status === "step") {
|
|
6061
|
+
let newStep = data.widget_data[0];
|
|
6062
|
+
const currentIntent = data.widget_data[0]?.current_intent;
|
|
6063
|
+
setSteps([...steps, newStep]);
|
|
6064
|
+
let newSteps = cloneDeep(stepRef.current);
|
|
6065
|
+
if (newSteps.length === 1) {
|
|
6066
|
+
newSteps.forEach((step) => {
|
|
6067
|
+
step.step_status = "completed";
|
|
5994
6068
|
});
|
|
5995
|
-
questionsStepsMapRef.current = initialMap;
|
|
5996
|
-
setQuestionsStepsMap(cloneDeep(initialMap));
|
|
5997
6069
|
}
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
if (!isThinking) {
|
|
6002
|
-
setIsThinking(true);
|
|
6003
|
-
}
|
|
6004
|
-
// Update thinking content in a more reliable way
|
|
6005
|
-
const newValue = (thinkingContentRef.current || "") + data.message;
|
|
6006
|
-
setThinkingContentRef.current(newValue);
|
|
6007
|
-
thinkingContentRef.current = thinkingContentRef.current + data.message;
|
|
6008
|
-
messageToStoreRef.current.chatData.thinkingResponse.thinkingStream = newValue;
|
|
6009
|
-
// Update the ThinkingIndicator components with the new accumulated content
|
|
6010
|
-
// messageToStoreRef.current.chatData.thinkingResponse.thinkingContent = (
|
|
6011
|
-
// <ThinkingIndicator
|
|
6012
|
-
// thinkingContent={newValue}
|
|
6013
|
-
// isStreaming={isStreaming}
|
|
6014
|
-
// thinkDone={thinkDone}
|
|
6015
|
-
// renderThinkingLoader={renderThinkingLoader}
|
|
6016
|
-
// thinkingStarted={thinkingStarted}
|
|
6017
|
-
// />
|
|
6018
|
-
// );
|
|
6019
|
-
dispatch(setThinkingContext({
|
|
6020
|
-
thinkingHeaderMessage: thinkingHeaderMessageRef.current,
|
|
6021
|
-
thinkingContent: thinkingContentRef.current,
|
|
6022
|
-
}));
|
|
6023
|
-
setThinkingStarted(true);
|
|
6024
|
-
setIsThinkingFromParent(false);
|
|
6025
|
-
// botData.utilityObject.thinkingResponse.thinkingContent = (
|
|
6026
|
-
// <ThinkingIndicator
|
|
6027
|
-
// thinkingContent={newValue}
|
|
6028
|
-
// isStreaming={isStreaming}
|
|
6029
|
-
// thinkDone={thinkDone}
|
|
6030
|
-
// renderThinkingLoader={renderThinkingLoader}
|
|
6031
|
-
// thinkingStarted={thinkingStarted}
|
|
6032
|
-
// />
|
|
6033
|
-
// );
|
|
6070
|
+
const existingStepIndex = newSteps.findIndex((step) => step.header === newStep.header);
|
|
6071
|
+
if (existingStepIndex !== -1) {
|
|
6072
|
+
newSteps[existingStepIndex] = newStep;
|
|
6034
6073
|
}
|
|
6035
|
-
else
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6074
|
+
else {
|
|
6075
|
+
newSteps.push(newStep);
|
|
6076
|
+
}
|
|
6077
|
+
stepRef.current = newSteps;
|
|
6078
|
+
setSteps(newSteps);
|
|
6079
|
+
if (currentIntent && questionsStepsMapRef.current[currentIntent]) {
|
|
6080
|
+
let intentSteps = cloneDeep(questionsStepsMapRef.current[currentIntent]);
|
|
6081
|
+
if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
|
|
6082
|
+
intentSteps[0].step_status = "completed";
|
|
6044
6083
|
}
|
|
6045
|
-
const
|
|
6046
|
-
if (
|
|
6047
|
-
|
|
6084
|
+
const existingIdx = intentSteps.findIndex((s) => s.header === newStep.header);
|
|
6085
|
+
if (existingIdx !== -1) {
|
|
6086
|
+
intentSteps[existingIdx] = newStep;
|
|
6048
6087
|
}
|
|
6049
6088
|
else {
|
|
6050
|
-
|
|
6051
|
-
}
|
|
6052
|
-
stepRef.current = newSteps;
|
|
6053
|
-
setSteps(newSteps);
|
|
6054
|
-
if (currentIntent && questionsStepsMapRef.current[currentIntent]) {
|
|
6055
|
-
let intentSteps = cloneDeep(questionsStepsMapRef.current[currentIntent]);
|
|
6056
|
-
if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
|
|
6057
|
-
intentSteps[0].step_status = "completed";
|
|
6058
|
-
}
|
|
6059
|
-
const existingIdx = intentSteps.findIndex((s) => s.header === newStep.header);
|
|
6060
|
-
if (existingIdx !== -1) {
|
|
6061
|
-
intentSteps[existingIdx] = newStep;
|
|
6062
|
-
}
|
|
6063
|
-
else {
|
|
6064
|
-
intentSteps.push(newStep);
|
|
6065
|
-
}
|
|
6066
|
-
questionsStepsMapRef.current[currentIntent] = intentSteps;
|
|
6067
|
-
setQuestionsStepsMap(cloneDeep(questionsStepsMapRef.current));
|
|
6068
|
-
}
|
|
6069
|
-
setStepChange((prev) => !prev);
|
|
6070
|
-
}
|
|
6071
|
-
else if (data.message !== "[DONE]") {
|
|
6072
|
-
setStepsDone(true);
|
|
6073
|
-
// setTimeout(() => {
|
|
6074
|
-
// setStepsDone(true);
|
|
6075
|
-
// }, 5000);
|
|
6076
|
-
if (!thinkingDoneRef?.current && currentMode === "agent") {
|
|
6077
|
-
thinkingDoneRef.current = true;
|
|
6078
|
-
setThinkDone(true);
|
|
6079
|
-
setIsThinkingFromParent(false);
|
|
6080
|
-
const endTime = Date.now();
|
|
6081
|
-
const startTime = thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6082
|
-
const duration = Math.round((endTime - startTime) / 1000);
|
|
6083
|
-
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6084
|
-
setThinkingTime(finalThinkingTime);
|
|
6085
|
-
setShowThoughtDropdown(true);
|
|
6086
|
-
setIsThinking(false);
|
|
6087
|
-
// Store thinking time in messageToStoreRef for persistence
|
|
6088
|
-
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6089
|
-
thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6090
|
-
setThinkingHeaderMessage(`Thought for ${formatThinkingTime(finalThinkingTime)}`);
|
|
6091
|
-
thinkingHeaderMessageRef.current = `Thought for ${formatThinkingTime(finalThinkingTime)}`;
|
|
6092
|
-
dispatch(setThinkingContext({
|
|
6093
|
-
thinkingHeaderMessage: `Thinking Completed`,
|
|
6094
|
-
thinkingContent: thinkingContentRef.current,
|
|
6095
|
-
}));
|
|
6096
|
-
// dispatch(setThinkingContext({
|
|
6097
|
-
// thinkingHeaderMessage: `Thought for ${formatThinkingTime(finalThinkingTime)}`,
|
|
6098
|
-
// thinkingContent: thinkingContentRef.current,
|
|
6099
|
-
// }));
|
|
6100
|
-
// botData.utilityObject.thinkingResponse.thinkingHeading = (
|
|
6101
|
-
// <ThinkinHeaderInfo
|
|
6102
|
-
// thinkingHeaderMessage={`Thought for ${formatThinkingTime(finalThinkingTime)}`}
|
|
6103
|
-
// />
|
|
6104
|
-
// );
|
|
6089
|
+
intentSteps.push(newStep);
|
|
6105
6090
|
}
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
// thinkingStarted.current = false;
|
|
6109
|
-
// }
|
|
6110
|
-
setContent((prev) => {
|
|
6111
|
-
return prev + data.message;
|
|
6112
|
-
});
|
|
6113
|
-
// if (currentMode === "agent") {
|
|
6114
|
-
// setIsThinkingFromParent(false);
|
|
6115
|
-
// botData.utilityObject.isThinking = false;
|
|
6116
|
-
// botData.utilityObject.thinkingResponse.isThinking = false;
|
|
6117
|
-
// const finalThinkingTime =
|
|
6118
|
-
// thinkingTime || thinkingTimeFinalRef.current || 1;
|
|
6119
|
-
// let thinkingTimeFinal = cloneDeep(finalThinkingTime);
|
|
6120
|
-
// botData.utilityObject.thinkingResponse.thinkingHeading = (
|
|
6121
|
-
// <ThinkinHeaderInfo
|
|
6122
|
-
// thinkingHeaderMessage={`Thought for ${formatThinkingTime(thinkingTimeFinal)}`}
|
|
6123
|
-
// />
|
|
6124
|
-
// );
|
|
6125
|
-
// }
|
|
6126
|
-
// // End thinking when regular content starts
|
|
6127
|
-
// if (isThinking && currentMode === "agent") {
|
|
6128
|
-
// setIsThinking(false);
|
|
6129
|
-
// if (!thinkDone) {
|
|
6130
|
-
// const endTime = Date.now();
|
|
6131
|
-
// const startTime =
|
|
6132
|
-
// thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6133
|
-
// const duration = Math.round((endTime - startTime) / 1000);
|
|
6134
|
-
// const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6135
|
-
// setThinkingTime(finalThinkingTime);
|
|
6136
|
-
// setShowThoughtDropdown(true);
|
|
6137
|
-
// // Store thinking time in messageToStoreRef for persistence
|
|
6138
|
-
// messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6139
|
-
// thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6140
|
-
// }
|
|
6141
|
-
// }
|
|
6142
|
-
// if(!thinkDone && currentMode === "agent") {
|
|
6143
|
-
// setThinkDone(true);
|
|
6144
|
-
// setIsThinking(false);
|
|
6145
|
-
// setTimeout(() => {
|
|
6146
|
-
// // setThinkDone(true);
|
|
6147
|
-
// const endTime = Date.now();
|
|
6148
|
-
// const startTime =
|
|
6149
|
-
// thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6150
|
-
// const duration = Math.round((endTime - startTime) / 1000);
|
|
6151
|
-
// const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6152
|
-
// setThinkingTime(finalThinkingTime);
|
|
6153
|
-
// setShowThoughtDropdown(true);
|
|
6154
|
-
// // Store thinking time in messageToStoreRef for persistence
|
|
6155
|
-
// messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6156
|
-
// thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6157
|
-
// setContent((prev) => {
|
|
6158
|
-
// return prev + data.message;
|
|
6159
|
-
// });
|
|
6160
|
-
// }, 1000);
|
|
6161
|
-
// }
|
|
6162
|
-
// else {
|
|
6163
|
-
// setContent((prev) => {
|
|
6164
|
-
// return prev + data.message;
|
|
6165
|
-
// });
|
|
6166
|
-
// }
|
|
6091
|
+
questionsStepsMapRef.current[currentIntent] = intentSteps;
|
|
6092
|
+
setQuestionsStepsMap(cloneDeep(questionsStepsMapRef.current));
|
|
6167
6093
|
}
|
|
6168
|
-
|
|
6169
|
-
|
|
6094
|
+
setStepChange((prev) => !prev);
|
|
6095
|
+
}
|
|
6096
|
+
else if (data.message !== "[DONE]") {
|
|
6097
|
+
setStepsDone(true);
|
|
6098
|
+
if (!thinkingDoneRef?.current && currentMode === "agent") {
|
|
6099
|
+
thinkingDoneRef.current = true;
|
|
6100
|
+
setThinkDone(true);
|
|
6101
|
+
setIsThinkingFromParent(false);
|
|
6102
|
+
const endTime = Date.now();
|
|
6103
|
+
const startTime = thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6104
|
+
const duration = Math.round((endTime - startTime) / 1000);
|
|
6105
|
+
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6106
|
+
setThinkingTime(finalThinkingTime);
|
|
6107
|
+
setShowThoughtDropdown(true);
|
|
6108
|
+
setIsThinking(false);
|
|
6109
|
+
// Store thinking time in messageToStoreRef for persistence
|
|
6110
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6111
|
+
thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6112
|
+
setThinkingHeaderMessage(`Thought for ${formatThinkingTime(finalThinkingTime)}`);
|
|
6113
|
+
thinkingHeaderMessageRef.current = `Thought for ${formatThinkingTime(finalThinkingTime)}`;
|
|
6114
|
+
dispatch(setThinkingContext({
|
|
6115
|
+
thinkingHeaderMessage: `Thinking Completed`,
|
|
6116
|
+
thinkingContent: thinkingContentRef.current,
|
|
6117
|
+
}));
|
|
6170
6118
|
}
|
|
6119
|
+
setContent((prev) => {
|
|
6120
|
+
return prev + data.message;
|
|
6121
|
+
});
|
|
6122
|
+
}
|
|
6123
|
+
else {
|
|
6124
|
+
setIsStreamingDone(true);
|
|
6125
|
+
const doneState = streamStateMap.get(streamKey);
|
|
6126
|
+
if (doneState)
|
|
6127
|
+
doneState.completed = true;
|
|
6171
6128
|
}
|
|
6172
6129
|
}
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
}
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
const duration = Math.round((endTime - thinkingStartTimeRef.current) / 1000);
|
|
6185
|
-
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6186
|
-
setThinkingTime(finalThinkingTime);
|
|
6187
|
-
setShowThoughtDropdown(true);
|
|
6188
|
-
thinkingStartTimeRef.current = finalThinkingTime;
|
|
6189
|
-
// Store thinking time in messageToStoreRef for persistence
|
|
6190
|
-
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6191
|
-
}
|
|
6192
|
-
});
|
|
6193
|
-
// Handle stream closure
|
|
6194
|
-
sourceRef.current.addEventListener("close", () => {
|
|
6195
|
-
setIsStreaming(false);
|
|
6196
|
-
});
|
|
6197
|
-
}
|
|
6198
|
-
catch (error) {
|
|
6199
|
-
console.error("Error processing stream:", error);
|
|
6200
|
-
setContent("Error streaming response. Please try again.");
|
|
6130
|
+
}
|
|
6131
|
+
catch (e) {
|
|
6132
|
+
console.error("Error processing message:", e);
|
|
6133
|
+
}
|
|
6134
|
+
});
|
|
6135
|
+
// Handle stream errors
|
|
6136
|
+
source.addEventListener("error", (event) => {
|
|
6137
|
+
const errState = streamStateMap.get(streamKey);
|
|
6138
|
+
if (!errState || errState.listenerGeneration !== generation)
|
|
6139
|
+
return;
|
|
6140
|
+
console.error("Stream error:", event.reason);
|
|
6201
6141
|
setIsStreaming(false);
|
|
6142
|
+
errState.completed = true;
|
|
6202
6143
|
if (isThinking) {
|
|
6203
6144
|
setIsThinking(false);
|
|
6204
6145
|
const endTime = Date.now();
|
|
@@ -6206,13 +6147,62 @@ const StreamedContent = ({ botData }) => {
|
|
|
6206
6147
|
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6207
6148
|
setThinkingTime(finalThinkingTime);
|
|
6208
6149
|
setShowThoughtDropdown(true);
|
|
6150
|
+
thinkingStartTimeRef.current = finalThinkingTime;
|
|
6209
6151
|
// Store thinking time in messageToStoreRef for persistence
|
|
6210
6152
|
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6211
6153
|
}
|
|
6212
|
-
}
|
|
6154
|
+
});
|
|
6155
|
+
// Handle stream closure
|
|
6156
|
+
source.addEventListener("close", () => {
|
|
6157
|
+
const closeState = streamStateMap.get(streamKey);
|
|
6158
|
+
if (!closeState || closeState.listenerGeneration !== generation)
|
|
6159
|
+
return;
|
|
6160
|
+
setIsStreaming(false);
|
|
6161
|
+
closeState.completed = true;
|
|
6162
|
+
});
|
|
6213
6163
|
};
|
|
6164
|
+
/**
|
|
6165
|
+
* Effect to initialize streaming or restore state on tab-switch remount.
|
|
6166
|
+
* Uses module-level streamStateMap to detect remounts and avoid re-triggering the API.
|
|
6167
|
+
*/
|
|
6214
6168
|
useEffect(() => {
|
|
6215
|
-
|
|
6169
|
+
const mapState = streamStateMap.get(streamKey);
|
|
6170
|
+
if (mapState?.initiated) {
|
|
6171
|
+
// Remount after tab switch - restore state from persisted data
|
|
6172
|
+
const store = messageToStoreRef.current;
|
|
6173
|
+
// Restore accumulated content
|
|
6174
|
+
setContent(store.chatData?.response || "");
|
|
6175
|
+
// Restore thinking state
|
|
6176
|
+
if (store.chatData?.thinkingResponse?.thinkingStream) {
|
|
6177
|
+
thinkingContentRef.current = store.chatData.thinkingResponse.thinkingStream;
|
|
6178
|
+
}
|
|
6179
|
+
if (store.chatData?.thinkingResponse?.thinkingTime) {
|
|
6180
|
+
thinkingTimeFinalRef.current = store.chatData.thinkingResponse.thinkingTime;
|
|
6181
|
+
setThinkingTime(store.chatData.thinkingResponse.thinkingTime);
|
|
6182
|
+
}
|
|
6183
|
+
if (mapState.completed) {
|
|
6184
|
+
// Stream already finished while we were unmounted - trigger completion
|
|
6185
|
+
setIsStreaming(false);
|
|
6186
|
+
setIsStreamingDone(true);
|
|
6187
|
+
}
|
|
6188
|
+
else if (mapState.source) {
|
|
6189
|
+
// Stream still in progress - re-attach listeners to existing source
|
|
6190
|
+
sourceRef.current = mapState.source;
|
|
6191
|
+
setIsStreaming(true);
|
|
6192
|
+
attachListeners(mapState.source);
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
else {
|
|
6196
|
+
// First mount - initialize Map entry and start streaming
|
|
6197
|
+
streamStateMap.set(streamKey, {
|
|
6198
|
+
messageStore: messageToStoreRef.current,
|
|
6199
|
+
source: null,
|
|
6200
|
+
initiated: false,
|
|
6201
|
+
completed: false,
|
|
6202
|
+
listenerGeneration: 0,
|
|
6203
|
+
});
|
|
6204
|
+
processStream();
|
|
6205
|
+
}
|
|
6216
6206
|
}, []);
|
|
6217
6207
|
/**
|
|
6218
6208
|
* Effect to update chat data when streaming is complete
|
|
@@ -6381,6 +6371,8 @@ const StreamedContent = ({ botData }) => {
|
|
|
6381
6371
|
questionsStepsMap: cloneDeep(questionsStepsMapRef.current),
|
|
6382
6372
|
});
|
|
6383
6373
|
}
|
|
6374
|
+
// Clean up module-level Map entry - stream is fully processed
|
|
6375
|
+
streamStateMap.delete(streamKey);
|
|
6384
6376
|
// Trigger re-render by updating chatDataState
|
|
6385
6377
|
setTimeout(() => {
|
|
6386
6378
|
setChatDataState({ ...chatDataRef.current });
|
|
@@ -6412,6 +6404,12 @@ const StreamedContent = ({ botData }) => {
|
|
|
6412
6404
|
sourceRef.current.close();
|
|
6413
6405
|
setIsStreaming(false);
|
|
6414
6406
|
setIsStreamingDone(true);
|
|
6407
|
+
// Clean up stream state in module-level Map
|
|
6408
|
+
const abortState = streamStateMap.get(streamKey);
|
|
6409
|
+
if (abortState) {
|
|
6410
|
+
abortState.completed = true;
|
|
6411
|
+
abortState.source = null;
|
|
6412
|
+
}
|
|
6415
6413
|
// Stop the agent flow on the backend
|
|
6416
6414
|
if (messageToStoreRef.current.sessionId) {
|
|
6417
6415
|
stopAgentFlow({ session_id: messageToStoreRef.current.sessionId }, baseUrl);
|
|
@@ -6455,13 +6453,13 @@ const StreamedContent = ({ botData }) => {
|
|
|
6455
6453
|
};
|
|
6456
6454
|
}, [isStreaming]);
|
|
6457
6455
|
/**
|
|
6458
|
-
* Cleanup
|
|
6456
|
+
* Cleanup on unmount: Do NOT close the stream here.
|
|
6457
|
+
* The stream connection is kept alive in streamStateMap so it survives
|
|
6458
|
+
* tab-switch remounts. It is only closed by explicit abortStreaming() or new chat.
|
|
6459
6459
|
*/
|
|
6460
6460
|
useEffect(() => {
|
|
6461
6461
|
return () => {
|
|
6462
|
-
|
|
6463
|
-
sourceRef.current.close();
|
|
6464
|
-
}
|
|
6462
|
+
// Intentionally not closing the stream - it persists in streamStateMap
|
|
6465
6463
|
};
|
|
6466
6464
|
}, []);
|
|
6467
6465
|
/**
|