已开启
feat: deepsearch前端对话流程优化 #66
feat: deepsearch前端对话流程优化 #66
已开启
chenjingheng创建于 1月28日
共 2 个文件变更+253-151
@@ -50,11 +50,13 @@ export class DeepsearchSSEHandler {
50 private store: StoreDependencies;50 private store: StoreDependencies;
51 private streamCache: StreamCache;51 private streamCache: StreamCache;
52 private conversationId: string;52 private conversationId: string;
53+ private messageFindCache: Map<string, Message | null>; // 新增:消息查找缓存
53 54 
54 constructor(store: StoreDependencies, streamCache: StreamCache, conversationId: string) {55 constructor(store: StoreDependencies, streamCache: StreamCache, conversationId: string) {
55 this.store = store;56 this.store = store;
56 this.streamCache = streamCache;57 this.streamCache = streamCache;
57 this.conversationId = conversationId;58 this.conversationId = conversationId;
59+ this.messageFindCache = new Map(); // 初始化缓存
58 }60 }
59 61 
60 /**62 /**
@@ -143,8 +145,10 @@ export class DeepsearchSSEHandler {
143 const lastMessageItems = this.store.getCurrentMessageItems();145 const lastMessageItems = this.store.getCurrentMessageItems();
144 if (lastMessageItems && sectionIdx !== undefined && planIdx !== undefined) {146 if (lastMessageItems && sectionIdx !== undefined && planIdx !== undefined) {
145 147 
146- const sectionTask = this.findTaskInMessages(lastMessageItems.messagesIds, msg =>148+ const sectionTask = this.findTaskInMessages(
147- msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx149+ lastMessageItems.messagesIds,
150+ msg => msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx,
151+ `section_${sectionIdx}` // 添加缓存key
148 );152 );
149 153 
150 // 【步骤1】更新上一个 planTask (task_1_x_(n-1))154 // 【步骤1】更新上一个 planTask (task_1_x_(n-1))
@@ -204,8 +208,10 @@ export class DeepsearchSSEHandler {
204 const lastMessageItems = this.store.getCurrentMessageItems();208 const lastMessageItems = this.store.getCurrentMessageItems();
205 if (!lastMessageItems) return;209 if (!lastMessageItems) return;
206 210 
207- const sectionTask = this.findTaskInMessages(lastMessageItems.messagesIds, msg =>211+ const sectionTask = this.findTaskInMessages(
208- msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx212+ lastMessageItems.messagesIds,
213+ msg => msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx,
214+ `section_${sectionIdx}` // 添加缓存key
209 );215 );
210 216 
211 if (sectionTask) {217 if (sectionTask) {
@@ -303,8 +309,10 @@ export class DeepsearchSSEHandler {
303 const lastMessageItems = this.store.getCurrentMessageItems();309 const lastMessageItems = this.store.getCurrentMessageItems();
304 if (!lastMessageItems) return;310 if (!lastMessageItems) return;
305 311 
306- const sectionTask = this.findTaskInMessages(lastMessageItems.messagesIds, msg =>312+ const sectionTask = this.findTaskInMessages(
307- msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx313+ lastMessageItems.messagesIds,
314+ msg => msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx,
315+ `section_${sectionIdx}` // 添加缓存key
308 );316 );
309 317 
310 if (sectionTask) {318 if (sectionTask) {
@@ -339,7 +347,11 @@ export class DeepsearchSSEHandler {
339 const streamKey = this.generateStreamKey(sseData.agent, sectionIdx, planIdx, stepIdx);347 const streamKey = this.generateStreamKey(sseData.agent, sectionIdx, planIdx, stepIdx);
340 const lastMessageItems = this.store.getCurrentMessageItems();348 const lastMessageItems = this.store.getCurrentMessageItems();
341 349 
342- if (!lastMessageItems || getMessageItemsIsUser(lastMessageItems)) return;350+ if (!lastMessageItems || getMessageItemsIsUser(lastMessageItems)) {
351+ // 清除缓存
352+ this.messageFindCache.clear();
353+ return;
354+ }
343 355 
344 // outline 完成356 // outline 完成
345 if (sseData.agent === 'outline') {357 if (sseData.agent === 'outline') {
@@ -532,8 +544,10 @@ export class DeepsearchSSEHandler {
532 // sub_reporter 完成544 // sub_reporter 完成
533 if (sseData.agent === 'sub_reporter' && sectionIdx !== undefined && sectionIdx > 0) {545 if (sseData.agent === 'sub_reporter' && sectionIdx !== undefined && sectionIdx > 0) {
534 const cachedContent = this.getCacheContent(streamKey);546 const cachedContent = this.getCacheContent(streamKey);
535- const sectionTask = this.findTaskInMessages(lastMessageItems.messagesIds, msg =>547+ const sectionTask = this.findTaskInMessages(
536- msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx548+ lastMessageItems.messagesIds,
549+ msg => msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx,
550+ `section_${sectionIdx}` // 添加缓存key
537 );551 );
538 552 
539 if (sectionTask) {553 if (sectionTask) {
@@ -599,8 +613,10 @@ export class DeepsearchSSEHandler {
599 613 
600 // 检查是否包含最终结果(不是简单的 SECTION END 或 ALL END)614 // 检查是否包含最终结果(不是简单的 SECTION END 或 ALL END)
601 if (content && typeof content === 'object' && (content.response_content || content.exception_info)) {615 if (content && typeof content === 'object' && (content.response_content || content.exception_info)) {
602- const outlineTask = this.findTaskInMessages(lastMessageItems.messagesIds, msg =>616+ const outlineTask = this.findTaskInMessages(
603- msg.type === MessageType.TASK && msg.sectionIdx === 0617+ lastMessageItems.messagesIds,
618+ msg => msg.type === MessageType.TASK && msg.sectionIdx === 0,
619+ 'outline_root' // 添加缓存key
604 );620 );
605 621 
606 if (outlineTask) {622 if (outlineTask) {
@@ -634,6 +650,9 @@ export class DeepsearchSSEHandler {
634 isStreaming: false,650 isStreaming: false,
635 });651 });
636 }652 }
653+ 
654+ // 处理完成后清除缓存
655+ this.messageFindCache.clear();
637 }656 }
638 657 
639 /**658 /**
@@ -648,8 +667,10 @@ export class DeepsearchSSEHandler {
648 if (['collector_info_retrieval', 'collector_summary'].includes(sseData.agent) &&667 if (['collector_info_retrieval', 'collector_summary'].includes(sseData.agent) &&
649 sectionIdx !== undefined && planIdx !== undefined && stepIdx !== undefined) {668 sectionIdx !== undefined && planIdx !== undefined && stepIdx !== undefined) {
650 669 
651- const sectionTask = this.findTaskInMessages(lastMessageItems.messagesIds, msg =>670+ const sectionTask = this.findTaskInMessages(
652- msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx671+ lastMessageItems.messagesIds,
672+ msg => msg.type === MessageType.TASK && msg.sectionIdx === sectionIdx,
673+ `section_${sectionIdx}` // 添加缓存key
653 );674 );
654 675 
655 if (!sectionTask) {676 if (!sectionTask) {
@@ -835,9 +856,9 @@ export class DeepsearchSSEHandler {
835 });856 });
836 857 
837 // 3. 更新 task_1 (outline_task): status = COMPLETED858 // 3. 更新 task_1 (outline_task): status = COMPLETED
838- updateMessage(lastMessageItems.id, outlineTask.id, {859+ // updateMessage(lastMessageItems.id, outlineTask.id, {
839- status: TaskStatus.COMPLETED,860+ // status: TaskStatus.COMPLETED,
840- });861+ // });
841 }862 }
842 }863 }
843 864 
@@ -1068,21 +1089,38 @@ export class DeepsearchSSEHandler {
1068 }1089 }
1069 1090 
1070 /**1091 /**
1071- * 在消息列表中递归查找任务1092+ * 在消息列表中递归查找任务(带缓存)
1072 */1093 */
1073- private findTaskInMessages(messageIds: string[], predicate: (msg: Message) => boolean): Message | null {1094+ private findTaskInMessages(messageIds: string[], predicate: (msg: Message) => boolean, cacheKey?: string): Message | null {
1095+ // 如果有缓存key,先检查缓存
1096+ if (cacheKey && this.messageFindCache.has(cacheKey)) {
1097+ return this.messageFindCache.get(cacheKey)!;
1098+ }
1099+ 
1100+ // 递归查找
1074 for (const messageId of messageIds) {1101 for (const messageId of messageIds) {
1075 const msg = this.store.getMessageById(messageId);1102 const msg = this.store.getMessageById(messageId);
1076 if (!msg) continue;1103 if (!msg) continue;
1077 1104 
1078 if (predicate(msg)) {1105 if (predicate(msg)) {
1106+ // 缓存结果
1107+ if (cacheKey) {
1108+ this.messageFindCache.set(cacheKey, msg);
1109+ }
1079 return msg;1110 return msg;
1080 }1111 }
1081 if (msg.childMessageIds && msg.childMessageIds.length > 0) {1112 if (msg.childMessageIds && msg.childMessageIds.length > 0) {
1082 const found = this.findTaskInMessages(msg.childMessageIds, predicate);1113 const found = this.findTaskInMessages(msg.childMessageIds, predicate);
1083- if (found) return found;1114+ if (found) {
1115+ // 缓存结果
1116+ if (cacheKey) {
1117+ this.messageFindCache.set(cacheKey, found);
1118+ }
1119+ return found;
1120+ }
1084 }1121 }
1085 }1122 }
1123+ 
1086 return null;1124 return null;
1087 }1125 }
1088 1126 
@@ -1130,9 +1168,9 @@ export class DeepsearchSSEHandler {
1130 let count = 0;1168 let count = 0;
1131 1169 
1132 const markRecursively = (message: Message) => {1170 const markRecursively = (message: Message) => {
1133- // 只标记非 COMPLETED/CANCELLED(用户手动停止)/UNKNOWN 的消息1171+ // 只标记非 COMPLETED/CANCELLED(用户手动停止)/UNKNOWN / FAILED 的消息
1134- if (message.status !== TaskStatus.COMPLETED && message.status !== TaskStatus.CANCELLED &&1172+ if (message.status !== TaskStatus.COMPLETED && message.status !== TaskStatus.CANCELLED &&
1135- (/*markAsCompleted ||*/ message.status !== TaskStatus.UNKNOWN)) {1173+ message.status !== TaskStatus.FAILED && (/*markAsCompleted ||*/ message.status !== TaskStatus.UNKNOWN)) {
1136 updateMessage(messageItems.id, message.id, {1174 updateMessage(messageItems.id, message.id, {
1137 status: targetStatus,1175 status: targetStatus,
1138 });1176 });
@@ -828,12 +828,15 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
828 828 
829 if (!hasChanges) return state;829 if (!hasChanges) return state;
830 830 
831- const newMessageItemsMap = new Map(state.messageItemsMap);831+ // 创建新的MessageItems对象
832- newMessageItemsMap.set(messageItemsId, {832+ const updatedMessageItems: MessageItems = {
833 ...messageItems,833 ...messageItems,
834 ...updates,834 ...updates,
835 updatedAt: Date.now(),835 updatedAt: Date.now(),
836- });836+ };
837+ 
838+ const newMessageItemsMap = new Map(state.messageItemsMap);
839+ newMessageItemsMap.set(messageItemsId, updatedMessageItems);
837 840 
838 return {841 return {
839 messageItemsMap: newMessageItemsMap,842 messageItemsMap: newMessageItemsMap,
@@ -1050,34 +1053,41 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1050 1053 
1051 updateMessage: (messageItemsId: string, messageId: string, updates: Partial<Message>) => {1054 updateMessage: (messageItemsId: string, messageId: string, updates: Partial<Message>) => {
1052 set((state) => {1055 set((state) => {
1053- // 更新 messagesMap
1054 const existingMessage = state.messagesMap.get(messageId);1056 const existingMessage = state.messagesMap.get(messageId);
1055 if (!existingMessage) {1057 if (!existingMessage) {
1056 console.warn('[updateMessage] Message not found:', messageId);1058 console.warn('[updateMessage] Message not found:', messageId);
1057 return state;1059 return state;
1058 }1060 }
1059 1061 
1060- const newMessagesMap = new Map(state.messagesMap);1062+ // 创建新的Message对象
1061 const updatedMessage: Message = {1063 const updatedMessage: Message = {
1062 ...existingMessage,1064 ...existingMessage,
1063 ...updates,1065 ...updates,
1064 updatedAt: Date.now(),1066 updatedAt: Date.now(),
1065 };1067 };
1068+ 
1069+ const newMessagesMap = new Map(state.messagesMap);
1066 newMessagesMap.set(messageId, updatedMessage);1070 newMessagesMap.set(messageId, updatedMessage);
1067 1071 
1068- // 更新 messageItemsMap 的时间戳1072+ // 更新 messageItems 时间戳
1069- const newMessageItemsMap = new Map(state.messageItemsMap);1073+ const messageItems = state.messageItemsMap.get(messageItemsId);
1070- const messageItems = newMessageItemsMap.get(messageItemsId);
1071 if (messageItems) {1074 if (messageItems) {
1072- newMessageItemsMap.set(messageItemsId, {1075+ const updatedMessageItems: MessageItems = {
1073 ...messageItems,1076 ...messageItems,
1074 updatedAt: Date.now(),1077 updatedAt: Date.now(),
1075- });1078+ };
1079+ 
1080+ const newMessageItemsMap = new Map(state.messageItemsMap);
1081+ newMessageItemsMap.set(messageItemsId, updatedMessageItems);
1082+ 
1083+ return {
1084+ messagesMap: newMessagesMap,
1085+ messageItemsMap: newMessageItemsMap,
1086+ };
1076 }1087 }
1077 1088 
1078 return {1089 return {
1079 messagesMap: newMessagesMap,1090 messagesMap: newMessagesMap,
1080- messageItemsMap: newMessageItemsMap,
1081 };1091 };
1082 });1092 });
1083 },1093 },
@@ -1088,29 +1098,31 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1088 if (!messageItems) return state;1098 if (!messageItems) return state;
1089 1099 
1090 const newMessagesMap = new Map(state.messagesMap);1100 const newMessagesMap = new Map(state.messagesMap);
1091- const newMessageItemsMap = new Map(state.messageItemsMap);
1092 1101 
1093 // 递归删除子消息1102 // 递归删除子消息
1094 deleteMessageRecursively(messageId, newMessagesMap, state.messagesMap);1103 deleteMessageRecursively(messageId, newMessagesMap, state.messagesMap);
1095 1104 
1096- // 从 messageItems 的 messagesIds 中移除1105+ // 更新 messageItems
1097- const newMessagesIds = messageItems.messagesIds.filter(id => id !== messageId);1106+ const updatedMessageItems: MessageItems = {
1098- newMessageItemsMap.set(messageItemsId, {
1099 ...messageItems,1107 ...messageItems,
1100- messagesIds: newMessagesIds,1108+ messagesIds: messageItems.messagesIds.filter(id => id !== messageId),
1101 updatedAt: Date.now(),1109 updatedAt: Date.now(),
1102- });1110+ };
1111+ 
1112+ const newMessageItemsMap = new Map(state.messageItemsMap);
1113+ newMessageItemsMap.set(messageItemsId, updatedMessageItems);
1103 1114 
1104 // 从父消息的 childMessageIds 中移除1115 // 从父消息的 childMessageIds 中移除
1105 const message = state.messagesMap.get(messageId);1116 const message = state.messagesMap.get(messageId);
1106 if (message?.parentMessageId) {1117 if (message?.parentMessageId) {
1107 const parentMessage = newMessagesMap.get(message.parentMessageId);1118 const parentMessage = newMessagesMap.get(message.parentMessageId);
1108 if (parentMessage?.childMessageIds) {1119 if (parentMessage?.childMessageIds) {
1109- newMessagesMap.set(message.parentMessageId, {1120+ const updatedParent: Message = {
1110 ...parentMessage,1121 ...parentMessage,
1111 childMessageIds: parentMessage.childMessageIds.filter(id => id !== messageId),1122 childMessageIds: parentMessage.childMessageIds.filter(id => id !== messageId),
1112 updatedAt: Date.now(),1123 updatedAt: Date.now(),
1113- });1124+ };
1125+ newMessagesMap.set(message.parentMessageId, updatedParent);
1114 }1126 }
1115 }1127 }
1116 1128 
@@ -1131,27 +1143,36 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1131 1143 
1132 if (!content || content.length === 0) return state;1144 if (!content || content.length === 0) return state;
1133 1145 
1134- const newMessagesMap = new Map(state.messagesMap);1146+ // 创建新的Message对象
1135 const currentContent = typeof existingMessage.content === 'string' ? existingMessage.content : '';1147 const currentContent = typeof existingMessage.content === 'string' ? existingMessage.content : '';
1136- newMessagesMap.set(messageId, {1148+ const updatedMessage: Message = {
1137 ...existingMessage,1149 ...existingMessage,
1138 content: currentContent + content,1150 content: currentContent + content,
1139 updatedAt: Date.now(),1151 updatedAt: Date.now(),
1140- });1152+ };
1153+ 
1154+ const newMessagesMap = new Map(state.messagesMap);
1155+ newMessagesMap.set(messageId, updatedMessage);
1141 1156 
1142 // 更新 messageItems 时间戳1157 // 更新 messageItems 时间戳
1143- const newMessageItemsMap = new Map(state.messageItemsMap);1158+ const messageItems = state.messageItemsMap.get(messageItemsId);
1144- const messageItems = newMessageItemsMap.get(messageItemsId);
1145 if (messageItems) {1159 if (messageItems) {
1146- newMessageItemsMap.set(messageItemsId, {1160+ const updatedMessageItems: MessageItems = {
1147 ...messageItems,1161 ...messageItems,
1148 updatedAt: Date.now(),1162 updatedAt: Date.now(),
1149- });1163+ };
1164+ 
1165+ const newMessageItemsMap = new Map(state.messageItemsMap);
1166+ newMessageItemsMap.set(messageItemsId, updatedMessageItems);
1167+ 
1168+ return {
1169+ messagesMap: newMessagesMap,
1170+ messageItemsMap: newMessageItemsMap,
1171+ };
1150 }1172 }
1151 1173 
1152 return {1174 return {
1153 messagesMap: newMessagesMap,1175 messagesMap: newMessagesMap,
1154- messageItemsMap: newMessageItemsMap,
1155 };1176 };
1156 });1177 });
1157 },1178 },
@@ -1246,75 +1267,93 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1246 // 标记正在处理队列1267 // 标记正在处理队列
1247 set({ sseProcessingQueue: true });1268 set({ sseProcessingQueue: true });
1248 1269 
1249- // 获取队列中的第一个事件1270+ // 使用requestAnimationFrame批量处理
1250- const event = state.sseEventQueue[0];1271+ const BATCH_SIZE = 10; // 每批处理10个事件
1251 1272 
1252- // 获取当前 MessageItems1273+ const processBatch = () => {
1253- const getCurrentMessageItems = () => {1274+ const currentState = get();
1254- const currentList = get().getCurrentMessageItems();1275+ const eventsToProcess = currentState.sseEventQueue.slice(0, BATCH_SIZE);
1255- return currentList[currentList.length - 1];
1256- };
1257 1276 
1258- // 动态导入 deepsearch 处理器1277+ if (eventsToProcess.length === 0) {
1259- import('./handlers/deepsearchSSEHandler').then(({ DeepsearchSSEHandler }) => {1278+ set({ sseProcessingQueue: false });
1260- const handler = new DeepsearchSSEHandler(1279+ return;
1261- {
1262- getCurrentMessageItems: getCurrentMessageItems,
1263- addSystemMessage: get().addSystemMessage,
1264- addMessageAsChild: get().addMessageAsChild,
1265- updateMessage: get().updateMessage,
1266- deleteMessage: get().deleteMessage,
1267- updateMessageItems: get().updateMessageItems,
1268- appendMessageContent: get().appendMessageContent,
1269- getMessageById: get().getMessageById,
1270- getMessageTree: get().getMessageTree,
1271- getChildMessages: get().getChildMessages,
1272- getMessageItemsIsUser: get().getMessageItemsIsUser,
1273- },
1274- {
1275- get: (key: string) => get().sseStreamCache.get(key),
1276- set: (key: string, chunks: string[]) => {
1277- set((state) => {
1278- const newCache = new Map(state.sseStreamCache);
1279- newCache.set(key, chunks);
1280- return { sseStreamCache: newCache };
1281- });
1282- },
1283- delete: (key: string) => {
1284- set((state) => {
1285- const newCache = new Map(state.sseStreamCache);
1286- newCache.delete(key);
1287- return { sseStreamCache: newCache };
1288- });
1289- },
1290- },
1291- event.conversationId
1292- );
1293- // 使用类型断言,因为 useConversationStore 不应该知道具体的 SSE 数据结构
1294- handler.handleSSEMessage(event.sseData as any);
1295- 
1296- // 从队列中移除已处理的事件
1297- set((state) => ({
1298- sseEventQueue: state.sseEventQueue.slice(1),
1299- }));
1300- 
1301- // 继续处理下一个事件
1302- get().processSSEQueue();
1303- }).catch((error) => {
1304- console.error('[processSSEQueue] Failed to load deepsearch handler:', error);
1305- // 降级处理:创建简单的文本消息
1306- // 使用类型断言访问 SSE 数据属性
1307- const sseData = event.sseData as any;
1308- if (sseData.event === 'start' || sseData.event === 'message') {
1309- get().addSystemMessage(event.conversationId, MessageType.REPORT, sseData.content || '');
1310 }1280 }
1311 1281 
1312- // 从队列中移除失败的事件,继续处理下一个1282+ // 获取当前 MessageItems
1313- set((state) => ({1283+ const getCurrentMessageItems = () => {
1314- sseEventQueue: state.sseEventQueue.slice(1),1284+ const currentList = get().getCurrentMessageItems();
1315- }));1285+ return currentList[currentList.length - 1];
1316- get().processSSEQueue();1286+ };
1317- });1287+ 
1288+ // 动态导入 deepsearch 处理器
1289+ import('./handlers/deepsearchSSEHandler').then(({ DeepsearchSSEHandler }) => {
1290+ const handler = new DeepsearchSSEHandler(
1291+ {
1292+ getCurrentMessageItems: getCurrentMessageItems,
1293+ addSystemMessage: get().addSystemMessage,
1294+ addMessageAsChild: get().addMessageAsChild,
1295+ updateMessage: get().updateMessage,
1296+ deleteMessage: get().deleteMessage,
1297+ updateMessageItems: get().updateMessageItems,
1298+ appendMessageContent: get().appendMessageContent,
1299+ getMessageById: get().getMessageById,
1300+ getMessageTree: get().getMessageTree,
1301+ getChildMessages: get().getChildMessages,
1302+ getMessageItemsIsUser: get().getMessageItemsIsUser,
1303+ },
1304+ {
1305+ get: (key: string) => get().sseStreamCache.get(key),
1306+ set: (key: string, chunks: string[]) => {
1307+ set((state) => {
1308+ const newCache = new Map(state.sseStreamCache);
1309+ newCache.set(key, chunks);
1310+ return { sseStreamCache: newCache };
1311+ });
1312+ },
1313+ delete: (key: string) => {
1314+ set((state) => {
1315+ const newCache = new Map(state.sseStreamCache);
1316+ newCache.delete(key);
1317+ return { sseStreamCache: newCache };
1318+ });
1319+ },
1320+ },
1321+ eventsToProcess[0].conversationId
1322+ );
1323+ 
1324+ // 批量处理事件
1325+ eventsToProcess.forEach(event => {
1326+ // 使用类型断言,因为 useConversationStore 不应该知道具体的 SSE 数据结构
1327+ handler.handleSSEMessage(event.sseData as any);
1328+ });
1329+ 
1330+ // 从队列中移除已处理的事件
1331+ set((state) => ({
1332+ sseEventQueue: state.sseEventQueue.slice(eventsToProcess.length),
1333+ }));
1334+ 
1335+ // 继续处理下一批
1336+ requestAnimationFrame(processBatch);
1337+ }).catch((error) => {
1338+ console.error('[processSSEQueue] Failed to load deepsearch handler:', error);
1339+ 
1340+ // 降级处理:批量创建简单的文本消息
1341+ eventsToProcess.forEach(event => {
1342+ const sseData = event.sseData as any;
1343+ if (sseData.event === 'start' || sseData.event === 'message') {
1344+ get().addSystemMessage(event.conversationId, MessageType.REPORT, sseData.content || '');
1345+ }
1346+ });
1347+ 
1348+ // 从队列中移除失败的事件,继续处理下一批
1349+ set((state) => ({
1350+ sseEventQueue: state.sseEventQueue.slice(eventsToProcess.length),
1351+ }));
1352+ requestAnimationFrame(processBatch);
1353+ });
1354+ };
1355+ 
1356+ requestAnimationFrame(processBatch);
1318 },1357 },
1319 1358 
1320 // ========== 状态管理 ==========1359 // ========== 状态管理 ==========
@@ -1565,21 +1604,43 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1565 const state = get();1604 const state = get();
1566 const WARNING_THRESHOLD = 50 * 1024 * 1024; // 50MB in bytes1605 const WARNING_THRESHOLD = 50 * 1024 * 1024; // 50MB in bytes
1567 1606 
1568- // 计算 Map 结构的大小1607+ // 使用更轻量的估算方法
1569- const calculateMapSize = <K, V>(map: Map<K, V>): number => {1608+ const estimateSize = (obj: any): number => {
1570- let size = 0;1609+ if (obj === null || obj === undefined) return 0;
1571- map.forEach((value, key) => {1610+ if (typeof obj === 'string') return obj.length * 2; // UTF-16
1572- // 使用 JSON.stringify 估算大小,然后用 Blob 转换为字节数1611+ if (typeof obj === 'number') return 8;
1573- const serialized = JSON.stringify({ key, value });1612+ if (typeof obj === 'boolean') return 4;
1574- size += new Blob([serialized]).size;1613+ if (obj instanceof Date) return 24;
1575- });1614+ 
1576- return size;1615+ if (Array.isArray(obj)) {
1616+ return obj.reduce((sum, item) => sum + estimateSize(item), 0) + 16; // 数组开销
1617+ }
1618+ 
1619+ if (obj instanceof Map) {
1620+ let size = 16; // Map开销
1621+ obj.forEach((value, key) => {
1622+ size += estimateSize(key) + estimateSize(value) + 16; // entry开销
1623+ });
1624+ return size;
1625+ }
1626+ 
1627+ if (typeof obj === 'object') {
1628+ let size = 16; // 对象开销
1629+ for (const key in obj) {
1630+ if (obj.hasOwnProperty(key)) {
1631+ size += estimateSize(key) + estimateSize(obj[key]) + 16;
1632+ }
1633+ }
1634+ return size;
1635+ }
1636+ 
1637+ return 0;
1577 };1638 };
1578 1639 
1579 // 计算各个 Map 的大小1640 // 计算各个 Map 的大小
1580- const conversationsSize = calculateMapSize(state.conversationsMap);1641+ const conversationsSize = estimateSize(state.conversationsMap);
1581- const messageItemsSize = calculateMapSize(state.messageItemsMap);1642+ const messageItemsSize = estimateSize(state.messageItemsMap);
1582- const messagesSize = calculateMapSize(state.messagesMap);1643+ const messagesSize = estimateSize(state.messagesMap);
1583 1644 
1584 const totalSize = conversationsSize + messageItemsSize + messagesSize;1645 const totalSize = conversationsSize + messageItemsSize + messagesSize;
1585 const totalSizeInMB = totalSize / (1024 * 1024);1646 const totalSizeInMB = totalSize / (1024 * 1024);
@@ -1795,21 +1856,20 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1795 }1856 }
1796 1857 
1797 set((state) => {1858 set((state) => {
1798- const newMessageItemsMap = new Map(state.messageItemsMap);
1799- const newMessagesMap = new Map(state.messagesMap);
1800- const newConversationsMap = new Map(state.conversationsMap);
1801- 
1802 // 恢复 messageItems1859 // 恢复 messageItems
1860+ const newMessageItemsMap = new Map(state.messageItemsMap);
1803 doc.messageItems.forEach((items) => {1861 doc.messageItems.forEach((items) => {
1804 newMessageItemsMap.set(items.id, items);1862 newMessageItemsMap.set(items.id, items);
1805 });1863 });
1806 1864 
1807 // 恢复 messages1865 // 恢复 messages
1866+ const newMessagesMap = new Map(state.messagesMap);
1808 Object.entries(doc.messages).forEach(([msgId, msg]) => {1867 Object.entries(doc.messages).forEach(([msgId, msg]) => {
1809 newMessagesMap.set(msgId, msg);1868 newMessagesMap.set(msgId, msg);
1810 });1869 });
1811 1870 
1812 // 更新 conversation 的 messageItemsIds1871 // 更新 conversation 的 messageItemsIds
1872+ const newConversationsMap = new Map(state.conversationsMap);
1813 const existingConversation = newConversationsMap.get(conversationId);1873 const existingConversation = newConversationsMap.get(conversationId);
1814 if (existingConversation) {1874 if (existingConversation) {
1815 newConversationsMap.set(conversationId, {1875 newConversationsMap.set(conversationId, {
@@ -1819,9 +1879,9 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1819 }1879 }
1820 1880 
1821 return {1881 return {
1822- conversationsMap: newConversationsMap,
1823 messageItemsMap: newMessageItemsMap,1882 messageItemsMap: newMessageItemsMap,
1824 messagesMap: newMessagesMap,1883 messagesMap: newMessagesMap,
1884+ conversationsMap: newConversationsMap,
1825 };1885 };
1826 });1886 });
1827 } catch (error) {1887 } catch (error) {
@@ -1848,56 +1908,60 @@ export const useConversationStore = create<ConversationStore>((set, get) => ({
1848 }1908 }
1849 1909 
1850 set((state) => {1910 set((state) => {
1851- const newMessageItemsMap = new Map(state.messageItemsMap);
1852- 
1853 // 删除当前对话的所有 messageItems1911 // 删除当前对话的所有 messageItems
1912+ const newMessageItemsMap = new Map(state.messageItemsMap);
1854 conversation.messageItemsIds.forEach((itemsId) => {1913 conversation.messageItemsIds.forEach((itemsId) => {
1855 newMessageItemsMap.delete(itemsId);1914 newMessageItemsMap.delete(itemsId);
1856 });1915 });
1857 1916 
1858- // 注意:messagesMap 中的消息需要递归删除1917+ // 删除属于当前对话的所有 messages
1859- // 为了简化,我们清空并重新构建只包含非当前对话的消息1918+ // 先收集要删除的 messageId,因为不能在遍历Map时删除
1860- const newFilteredMessagesMap = new Map<string, Message>();1919+ const messageIdsToDelete: string[] = [];
1861 state.messagesMap.forEach((msg, msgId) => {1920 state.messagesMap.forEach((msg, msgId) => {
1862- // 只保留不属于当前对话的消息1921+ if (msg.conversationId === currentConversationId) {
1863- if (msg.conversationId !== currentConversationId) {1922+ messageIdsToDelete.push(msgId);
1864- newFilteredMessagesMap.set(msgId, msg);
1865 }1923 }
1866 });1924 });
1867 1925 
1926+ // 删除收集到的消息
1927+ const newMessagesMap = new Map(state.messagesMap);
1928+ messageIdsToDelete.forEach(msgId => {
1929+ newMessagesMap.delete(msgId);
1930+ });
1931+ 
1868 return {1932 return {
1869 messageItemsMap: newMessageItemsMap,1933 messageItemsMap: newMessageItemsMap,
1870- messagesMap: newFilteredMessagesMap,1934+ messagesMap: newMessagesMap,
1871 };1935 };
1872 });1936 });
1873 },1937 },
1874}));1938}));
1875- 
1876// ===== 监听 IndexDB 删除事件,同步删除内存中的对话 =====1939// ===== 监听 IndexDB 删除事件,同步删除内存中的对话 =====
1877if (typeof window !== 'undefined') {1940if (typeof window !== 'undefined') {
1878 conversationEventEmitter.on('conversation-deleted', async (event: any) => {1941 conversationEventEmitter.on('conversation-deleted', async (event: any) => {
1879- const { conversationId } = event1942+ const { conversationId } = event;
1880 1943 
1881 // 从内存中删除对话1944 // 从内存中删除对话
1882 useConversationStore.setState((state) => {1945 useConversationStore.setState((state) => {
1883- const newConversationsMap = new Map(state.conversationsMap)1946+ // 删除conversationsMap中的条目
1884- const newConversationsList = state.conversationsList.filter((id: string) => id !== conversationId)1947+ const newConversationsMap = new Map(state.conversationsMap);
1948+ newConversationsMap.delete(conversationId);
1949+ 
1950+ // 从conversationsList中移除
1951+ const newConversationsList = state.conversationsList.filter(id => id !== conversationId);
1885 1952 
1886 // 如果删除的是当前对话,清空当前对话ID1953 // 如果删除的是当前对话,清空当前对话ID
1887 const newCurrentConversationId = state.currentConversationId === conversationId1954 const newCurrentConversationId = state.currentConversationId === conversationId
1888 ? null1955 ? null
1889- : state.currentConversationId1956+ : state.currentConversationId;
1890- 
1891- // 从内存中删除对话基本信息
1892- newConversationsMap.delete(conversationId)
1893 1957 
1894 return {1958 return {
1895 conversationsMap: newConversationsMap,1959 conversationsMap: newConversationsMap,
1896 conversationsList: newConversationsList,1960 conversationsList: newConversationsList,
1897 currentConversationId: newCurrentConversationId,1961 currentConversationId: newCurrentConversationId,
1898- }1962+ };
1899- })1963+ });
1900- })1964+ });
1901}1965}
1902 1966 
1903// 开发环境下暴露 store 到 window 对象,方便调试1967// 开发环境下暴露 store 到 window 对象,方便调试