impact-chatbot 2.3.8 → 2.3.10
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 +225 -228
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +225 -228
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -5837,6 +5837,12 @@ const StepsResponseTab = (props) => {
|
|
|
5837
5837
|
], value: tabValue }) }));
|
|
5838
5838
|
};
|
|
5839
5839
|
|
|
5840
|
+
/**
|
|
5841
|
+
* Module-level Map to persist streaming state across component remounts (tab switches).
|
|
5842
|
+
* Keyed by a stable identifier derived from input payload + mode + conversation ID.
|
|
5843
|
+
* This survives the cloneDeep replacement of botData in SmartBot's useEffect.
|
|
5844
|
+
*/
|
|
5845
|
+
const streamStateMap = new Map();
|
|
5840
5846
|
/**
|
|
5841
5847
|
* Formats thinking time to display minutes when appropriate
|
|
5842
5848
|
* @param {number} seconds - Time in seconds
|
|
@@ -5919,9 +5925,13 @@ const StreamedContent = ({ botData }) => {
|
|
|
5919
5925
|
const thinkingDoneRef = React.useRef(false);
|
|
5920
5926
|
const setThinkingContentRef = React.useRef(setThinkingContent); // Store current setThinkingContent function
|
|
5921
5927
|
const streamTimeoutRef = React.useRef(null); // Ref for stream timeout
|
|
5922
|
-
|
|
5923
|
-
|
|
5928
|
+
// Stable key for the module-level streamStateMap (survives cloneDeep of botData)
|
|
5929
|
+
const streamKey = React.useRef(`${currentMode}_${activeConversationId}_${JSON.stringify(botData.inputBody)}`).current;
|
|
5930
|
+
// Look up existing stream state from the Map (persists across tab-switch remounts)
|
|
5931
|
+
const existingStreamState = streamStateMap.get(streamKey);
|
|
5932
|
+
const messageToStoreRef = React.useRef(existingStreamState?.messageStore || {
|
|
5924
5933
|
status: "",
|
|
5934
|
+
currentMode: currentMode,
|
|
5925
5935
|
chatData: {
|
|
5926
5936
|
response: "",
|
|
5927
5937
|
response_heading: "",
|
|
@@ -5932,12 +5942,11 @@ const StreamedContent = ({ botData }) => {
|
|
|
5932
5942
|
thinkingHeading: botData?.utilityObject?.thinkingResponse?.thinkingHeading
|
|
5933
5943
|
},
|
|
5934
5944
|
},
|
|
5935
|
-
currentMode: currentMode,
|
|
5936
5945
|
appendedData: {},
|
|
5937
5946
|
appendedDataFromLastChunk: {},
|
|
5938
5947
|
initValue: false,
|
|
5939
5948
|
sessionId: "",
|
|
5940
|
-
uniqueChatId: ""
|
|
5949
|
+
uniqueChatId: "",
|
|
5941
5950
|
});
|
|
5942
5951
|
React.useRef(new Set()); // Tracks processed message chunks to prevent duplicates
|
|
5943
5952
|
React.useRef(""); // Tracks current content before adding new chunk
|
|
@@ -5988,239 +5997,171 @@ const StreamedContent = ({ botData }) => {
|
|
|
5988
5997
|
: undefined,
|
|
5989
5998
|
timeout: 30000, // 30 second timeout
|
|
5990
5999
|
}, messageToStoreRef);
|
|
6000
|
+
// Persist source in module-level Map so the connection survives tab-switch unmounts
|
|
6001
|
+
const state = streamStateMap.get(streamKey);
|
|
6002
|
+
if (state) {
|
|
6003
|
+
state.source = sourceRef.current;
|
|
6004
|
+
state.initiated = true;
|
|
6005
|
+
}
|
|
5991
6006
|
// localStorage.setItem("isStreaming", "true");
|
|
5992
6007
|
// Handle incoming messages
|
|
5993
|
-
sourceRef.current
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6008
|
+
attachListeners(sourceRef.current);
|
|
6009
|
+
}
|
|
6010
|
+
catch (error) {
|
|
6011
|
+
console.error("Error processing stream:", error);
|
|
6012
|
+
setContent("Error streaming response. Please try again.");
|
|
6013
|
+
setIsStreaming(false);
|
|
6014
|
+
if (isThinking) {
|
|
6015
|
+
setIsThinking(false);
|
|
6016
|
+
const endTime = Date.now();
|
|
6017
|
+
const duration = Math.round((endTime - thinkingStartTimeRef.current) / 1000);
|
|
6018
|
+
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6019
|
+
setThinkingTime(finalThinkingTime);
|
|
6020
|
+
setShowThoughtDropdown(true);
|
|
6021
|
+
// Store thinking time in messageToStoreRef for persistence
|
|
6022
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
};
|
|
6026
|
+
/**
|
|
6027
|
+
* Attaches event listeners to an SSE source with generation-based stale detection.
|
|
6028
|
+
* Only the latest mount's listeners will actually update state.
|
|
6029
|
+
*/
|
|
6030
|
+
const attachListeners = (source) => {
|
|
6031
|
+
const state = streamStateMap.get(streamKey);
|
|
6032
|
+
const generation = state ? ++state.listenerGeneration : 0;
|
|
6033
|
+
source.addEventListener("message", (event) => {
|
|
6034
|
+
// Skip if this listener is from a stale (previous) mount
|
|
6035
|
+
const currState = streamStateMap.get(streamKey);
|
|
6036
|
+
if (!currState || currState.listenerGeneration !== generation)
|
|
6037
|
+
return;
|
|
6038
|
+
try {
|
|
6039
|
+
if (currentMode === "agent" && !isThinkingFromParent) {
|
|
6040
|
+
setIsThinkingFromParent(true);
|
|
6041
|
+
botData.utilityObject.isThinking = true;
|
|
6042
|
+
botData.utilityObject.thinkingResponse.isThinking = true;
|
|
6043
|
+
thinkingStartTimeRef.current = Date.now();
|
|
6044
|
+
}
|
|
6045
|
+
const data = JSON.parse(event.data);
|
|
6046
|
+
if (data?.message || data?.status === "step" || data?.status === "thinking" || data?.status === "questions") {
|
|
6047
|
+
if (data.status === "questions") {
|
|
6048
|
+
const incomingQuestions = data.widget_data?.[0]?.questions || [];
|
|
6049
|
+
questionsRef.current = incomingQuestions;
|
|
6050
|
+
setQuestions(incomingQuestions);
|
|
6051
|
+
const initialMap = {};
|
|
6052
|
+
incomingQuestions.forEach((q) => {
|
|
6053
|
+
initialMap[q] = [
|
|
6054
|
+
{
|
|
6055
|
+
header: "Processing Request",
|
|
6056
|
+
sub_header: "Analyzing the current request",
|
|
6057
|
+
step_status: "not-completed",
|
|
6058
|
+
},
|
|
6059
|
+
];
|
|
6060
|
+
});
|
|
6061
|
+
questionsStepsMapRef.current = initialMap;
|
|
6062
|
+
setQuestionsStepsMap(lodash.cloneDeep(initialMap));
|
|
6000
6063
|
}
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
if
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6064
|
+
else if (data.status === "thinking") {
|
|
6065
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingHeading = "Planning next moves";
|
|
6066
|
+
// Start thinking if not already started
|
|
6067
|
+
if (!isThinking) {
|
|
6068
|
+
setIsThinking(true);
|
|
6069
|
+
}
|
|
6070
|
+
// Update thinking content in a more reliable way
|
|
6071
|
+
const newValue = (thinkingContentRef.current || "") + data.message;
|
|
6072
|
+
setThinkingContentRef.current(newValue);
|
|
6073
|
+
thinkingContentRef.current = thinkingContentRef.current + data.message;
|
|
6074
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingStream = newValue;
|
|
6075
|
+
dispatch(smartBotActions.setThinkingContext({
|
|
6076
|
+
thinkingHeaderMessage: thinkingHeaderMessageRef.current,
|
|
6077
|
+
thinkingContent: thinkingContentRef.current,
|
|
6078
|
+
}));
|
|
6079
|
+
setThinkingStarted(true);
|
|
6080
|
+
setIsThinkingFromParent(false);
|
|
6081
|
+
}
|
|
6082
|
+
else if (data.status === "step") {
|
|
6083
|
+
let newStep = data.widget_data[0];
|
|
6084
|
+
const currentIntent = data.widget_data[0]?.current_intent;
|
|
6085
|
+
setSteps([...steps, newStep]);
|
|
6086
|
+
let newSteps = lodash.cloneDeep(stepRef.current);
|
|
6087
|
+
if (newSteps.length === 1) {
|
|
6088
|
+
newSteps.forEach((step) => {
|
|
6089
|
+
step.step_status = "completed";
|
|
6016
6090
|
});
|
|
6017
|
-
questionsStepsMapRef.current = initialMap;
|
|
6018
|
-
setQuestionsStepsMap(lodash.cloneDeep(initialMap));
|
|
6019
6091
|
}
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
if (!isThinking) {
|
|
6024
|
-
setIsThinking(true);
|
|
6025
|
-
}
|
|
6026
|
-
// Update thinking content in a more reliable way
|
|
6027
|
-
const newValue = (thinkingContentRef.current || "") + data.message;
|
|
6028
|
-
setThinkingContentRef.current(newValue);
|
|
6029
|
-
thinkingContentRef.current = thinkingContentRef.current + data.message;
|
|
6030
|
-
messageToStoreRef.current.chatData.thinkingResponse.thinkingStream = newValue;
|
|
6031
|
-
// Update the ThinkingIndicator components with the new accumulated content
|
|
6032
|
-
// messageToStoreRef.current.chatData.thinkingResponse.thinkingContent = (
|
|
6033
|
-
// <ThinkingIndicator
|
|
6034
|
-
// thinkingContent={newValue}
|
|
6035
|
-
// isStreaming={isStreaming}
|
|
6036
|
-
// thinkDone={thinkDone}
|
|
6037
|
-
// renderThinkingLoader={renderThinkingLoader}
|
|
6038
|
-
// thinkingStarted={thinkingStarted}
|
|
6039
|
-
// />
|
|
6040
|
-
// );
|
|
6041
|
-
dispatch(smartBotActions.setThinkingContext({
|
|
6042
|
-
thinkingHeaderMessage: thinkingHeaderMessageRef.current,
|
|
6043
|
-
thinkingContent: thinkingContentRef.current,
|
|
6044
|
-
}));
|
|
6045
|
-
setThinkingStarted(true);
|
|
6046
|
-
setIsThinkingFromParent(false);
|
|
6047
|
-
// botData.utilityObject.thinkingResponse.thinkingContent = (
|
|
6048
|
-
// <ThinkingIndicator
|
|
6049
|
-
// thinkingContent={newValue}
|
|
6050
|
-
// isStreaming={isStreaming}
|
|
6051
|
-
// thinkDone={thinkDone}
|
|
6052
|
-
// renderThinkingLoader={renderThinkingLoader}
|
|
6053
|
-
// thinkingStarted={thinkingStarted}
|
|
6054
|
-
// />
|
|
6055
|
-
// );
|
|
6092
|
+
const existingStepIndex = newSteps.findIndex((step) => step.header === newStep.header);
|
|
6093
|
+
if (existingStepIndex !== -1) {
|
|
6094
|
+
newSteps[existingStepIndex] = newStep;
|
|
6056
6095
|
}
|
|
6057
|
-
else
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6096
|
+
else {
|
|
6097
|
+
newSteps.push(newStep);
|
|
6098
|
+
}
|
|
6099
|
+
stepRef.current = newSteps;
|
|
6100
|
+
setSteps(newSteps);
|
|
6101
|
+
if (currentIntent && questionsStepsMapRef.current[currentIntent]) {
|
|
6102
|
+
let intentSteps = lodash.cloneDeep(questionsStepsMapRef.current[currentIntent]);
|
|
6103
|
+
if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
|
|
6104
|
+
intentSteps[0].step_status = "completed";
|
|
6066
6105
|
}
|
|
6067
|
-
const
|
|
6068
|
-
if (
|
|
6069
|
-
|
|
6106
|
+
const existingIdx = intentSteps.findIndex((s) => s.header === newStep.header);
|
|
6107
|
+
if (existingIdx !== -1) {
|
|
6108
|
+
intentSteps[existingIdx] = newStep;
|
|
6070
6109
|
}
|
|
6071
6110
|
else {
|
|
6072
|
-
|
|
6073
|
-
}
|
|
6074
|
-
stepRef.current = newSteps;
|
|
6075
|
-
setSteps(newSteps);
|
|
6076
|
-
if (currentIntent && questionsStepsMapRef.current[currentIntent]) {
|
|
6077
|
-
let intentSteps = lodash.cloneDeep(questionsStepsMapRef.current[currentIntent]);
|
|
6078
|
-
if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
|
|
6079
|
-
intentSteps[0].step_status = "completed";
|
|
6080
|
-
}
|
|
6081
|
-
const existingIdx = intentSteps.findIndex((s) => s.header === newStep.header);
|
|
6082
|
-
if (existingIdx !== -1) {
|
|
6083
|
-
intentSteps[existingIdx] = newStep;
|
|
6084
|
-
}
|
|
6085
|
-
else {
|
|
6086
|
-
intentSteps.push(newStep);
|
|
6087
|
-
}
|
|
6088
|
-
questionsStepsMapRef.current[currentIntent] = intentSteps;
|
|
6089
|
-
setQuestionsStepsMap(lodash.cloneDeep(questionsStepsMapRef.current));
|
|
6111
|
+
intentSteps.push(newStep);
|
|
6090
6112
|
}
|
|
6091
|
-
|
|
6113
|
+
questionsStepsMapRef.current[currentIntent] = intentSteps;
|
|
6114
|
+
setQuestionsStepsMap(lodash.cloneDeep(questionsStepsMapRef.current));
|
|
6092
6115
|
}
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
}));
|
|
6118
|
-
// dispatch(setThinkingContext({
|
|
6119
|
-
// thinkingHeaderMessage: `Thought for ${formatThinkingTime(finalThinkingTime)}`,
|
|
6120
|
-
// thinkingContent: thinkingContentRef.current,
|
|
6121
|
-
// }));
|
|
6122
|
-
// botData.utilityObject.thinkingResponse.thinkingHeading = (
|
|
6123
|
-
// <ThinkinHeaderInfo
|
|
6124
|
-
// thinkingHeaderMessage={`Thought for ${formatThinkingTime(finalThinkingTime)}`}
|
|
6125
|
-
// />
|
|
6126
|
-
// );
|
|
6127
|
-
}
|
|
6128
|
-
// if(thinkingStarted.current && !thinkDone){
|
|
6129
|
-
// setThinkDone(true);
|
|
6130
|
-
// thinkingStarted.current = false;
|
|
6131
|
-
// }
|
|
6132
|
-
setContent((prev) => {
|
|
6133
|
-
return prev + data.message;
|
|
6134
|
-
});
|
|
6135
|
-
// if (currentMode === "agent") {
|
|
6136
|
-
// setIsThinkingFromParent(false);
|
|
6137
|
-
// botData.utilityObject.isThinking = false;
|
|
6138
|
-
// botData.utilityObject.thinkingResponse.isThinking = false;
|
|
6139
|
-
// const finalThinkingTime =
|
|
6140
|
-
// thinkingTime || thinkingTimeFinalRef.current || 1;
|
|
6141
|
-
// let thinkingTimeFinal = cloneDeep(finalThinkingTime);
|
|
6142
|
-
// botData.utilityObject.thinkingResponse.thinkingHeading = (
|
|
6143
|
-
// <ThinkinHeaderInfo
|
|
6144
|
-
// thinkingHeaderMessage={`Thought for ${formatThinkingTime(thinkingTimeFinal)}`}
|
|
6145
|
-
// />
|
|
6146
|
-
// );
|
|
6147
|
-
// }
|
|
6148
|
-
// // End thinking when regular content starts
|
|
6149
|
-
// if (isThinking && currentMode === "agent") {
|
|
6150
|
-
// setIsThinking(false);
|
|
6151
|
-
// if (!thinkDone) {
|
|
6152
|
-
// const endTime = Date.now();
|
|
6153
|
-
// const startTime =
|
|
6154
|
-
// thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6155
|
-
// const duration = Math.round((endTime - startTime) / 1000);
|
|
6156
|
-
// const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6157
|
-
// setThinkingTime(finalThinkingTime);
|
|
6158
|
-
// setShowThoughtDropdown(true);
|
|
6159
|
-
// // Store thinking time in messageToStoreRef for persistence
|
|
6160
|
-
// messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6161
|
-
// thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6162
|
-
// }
|
|
6163
|
-
// }
|
|
6164
|
-
// if(!thinkDone && currentMode === "agent") {
|
|
6165
|
-
// setThinkDone(true);
|
|
6166
|
-
// setIsThinking(false);
|
|
6167
|
-
// setTimeout(() => {
|
|
6168
|
-
// // setThinkDone(true);
|
|
6169
|
-
// const endTime = Date.now();
|
|
6170
|
-
// const startTime =
|
|
6171
|
-
// thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6172
|
-
// const duration = Math.round((endTime - startTime) / 1000);
|
|
6173
|
-
// const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6174
|
-
// setThinkingTime(finalThinkingTime);
|
|
6175
|
-
// setShowThoughtDropdown(true);
|
|
6176
|
-
// // Store thinking time in messageToStoreRef for persistence
|
|
6177
|
-
// messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6178
|
-
// thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6179
|
-
// setContent((prev) => {
|
|
6180
|
-
// return prev + data.message;
|
|
6181
|
-
// });
|
|
6182
|
-
// }, 1000);
|
|
6183
|
-
// }
|
|
6184
|
-
// else {
|
|
6185
|
-
// setContent((prev) => {
|
|
6186
|
-
// return prev + data.message;
|
|
6187
|
-
// });
|
|
6188
|
-
// }
|
|
6189
|
-
}
|
|
6190
|
-
else {
|
|
6191
|
-
setIsStreamingDone(true);
|
|
6116
|
+
setStepChange((prev) => !prev);
|
|
6117
|
+
}
|
|
6118
|
+
else if (data.message !== "[DONE]") {
|
|
6119
|
+
setStepsDone(true);
|
|
6120
|
+
if (!thinkingDoneRef?.current && currentMode === "agent") {
|
|
6121
|
+
thinkingDoneRef.current = true;
|
|
6122
|
+
setThinkDone(true);
|
|
6123
|
+
setIsThinkingFromParent(false);
|
|
6124
|
+
const endTime = Date.now();
|
|
6125
|
+
const startTime = thinkingStartTimeRef.current || endTime - 1000; // Fallback to 1 second ago
|
|
6126
|
+
const duration = Math.round((endTime - startTime) / 1000);
|
|
6127
|
+
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6128
|
+
setThinkingTime(finalThinkingTime);
|
|
6129
|
+
setShowThoughtDropdown(true);
|
|
6130
|
+
setIsThinking(false);
|
|
6131
|
+
// Store thinking time in messageToStoreRef for persistence
|
|
6132
|
+
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6133
|
+
thinkingTimeFinalRef.current = finalThinkingTime;
|
|
6134
|
+
setThinkingHeaderMessage(`Thought for ${formatThinkingTime(finalThinkingTime)}`);
|
|
6135
|
+
thinkingHeaderMessageRef.current = `Thought for ${formatThinkingTime(finalThinkingTime)}`;
|
|
6136
|
+
dispatch(smartBotActions.setThinkingContext({
|
|
6137
|
+
thinkingHeaderMessage: `Thinking Completed`,
|
|
6138
|
+
thinkingContent: thinkingContentRef.current,
|
|
6139
|
+
}));
|
|
6192
6140
|
}
|
|
6141
|
+
setContent((prev) => {
|
|
6142
|
+
return prev + data.message;
|
|
6143
|
+
});
|
|
6144
|
+
}
|
|
6145
|
+
else {
|
|
6146
|
+
setIsStreamingDone(true);
|
|
6147
|
+
const doneState = streamStateMap.get(streamKey);
|
|
6148
|
+
if (doneState)
|
|
6149
|
+
doneState.completed = true;
|
|
6193
6150
|
}
|
|
6194
6151
|
}
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
}
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
const duration = Math.round((endTime - thinkingStartTimeRef.current) / 1000);
|
|
6207
|
-
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6208
|
-
setThinkingTime(finalThinkingTime);
|
|
6209
|
-
setShowThoughtDropdown(true);
|
|
6210
|
-
thinkingStartTimeRef.current = finalThinkingTime;
|
|
6211
|
-
// Store thinking time in messageToStoreRef for persistence
|
|
6212
|
-
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6213
|
-
}
|
|
6214
|
-
});
|
|
6215
|
-
// Handle stream closure
|
|
6216
|
-
sourceRef.current.addEventListener("close", () => {
|
|
6217
|
-
setIsStreaming(false);
|
|
6218
|
-
});
|
|
6219
|
-
}
|
|
6220
|
-
catch (error) {
|
|
6221
|
-
console.error("Error processing stream:", error);
|
|
6222
|
-
setContent("Error streaming response. Please try again.");
|
|
6152
|
+
}
|
|
6153
|
+
catch (e) {
|
|
6154
|
+
console.error("Error processing message:", e);
|
|
6155
|
+
}
|
|
6156
|
+
});
|
|
6157
|
+
// Handle stream errors
|
|
6158
|
+
source.addEventListener("error", (event) => {
|
|
6159
|
+
const errState = streamStateMap.get(streamKey);
|
|
6160
|
+
if (!errState || errState.listenerGeneration !== generation)
|
|
6161
|
+
return;
|
|
6162
|
+
console.error("Stream error:", event.reason);
|
|
6223
6163
|
setIsStreaming(false);
|
|
6164
|
+
errState.completed = true;
|
|
6224
6165
|
if (isThinking) {
|
|
6225
6166
|
setIsThinking(false);
|
|
6226
6167
|
const endTime = Date.now();
|
|
@@ -6228,13 +6169,62 @@ const StreamedContent = ({ botData }) => {
|
|
|
6228
6169
|
const finalThinkingTime = Math.max(duration, 1); // Ensure at least 1 second
|
|
6229
6170
|
setThinkingTime(finalThinkingTime);
|
|
6230
6171
|
setShowThoughtDropdown(true);
|
|
6172
|
+
thinkingStartTimeRef.current = finalThinkingTime;
|
|
6231
6173
|
// Store thinking time in messageToStoreRef for persistence
|
|
6232
6174
|
messageToStoreRef.current.chatData.thinkingResponse.thinkingTime = finalThinkingTime;
|
|
6233
6175
|
}
|
|
6234
|
-
}
|
|
6176
|
+
});
|
|
6177
|
+
// Handle stream closure
|
|
6178
|
+
source.addEventListener("close", () => {
|
|
6179
|
+
const closeState = streamStateMap.get(streamKey);
|
|
6180
|
+
if (!closeState || closeState.listenerGeneration !== generation)
|
|
6181
|
+
return;
|
|
6182
|
+
setIsStreaming(false);
|
|
6183
|
+
closeState.completed = true;
|
|
6184
|
+
});
|
|
6235
6185
|
};
|
|
6186
|
+
/**
|
|
6187
|
+
* Effect to initialize streaming or restore state on tab-switch remount.
|
|
6188
|
+
* Uses module-level streamStateMap to detect remounts and avoid re-triggering the API.
|
|
6189
|
+
*/
|
|
6236
6190
|
React.useEffect(() => {
|
|
6237
|
-
|
|
6191
|
+
const mapState = streamStateMap.get(streamKey);
|
|
6192
|
+
if (mapState?.initiated) {
|
|
6193
|
+
// Remount after tab switch - restore state from persisted data
|
|
6194
|
+
const store = messageToStoreRef.current;
|
|
6195
|
+
// Restore accumulated content
|
|
6196
|
+
setContent(store.chatData?.response || "");
|
|
6197
|
+
// Restore thinking state
|
|
6198
|
+
if (store.chatData?.thinkingResponse?.thinkingStream) {
|
|
6199
|
+
thinkingContentRef.current = store.chatData.thinkingResponse.thinkingStream;
|
|
6200
|
+
}
|
|
6201
|
+
if (store.chatData?.thinkingResponse?.thinkingTime) {
|
|
6202
|
+
thinkingTimeFinalRef.current = store.chatData.thinkingResponse.thinkingTime;
|
|
6203
|
+
setThinkingTime(store.chatData.thinkingResponse.thinkingTime);
|
|
6204
|
+
}
|
|
6205
|
+
if (mapState.completed) {
|
|
6206
|
+
// Stream already finished while we were unmounted - trigger completion
|
|
6207
|
+
setIsStreaming(false);
|
|
6208
|
+
setIsStreamingDone(true);
|
|
6209
|
+
}
|
|
6210
|
+
else if (mapState.source) {
|
|
6211
|
+
// Stream still in progress - re-attach listeners to existing source
|
|
6212
|
+
sourceRef.current = mapState.source;
|
|
6213
|
+
setIsStreaming(true);
|
|
6214
|
+
attachListeners(mapState.source);
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
else {
|
|
6218
|
+
// First mount - initialize Map entry and start streaming
|
|
6219
|
+
streamStateMap.set(streamKey, {
|
|
6220
|
+
messageStore: messageToStoreRef.current,
|
|
6221
|
+
source: null,
|
|
6222
|
+
initiated: false,
|
|
6223
|
+
completed: false,
|
|
6224
|
+
listenerGeneration: 0,
|
|
6225
|
+
});
|
|
6226
|
+
processStream();
|
|
6227
|
+
}
|
|
6238
6228
|
}, []);
|
|
6239
6229
|
/**
|
|
6240
6230
|
* Effect to update chat data when streaming is complete
|
|
@@ -6403,6 +6393,8 @@ const StreamedContent = ({ botData }) => {
|
|
|
6403
6393
|
questionsStepsMap: lodash.cloneDeep(questionsStepsMapRef.current),
|
|
6404
6394
|
});
|
|
6405
6395
|
}
|
|
6396
|
+
// Clean up module-level Map entry - stream is fully processed
|
|
6397
|
+
streamStateMap.delete(streamKey);
|
|
6406
6398
|
// Trigger re-render by updating chatDataState
|
|
6407
6399
|
setTimeout(() => {
|
|
6408
6400
|
setChatDataState({ ...chatDataRef.current });
|
|
@@ -6434,6 +6426,11 @@ const StreamedContent = ({ botData }) => {
|
|
|
6434
6426
|
sourceRef.current.close();
|
|
6435
6427
|
setIsStreaming(false);
|
|
6436
6428
|
setIsStreamingDone(true);
|
|
6429
|
+
// Delete module-level Map entry immediately on abort.
|
|
6430
|
+
// This ensures if the component unmounts before the isStreamingDone effect runs
|
|
6431
|
+
// (e.g. handleNewChatClick clears conversation), the next mount with the same
|
|
6432
|
+
// streamKey starts a fresh stream instead of restoring the aborted one.
|
|
6433
|
+
streamStateMap.delete(streamKey);
|
|
6437
6434
|
// Stop the agent flow on the backend
|
|
6438
6435
|
if (messageToStoreRef.current.sessionId) {
|
|
6439
6436
|
chatbotServices.stopAgentFlow({ session_id: messageToStoreRef.current.sessionId }, baseUrl);
|
|
@@ -6477,13 +6474,13 @@ const StreamedContent = ({ botData }) => {
|
|
|
6477
6474
|
};
|
|
6478
6475
|
}, [isStreaming]);
|
|
6479
6476
|
/**
|
|
6480
|
-
* Cleanup
|
|
6477
|
+
* Cleanup on unmount: Do NOT close the stream here.
|
|
6478
|
+
* The stream connection is kept alive in streamStateMap so it survives
|
|
6479
|
+
* tab-switch remounts. It is only closed by explicit abortStreaming() or new chat.
|
|
6481
6480
|
*/
|
|
6482
6481
|
React.useEffect(() => {
|
|
6483
6482
|
return () => {
|
|
6484
|
-
|
|
6485
|
-
sourceRef.current.close();
|
|
6486
|
-
}
|
|
6483
|
+
// Intentionally not closing the stream - it persists in streamStateMap
|
|
6487
6484
|
};
|
|
6488
6485
|
}, []);
|
|
6489
6486
|
/**
|