@ai-group/chat-sdk 3.6.7 → 3.6.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/cjs/components/XAdkChatbot/components/FunctionCallRender/index.js.map +2 -2
- package/dist/cjs/hooks/useADKChat.d.ts +2 -2
- package/dist/cjs/hooks/useADKChat.js +145 -179
- package/dist/cjs/hooks/useADKChat.js.map +3 -3
- package/dist/esm/components/XAdkChatbot/components/FunctionCallRender/index.js +2 -0
- package/dist/esm/components/XAdkChatbot/components/FunctionCallRender/index.js.map +1 -1
- package/dist/esm/hooks/useADKChat.d.ts +2 -2
- package/dist/esm/hooks/useADKChat.js +209 -199
- package/dist/esm/hooks/useADKChat.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -45,6 +45,47 @@ var combineTextParts = function combineTextParts(parts) {
|
|
|
45
45
|
return result;
|
|
46
46
|
};
|
|
47
47
|
var DEFAULT_SESSION_EVENTS_POLLING_INTERVAL = 10000;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 从 event + part 构建非文本 IMessage(functionCall / functionResponse / executableCode 等)。
|
|
51
|
+
*/
|
|
52
|
+
var buildNonTextMessage = function buildNonTextMessage(event, part) {
|
|
53
|
+
var role = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "bot";
|
|
54
|
+
var msg = {
|
|
55
|
+
id: v4(),
|
|
56
|
+
author: event.author,
|
|
57
|
+
invocationId: event.invocationId,
|
|
58
|
+
eventId: event.id,
|
|
59
|
+
timestamp: event.timestamp,
|
|
60
|
+
isLike: event.isLike || 0,
|
|
61
|
+
role: role,
|
|
62
|
+
modelCode: event.modelCode,
|
|
63
|
+
usageMetadata: event.usageMetadata,
|
|
64
|
+
finishReason: event.finishReason,
|
|
65
|
+
raw: event
|
|
66
|
+
};
|
|
67
|
+
if (part.inlineData) {
|
|
68
|
+
msg.inlineData = {
|
|
69
|
+
displayName: part.inlineData.displayName,
|
|
70
|
+
data: part.inlineData.data,
|
|
71
|
+
mimeType: part.inlineData.mimeType
|
|
72
|
+
};
|
|
73
|
+
} else if (part.fileData) {
|
|
74
|
+
msg.fileData = [part.fileData];
|
|
75
|
+
} else if (part.functionCall) {
|
|
76
|
+
msg.functionCall = part.functionCall;
|
|
77
|
+
} else if (part.functionResponse) {
|
|
78
|
+
msg.functionResponse = part.functionResponse;
|
|
79
|
+
} else if (part.executableCode) {
|
|
80
|
+
msg.executableCode = part.executableCode;
|
|
81
|
+
} else if (part.codeExecutionResult) {
|
|
82
|
+
msg.codeExecutionResult = part.codeExecutionResult;
|
|
83
|
+
} else if (part.text) {
|
|
84
|
+
msg.text = part.text;
|
|
85
|
+
msg.thought = part.thought;
|
|
86
|
+
}
|
|
87
|
+
return msg;
|
|
88
|
+
};
|
|
48
89
|
var getMessageEventId = function getMessageEventId(messageItem) {
|
|
49
90
|
var _messageItem$raw;
|
|
50
91
|
return messageItem.eventId || ((_messageItem$raw = messageItem.raw) === null || _messageItem$raw === void 0 ? void 0 : _messageItem$raw.id);
|
|
@@ -60,16 +101,19 @@ var deduplicateMessages = function deduplicateMessages(messageItems) {
|
|
|
60
101
|
seenMessageIds.add(messageItem.id);
|
|
61
102
|
return true;
|
|
62
103
|
});
|
|
104
|
+
|
|
105
|
+
// 机器人文本消息去重:同一 invocationId + 思考类型的文本消息,
|
|
106
|
+
// 如果文本内容存在包含关系,保留最长的(sessionDetails 完整消息),去掉被包含的短文本(SSE 流式增量)。
|
|
107
|
+
// 使用 invocationId 分组,同一轮对话的 invocationId 始终一致, SSE 后续 chunk 的 首个id 与 sessionDetails 的 id 相同,其余不同,
|
|
63
108
|
var botTextGroups = new Map();
|
|
64
109
|
uniqueIdMessages.forEach(function (messageItem) {
|
|
65
|
-
|
|
66
|
-
if (messageItem.role !== "bot" || !eventId || typeof messageItem.text !== "string") return;
|
|
110
|
+
if (messageItem.role !== "bot" || !messageItem.invocationId || typeof messageItem.text !== "string") return;
|
|
67
111
|
var normalizedText = messageItem.text.replace(/\s+/g, " ").trim();
|
|
68
112
|
if (!normalizedText) return;
|
|
69
113
|
var fileKey = (messageItem.fileData || []).map(function (file) {
|
|
70
114
|
return file.fileUri;
|
|
71
115
|
}).join("|");
|
|
72
|
-
var groupKey = "".concat(
|
|
116
|
+
var groupKey = "".concat(messageItem.invocationId, "\0").concat(Boolean(messageItem.thought), "\0").concat(fileKey);
|
|
73
117
|
var group = botTextGroups.get(groupKey) || [];
|
|
74
118
|
group.push({
|
|
75
119
|
messageItem: messageItem,
|
|
@@ -79,6 +123,7 @@ var deduplicateMessages = function deduplicateMessages(messageItems) {
|
|
|
79
123
|
});
|
|
80
124
|
var redundantMessageIds = new Set();
|
|
81
125
|
botTextGroups.forEach(function (group) {
|
|
126
|
+
if (group.length <= 1) return;
|
|
82
127
|
var completeTexts = [];
|
|
83
128
|
_toConsumableArray(group).sort(function (a, b) {
|
|
84
129
|
return b.normalizedText.length - a.normalizedText.length;
|
|
@@ -107,6 +152,10 @@ var mapSessionMessages = function mapSessionMessages(sessionEvents) {
|
|
|
107
152
|
if (item.author === "user" && item.content.parts.some(function (part) {
|
|
108
153
|
return part.task;
|
|
109
154
|
})) return;
|
|
155
|
+
// functionResponse 的 user 事件仅用于配对 functionCall,不作为独立消息展示
|
|
156
|
+
if (item.content.role === "user" && item.content.parts.every(function (part) {
|
|
157
|
+
return !part || part.functionResponse;
|
|
158
|
+
})) return;
|
|
110
159
|
var role = (item.content.role || "").toLowerCase() === "user" ? "user" : "bot";
|
|
111
160
|
var parts = item.content.parts.filter(function (part) {
|
|
112
161
|
if (!part) return false;
|
|
@@ -122,9 +171,13 @@ var mapSessionMessages = function mapSessionMessages(sessionEvents) {
|
|
|
122
171
|
var otherParts = parts.filter(function (part) {
|
|
123
172
|
return !part.text && !part.errorMessage && !part.inlineData && !part.fileData;
|
|
124
173
|
});
|
|
174
|
+
|
|
175
|
+
// 使用确定性 ID:同一服务端事件 + 同一 part 类型始终生成相同 ID,
|
|
176
|
+
// 确保多次 mapSessionMessages 调用产生的消息可以被 id 去重正确识别。
|
|
177
|
+
var partCounter = 0;
|
|
125
178
|
if (textParts.length > 0 || fileDataParts.length > 0) {
|
|
126
179
|
var messageItem = {
|
|
127
|
-
id:
|
|
180
|
+
id: "session-event:".concat(item.id, ":").concat(partCounter++),
|
|
128
181
|
author: item.author,
|
|
129
182
|
invocationId: item.invocationId,
|
|
130
183
|
eventId: item.id,
|
|
@@ -165,7 +218,7 @@ var mapSessionMessages = function mapSessionMessages(sessionEvents) {
|
|
|
165
218
|
}
|
|
166
219
|
otherParts.forEach(function (part) {
|
|
167
220
|
var messageItem = {
|
|
168
|
-
id:
|
|
221
|
+
id: "session-event:".concat(item.id, ":").concat(partCounter++),
|
|
169
222
|
author: item.author,
|
|
170
223
|
invocationId: item.invocationId,
|
|
171
224
|
eventId: item.id,
|
|
@@ -195,62 +248,54 @@ var mapSessionMessages = function mapSessionMessages(sessionEvents) {
|
|
|
195
248
|
});
|
|
196
249
|
return mapped;
|
|
197
250
|
};
|
|
198
|
-
var
|
|
199
|
-
var _messageItem$text;
|
|
200
|
-
return JSON.stringify({
|
|
201
|
-
role: messageItem.role,
|
|
202
|
-
text: ((_messageItem$text = messageItem.text) === null || _messageItem$text === void 0 ? void 0 : _messageItem$text.replace(/\r\n/g, "\n").trim()) || "",
|
|
203
|
-
thought: Boolean(messageItem.thought),
|
|
204
|
-
inlineData: messageItem.inlineData || null,
|
|
205
|
-
fileData: messageItem.fileData || null,
|
|
206
|
-
functionCall: messageItem.functionCall || null,
|
|
207
|
-
functionResponse: messageItem.functionResponse || null,
|
|
208
|
-
executableCode: messageItem.executableCode || null,
|
|
209
|
-
codeExecutionResult: messageItem.codeExecutionResult || null
|
|
210
|
-
});
|
|
211
|
-
};
|
|
212
|
-
var isStreamMessageWithoutServerEventId = function isStreamMessageWithoutServerEventId(messageItem) {
|
|
213
|
-
var eventId = getMessageEventId(messageItem);
|
|
214
|
-
return Boolean(messageItem.invocationId) && (!eventId || eventId === messageItem.invocationId);
|
|
215
|
-
};
|
|
216
|
-
var insertMissingSessionEvents = function insertMissingSessionEvents(currentMessages, sessionEvents) {
|
|
251
|
+
var insertMissingSessionEvents = function insertMissingSessionEvents(currentMessages, sessionEvents, removedInvocationIds) {
|
|
217
252
|
var renderedEventIds = new Set(currentMessages.map(getMessageEventId).filter(Boolean));
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
253
|
+
|
|
254
|
+
// 从所有 sessionEvents 中提取 functionResponse,配对到 currentMessages 中缺少响应的 functionCall
|
|
255
|
+
// (functionResponse 事件的 role 为 user,不应作为独立消息展示,仅用于补齐工具调用状态)
|
|
256
|
+
var nextMessages = _toConsumableArray(currentMessages);
|
|
257
|
+
var fnResMap = new Map();
|
|
258
|
+
sessionEvents.forEach(function (event) {
|
|
224
259
|
var _event$content, _event$content2;
|
|
225
|
-
|
|
226
|
-
|
|
260
|
+
if (((_event$content = event.content) === null || _event$content === void 0 ? void 0 : _event$content.role) !== "user" || !Array.isArray((_event$content2 = event.content) === null || _event$content2 === void 0 ? void 0 : _event$content2.parts)) return;
|
|
261
|
+
event.content.parts.forEach(function (p) {
|
|
262
|
+
var _p$functionResponse;
|
|
263
|
+
if ((_p$functionResponse = p.functionResponse) !== null && _p$functionResponse !== void 0 && _p$functionResponse.id) {
|
|
264
|
+
fnResMap.set(p.functionResponse.id, p.functionResponse);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
if (fnResMap.size > 0) {
|
|
269
|
+
var paired = false;
|
|
270
|
+
nextMessages = nextMessages.map(function (msg) {
|
|
271
|
+
if (msg.functionCall && !msg.functionResponse) {
|
|
272
|
+
var callId = msg.functionCall.id;
|
|
273
|
+
if (callId && fnResMap.has(callId)) {
|
|
274
|
+
paired = true;
|
|
275
|
+
return _objectSpread(_objectSpread({}, msg), {}, {
|
|
276
|
+
functionResponse: fnResMap.get(callId)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return msg;
|
|
281
|
+
});
|
|
282
|
+
if (!paired) nextMessages = currentMessages;
|
|
283
|
+
}
|
|
284
|
+
var missingEvents = sessionEvents.filter(function (event) {
|
|
285
|
+
var _event$content3, _event$content4;
|
|
286
|
+
var parts = (_event$content3 = event.content) === null || _event$content3 === void 0 ? void 0 : _event$content3.parts;
|
|
287
|
+
var canRender = Boolean(event.id) && ((_event$content4 = event.content) === null || _event$content4 === void 0 ? void 0 : _event$content4.role) === "model" && Array.isArray(parts) && parts.length > 0;
|
|
227
288
|
if (!canRender || renderedEventIds.has(event.id)) return false;
|
|
228
289
|
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
// 同 invocation 下内容不同或后续出现的事件,仍然按独立 event.id 补入。
|
|
232
|
-
var eventMessages = mapSessionMessages([event]);
|
|
233
|
-
var matchedIndexes = [];
|
|
234
|
-
var isRenderedByStream = eventMessages.length > 0 && eventMessages.every(function (eventMessage) {
|
|
235
|
-
var comparableContent = getComparableMessageContent(eventMessage);
|
|
236
|
-
var matchedIndex = currentMessages.findIndex(function (currentMessage, index) {
|
|
237
|
-
return unmatchedStreamMessageIndexes.has(index) && !matchedIndexes.includes(index) && currentMessage.invocationId === eventMessage.invocationId && getComparableMessageContent(currentMessage) === comparableContent;
|
|
238
|
-
});
|
|
239
|
-
if (matchedIndex < 0) return false;
|
|
240
|
-
matchedIndexes.push(matchedIndex);
|
|
241
|
-
return true;
|
|
242
|
-
});
|
|
243
|
-
if (isRenderedByStream) {
|
|
244
|
-
matchedIndexes.forEach(function (index) {
|
|
245
|
-
return unmatchedStreamMessageIndexes.delete(index);
|
|
246
|
-
});
|
|
290
|
+
// reChat 截断后,忽略被删除的 invocationId 对应的旧 bot 消息
|
|
291
|
+
if (removedInvocationIds && removedInvocationIds.size > 0 && event.invocationId && removedInvocationIds.has(event.invocationId)) {
|
|
247
292
|
return false;
|
|
248
293
|
}
|
|
249
294
|
return true;
|
|
250
295
|
});
|
|
251
|
-
if (missingEvents.length === 0) return
|
|
296
|
+
if (missingEvents.length === 0) return nextMessages;
|
|
252
297
|
var missingMessages = mapSessionMessages(missingEvents);
|
|
253
|
-
if (missingMessages.length === 0) return
|
|
298
|
+
if (missingMessages.length === 0) return nextMessages;
|
|
254
299
|
var eventOrder = new Map(sessionEvents.map(function (event, index) {
|
|
255
300
|
return [event.id, index];
|
|
256
301
|
}));
|
|
@@ -267,7 +312,8 @@ var insertMissingSessionEvents = function insertMissingSessionEvents(currentMess
|
|
|
267
312
|
}
|
|
268
313
|
return Number.POSITIVE_INFINITY;
|
|
269
314
|
};
|
|
270
|
-
|
|
315
|
+
|
|
316
|
+
// nextMessages 已在上方 functionResponse 配对阶段创建,此处直接复用
|
|
271
317
|
missingMessages.forEach(function (messageItem) {
|
|
272
318
|
var targetOrder = getMessageOrder(messageItem);
|
|
273
319
|
var insertIndex = nextMessages.findIndex(function (currentMessage) {
|
|
@@ -290,7 +336,7 @@ function useADKChat(_ref2) {
|
|
|
290
336
|
_ref2$config = _ref2.config,
|
|
291
337
|
config = _ref2$config === void 0 ? {} : _ref2$config,
|
|
292
338
|
_ref2$type = _ref2.type,
|
|
293
|
-
|
|
339
|
+
_type = _ref2$type === void 0 ? "agentDebug" : _ref2$type,
|
|
294
340
|
_ref2$enabled = _ref2.enabled,
|
|
295
341
|
enabled = _ref2$enabled === void 0 ? true : _ref2$enabled,
|
|
296
342
|
strategies = _ref2.strategies,
|
|
@@ -366,11 +412,11 @@ function useADKChat(_ref2) {
|
|
|
366
412
|
messages = _useState20[0],
|
|
367
413
|
setMessages = _useState20[1];
|
|
368
414
|
var pendingSessionEventsRef = useRef(null);
|
|
369
|
-
var sessionEventsFlushTimerRef = useRef(null);
|
|
370
|
-
var sessionEventsSyncingRef = useRef(false);
|
|
371
415
|
var sessionDetailLoadingRef = useRef(false);
|
|
372
416
|
// 用户自定义业务参数 (stateDelta),每次发送请求时携带
|
|
373
417
|
var stateDeltaRef = useRef(undefined);
|
|
418
|
+
// reChat 截断消息时记录被删除的 invocationId,防止轮询把旧 bot 回复补回
|
|
419
|
+
var reChatRemovedInvocationIdsRef = useRef(new Set());
|
|
374
420
|
|
|
375
421
|
// ===== 多会话后台连接管理 =====
|
|
376
422
|
var backgroundRef = useRef(new Map());
|
|
@@ -378,6 +424,7 @@ function useADKChat(_ref2) {
|
|
|
378
424
|
messagesRef.current = messages;
|
|
379
425
|
var currentSessionIdRef = useRef(currentSessionId);
|
|
380
426
|
currentSessionIdRef.current = currentSessionId;
|
|
427
|
+
// 合并消息
|
|
381
428
|
var mergedMessages = useMemo(function () {
|
|
382
429
|
var fnResMap = {};
|
|
383
430
|
var uniqueMessages = deduplicateMessages(messages);
|
|
@@ -399,33 +446,23 @@ function useADKChat(_ref2) {
|
|
|
399
446
|
}, [messages]);
|
|
400
447
|
var textMsgRef = useRef(null);
|
|
401
448
|
var eventDataRef = useRef(new Map());
|
|
402
|
-
var cancelSessionEventsFlush = useCallback(function () {
|
|
403
|
-
if (sessionEventsFlushTimerRef.current === null) return;
|
|
404
|
-
clearTimeout(sessionEventsFlushTimerRef.current);
|
|
405
|
-
sessionEventsFlushTimerRef.current = null;
|
|
406
|
-
}, []);
|
|
407
449
|
var flushPendingSessionEvents = useCallback(function () {
|
|
408
450
|
var pending = pendingSessionEventsRef.current;
|
|
409
|
-
|
|
451
|
+
// 仅在用户正在发送或流式文本拼接时跳过 flush,
|
|
452
|
+
// loading 状态不应阻塞轮询补入(异步任务完成的消息需要在 loading 期间也能补入)
|
|
453
|
+
var replyInProgress = sendingRef.current || textMsgRef.current !== null;
|
|
410
454
|
if (!pending || replyInProgress || pending.sessionId !== currentSessionIdRef.current) return;
|
|
411
|
-
var previewMessages = insertMissingSessionEvents(messagesRef.current, pending.events);
|
|
412
455
|
pendingSessionEventsRef.current = null;
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
if (
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
sessionEventsSyncingRef.current = false;
|
|
426
|
-
setLoading(false);
|
|
427
|
-
}, 0);
|
|
428
|
-
}, [setLoading]);
|
|
456
|
+
|
|
457
|
+
// 使用 functional update 在同一个 setMessages 回调中完成 diff + 写入,
|
|
458
|
+
// 避免双重调用和 loading 闪烁。仅在有实际新消息时才触发 loading 状态。
|
|
459
|
+
setMessages(function (prev) {
|
|
460
|
+
var nextMessages = insertMissingSessionEvents(prev, pending.events, reChatRemovedInvocationIdsRef.current);
|
|
461
|
+
if (nextMessages === prev) return prev; // 无变化,不触发 re-render
|
|
462
|
+
messagesRef.current = nextMessages;
|
|
463
|
+
return nextMessages;
|
|
464
|
+
});
|
|
465
|
+
}, []);
|
|
429
466
|
var syncSessionEvents = useCallback(function (events, targetSessionId) {
|
|
430
467
|
if (targetSessionId !== currentSessionIdRef.current) return;
|
|
431
468
|
pendingSessionEventsRef.current = {
|
|
@@ -436,12 +473,7 @@ function useADKChat(_ref2) {
|
|
|
436
473
|
}, [flushPendingSessionEvents]);
|
|
437
474
|
useEffect(function () {
|
|
438
475
|
pendingSessionEventsRef.current = null;
|
|
439
|
-
|
|
440
|
-
if (sessionEventsSyncingRef.current) {
|
|
441
|
-
sessionEventsSyncingRef.current = false;
|
|
442
|
-
setLoading(false);
|
|
443
|
-
}
|
|
444
|
-
}, [cancelSessionEventsFlush, currentSessionId, setLoading]);
|
|
476
|
+
}, [currentSessionId]);
|
|
445
477
|
useEffect(function () {
|
|
446
478
|
if (!loading) flushPendingSessionEvents();
|
|
447
479
|
}, [flushPendingSessionEvents, loading]);
|
|
@@ -458,21 +490,21 @@ function useADKChat(_ref2) {
|
|
|
458
490
|
}, []);
|
|
459
491
|
|
|
460
492
|
// 初始化开场白预设置问题
|
|
461
|
-
var insertSuggestedQuestions = function
|
|
493
|
+
var insertSuggestedQuestions = useCallback(function () {
|
|
462
494
|
var suggested_questions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
463
495
|
if (!(suggested_questions !== null && suggested_questions !== void 0 && suggested_questions.length)) return;
|
|
464
496
|
// 无消息内容 且 有建议问题时
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
};
|
|
497
|
+
setSuggestedQuestions(function (prev) {
|
|
498
|
+
return messages.length === 0 ? suggested_questions : prev;
|
|
499
|
+
});
|
|
500
|
+
}, [messages.length]);
|
|
469
501
|
|
|
470
502
|
// 初始化开场白
|
|
471
|
-
var insertPrologue = function
|
|
472
|
-
if (
|
|
473
|
-
setPrologue(
|
|
503
|
+
var insertPrologue = useCallback(function (prologueText) {
|
|
504
|
+
if (prologueText) {
|
|
505
|
+
setPrologue(prologueText);
|
|
474
506
|
}
|
|
475
|
-
};
|
|
507
|
+
}, []);
|
|
476
508
|
|
|
477
509
|
// 更新消息
|
|
478
510
|
var updateMessage = useCallback(function (msg) {
|
|
@@ -539,48 +571,15 @@ function useADKChat(_ref2) {
|
|
|
539
571
|
|
|
540
572
|
// 存储消息
|
|
541
573
|
var storeMessage = useCallback(function (part, event, role) {
|
|
542
|
-
var
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
role: role,
|
|
550
|
-
modelCode: event.modelCode,
|
|
551
|
-
usageMetadata: event.usageMetadata,
|
|
552
|
-
finishReason: event.finishReason,
|
|
553
|
-
raw: event
|
|
554
|
-
};
|
|
555
|
-
if (part) {
|
|
556
|
-
if (part.inlineData) {
|
|
557
|
-
msg.inlineData = {
|
|
558
|
-
displayName: part.inlineData.displayName,
|
|
559
|
-
data: part.inlineData.data,
|
|
560
|
-
mimeType: part.inlineData.mimeType
|
|
561
|
-
};
|
|
562
|
-
} else if (part.text) {
|
|
563
|
-
var _event$groundingMetad;
|
|
564
|
-
msg.text = part.text;
|
|
565
|
-
msg.thought = part.thought;
|
|
566
|
-
if (event !== null && event !== void 0 && (_event$groundingMetad = event.groundingMetadata) !== null && _event$groundingMetad !== void 0 && (_event$groundingMetad = _event$groundingMetad.searchEntryPoint) !== null && _event$groundingMetad !== void 0 && _event$groundingMetad.renderedContent) {
|
|
567
|
-
msg.renderedContent = event.groundingMetadata.searchEntryPoint.renderedContent;
|
|
568
|
-
}
|
|
569
|
-
} else if (part.fileData) {
|
|
570
|
-
msg.fileData = [part.fileData];
|
|
571
|
-
} else if (part.functionCall) {
|
|
572
|
-
msg.functionCall = part.functionCall;
|
|
573
|
-
} else if (part.functionResponse) {
|
|
574
|
-
msg.functionResponse = part.functionResponse;
|
|
575
|
-
} else if (part.executableCode) {
|
|
576
|
-
msg.executableCode = part.executableCode;
|
|
577
|
-
} else if (part.codeExecutionResult) {
|
|
578
|
-
msg.codeExecutionResult = part.codeExecutionResult;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
if (part && Object.keys(part).length > 0) {
|
|
582
|
-
insertMessage(msg);
|
|
574
|
+
var _event$groundingMetad;
|
|
575
|
+
if (!part || Object.keys(part).length === 0) return;
|
|
576
|
+
var msg = buildNonTextMessage(event, part, role);
|
|
577
|
+
|
|
578
|
+
// groundingMetadata 仅在前台 SSE 场景需要
|
|
579
|
+
if (part.text && event !== null && event !== void 0 && (_event$groundingMetad = event.groundingMetadata) !== null && _event$groundingMetad !== void 0 && (_event$groundingMetad = _event$groundingMetad.searchEntryPoint) !== null && _event$groundingMetad !== void 0 && _event$groundingMetad.renderedContent) {
|
|
580
|
+
msg.renderedContent = event.groundingMetadata.searchEntryPoint.renderedContent;
|
|
583
581
|
}
|
|
582
|
+
insertMessage(msg);
|
|
584
583
|
}, [insertMessage]);
|
|
585
584
|
|
|
586
585
|
// 处理消息部分(关键更新)
|
|
@@ -639,9 +638,9 @@ function useADKChat(_ref2) {
|
|
|
639
638
|
|
|
640
639
|
// 处理建议类消息
|
|
641
640
|
var processFollowupPart = useCallback(function (event) {
|
|
642
|
-
var _event$
|
|
641
|
+
var _event$content5;
|
|
643
642
|
// 获取建议类消息的文本内容
|
|
644
|
-
var part = (event === null || event === void 0 || (_event$
|
|
643
|
+
var part = (event === null || event === void 0 || (_event$content5 = event.content) === null || _event$content5 === void 0 || (_event$content5 = _event$content5.parts) === null || _event$content5 === void 0 ? void 0 : _event$content5[0]) || null;
|
|
645
644
|
var text = (part === null || part === void 0 ? void 0 : part.text) || "";
|
|
646
645
|
storeEvents(part, event);
|
|
647
646
|
if (text) {
|
|
@@ -649,7 +648,7 @@ function useADKChat(_ref2) {
|
|
|
649
648
|
return [].concat(_toConsumableArray(prev), [text]);
|
|
650
649
|
});
|
|
651
650
|
}
|
|
652
|
-
}, [storeEvents
|
|
651
|
+
}, [storeEvents]);
|
|
653
652
|
|
|
654
653
|
// 处理错误消息
|
|
655
654
|
var processErrorMessage = useCallback(function (chunkJson) {
|
|
@@ -795,20 +794,7 @@ function useADKChat(_ref2) {
|
|
|
795
794
|
}
|
|
796
795
|
} else {
|
|
797
796
|
bgTextMsg = null;
|
|
798
|
-
|
|
799
|
-
id: v4(),
|
|
800
|
-
author: chunkJson.author,
|
|
801
|
-
invocationId: chunkJson.invocationId,
|
|
802
|
-
eventId: chunkJson.id,
|
|
803
|
-
timestamp: chunkJson.timestamp,
|
|
804
|
-
role: "bot"
|
|
805
|
-
};
|
|
806
|
-
if (part.functionCall) msg.functionCall = part.functionCall;else if (part.functionResponse) msg.functionResponse = part.functionResponse;else if (part.executableCode) msg.executableCode = part.executableCode;else if (part.codeExecutionResult) msg.codeExecutionResult = part.codeExecutionResult;else {
|
|
807
|
-
msg.text = part.text;
|
|
808
|
-
msg.thought = part.thought;
|
|
809
|
-
if (part.fileData) msg.fileData = [part.fileData];
|
|
810
|
-
}
|
|
811
|
-
bg.messages = [].concat(_toConsumableArray(bg.messages), [msg]);
|
|
797
|
+
bg.messages = [].concat(_toConsumableArray(bg.messages), [buildNonTextMessage(chunkJson, part)]);
|
|
812
798
|
}
|
|
813
799
|
}
|
|
814
800
|
} catch (err) {
|
|
@@ -843,7 +829,7 @@ function useADKChat(_ref2) {
|
|
|
843
829
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
844
830
|
var _chunkJson2;
|
|
845
831
|
var _part = _step3.value;
|
|
846
|
-
// partial为
|
|
832
|
+
// partial为 false 时忽略该条消息文本
|
|
847
833
|
processPart(chunkJson, _part, ((_chunkJson2 = chunkJson) === null || _chunkJson2 === void 0 ? void 0 : _chunkJson2.partial) === false);
|
|
848
834
|
}
|
|
849
835
|
} catch (err) {
|
|
@@ -865,6 +851,12 @@ function useADKChat(_ref2) {
|
|
|
865
851
|
bg.loading = false;
|
|
866
852
|
bg.textMsgRef = null;
|
|
867
853
|
}
|
|
854
|
+
// 如果该后台会话已被恢复到前台(backgroundRef 中已删除),
|
|
855
|
+
// 需要更新前台 loading 状态
|
|
856
|
+
if (!backgroundRef.current.has(targetSessionId) && currentSessionIdRef.current === targetSessionId) {
|
|
857
|
+
setLoading(false);
|
|
858
|
+
textMsgRef.current = null;
|
|
859
|
+
}
|
|
868
860
|
} else {
|
|
869
861
|
setLoading(false);
|
|
870
862
|
if (textMsgRef.current) {
|
|
@@ -872,6 +864,7 @@ function useADKChat(_ref2) {
|
|
|
872
864
|
onMessage === null || onMessage === void 0 || onMessage(((_textMsgRef$current = textMsgRef.current) === null || _textMsgRef$current === void 0 ? void 0 : _textMsgRef$current.text) || "", textMsgRef.current);
|
|
873
865
|
}
|
|
874
866
|
textMsgRef.current = null;
|
|
867
|
+
ctrl.current = null;
|
|
875
868
|
}
|
|
876
869
|
resolve();
|
|
877
870
|
},
|
|
@@ -880,8 +873,14 @@ function useADKChat(_ref2) {
|
|
|
880
873
|
if (isBackground) {
|
|
881
874
|
var bg = backgroundRef.current.get(targetSessionId);
|
|
882
875
|
if (bg) bg.loading = false;
|
|
876
|
+
// 同上:后台会话已恢复到前台时同步 loading 状态
|
|
877
|
+
if (!backgroundRef.current.has(targetSessionId) && currentSessionIdRef.current === targetSessionId) {
|
|
878
|
+
setLoading(false);
|
|
879
|
+
ctrl.current = null;
|
|
880
|
+
}
|
|
883
881
|
} else {
|
|
884
882
|
setLoading(false);
|
|
883
|
+
ctrl.current = null;
|
|
885
884
|
}
|
|
886
885
|
resolve();
|
|
887
886
|
console.error("EventSource failed:", error);
|
|
@@ -889,7 +888,7 @@ function useADKChat(_ref2) {
|
|
|
889
888
|
}
|
|
890
889
|
});
|
|
891
890
|
});
|
|
892
|
-
}, [
|
|
891
|
+
}, [processActionArtifact, processErrorMessage, processPart, updateLastBotEventMeta]);
|
|
893
892
|
|
|
894
893
|
// 发送会话
|
|
895
894
|
var startChat = /*#__PURE__*/function () {
|
|
@@ -914,6 +913,8 @@ function useADKChat(_ref2) {
|
|
|
914
913
|
sendingRef.current = true;
|
|
915
914
|
// 清空建议问题
|
|
916
915
|
setSuggestedQuestions([]);
|
|
916
|
+
// 正常发送时重置 reChat 删除标记
|
|
917
|
+
reChatRemovedInvocationIdsRef.current = new Set();
|
|
917
918
|
// 发送消息
|
|
918
919
|
setMessages(function (prev) {
|
|
919
920
|
var temp = _toConsumableArray(prev);
|
|
@@ -950,8 +951,8 @@ function useADKChat(_ref2) {
|
|
|
950
951
|
}
|
|
951
952
|
return temp;
|
|
952
953
|
});
|
|
953
|
-
_context2.prev =
|
|
954
|
-
_context2.next =
|
|
954
|
+
_context2.prev = 9;
|
|
955
|
+
_context2.next = 12;
|
|
955
956
|
return sendMessageRequest(_objectSpread({
|
|
956
957
|
stream: true,
|
|
957
958
|
sessionId: currentSessionId,
|
|
@@ -976,18 +977,18 @@ function useADKChat(_ref2) {
|
|
|
976
977
|
}, stateDeltaRef.current !== undefined && {
|
|
977
978
|
stateDelta: stateDeltaRef.current
|
|
978
979
|
}));
|
|
979
|
-
case
|
|
980
|
-
_context2.prev =
|
|
980
|
+
case 12:
|
|
981
|
+
_context2.prev = 12;
|
|
981
982
|
sendingRef.current = false;
|
|
982
|
-
return _context2.finish(
|
|
983
|
-
case
|
|
983
|
+
return _context2.finish(12);
|
|
984
|
+
case 15:
|
|
984
985
|
// 获取聊天记录
|
|
985
986
|
initAppConversations();
|
|
986
|
-
case
|
|
987
|
+
case 16:
|
|
987
988
|
case "end":
|
|
988
989
|
return _context2.stop();
|
|
989
990
|
}
|
|
990
|
-
}, _callee2, null, [[
|
|
991
|
+
}, _callee2, null, [[9,, 12, 15]]);
|
|
991
992
|
}));
|
|
992
993
|
return function startChat(_x) {
|
|
993
994
|
return _ref5.apply(this, arguments);
|
|
@@ -997,7 +998,7 @@ function useADKChat(_ref2) {
|
|
|
997
998
|
// 重新发送会话
|
|
998
999
|
var reChat = /*#__PURE__*/function () {
|
|
999
1000
|
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
|
|
1000
|
-
var lastUserIndex, newMessages, lastUserMessage, _lastUserMessage$text, text, _lastUserMessage$file, fileData;
|
|
1001
|
+
var lastUserIndex, newMessages, removedInvocationIds, i, msg, lastUserMessage, _lastUserMessage$text, text, _lastUserMessage$file, fileData;
|
|
1001
1002
|
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
|
1002
1003
|
while (1) switch (_context3.prev = _context3.next) {
|
|
1003
1004
|
case 0:
|
|
@@ -1030,10 +1031,18 @@ function useADKChat(_ref2) {
|
|
|
1030
1031
|
case 10:
|
|
1031
1032
|
newMessages = messages.slice(0, lastUserIndex + 1);
|
|
1032
1033
|
setMessages(newMessages);
|
|
1034
|
+
|
|
1035
|
+
// 收集被截断的 bot 消息的 invocationId,轮询时忽略这些旧回复
|
|
1036
|
+
removedInvocationIds = new Set();
|
|
1037
|
+
for (i = lastUserIndex + 1; i < messages.length; i++) {
|
|
1038
|
+
msg = messages[i];
|
|
1039
|
+
if (msg.invocationId) removedInvocationIds.add(msg.invocationId);
|
|
1040
|
+
}
|
|
1041
|
+
reChatRemovedInvocationIdsRef.current = removedInvocationIds;
|
|
1033
1042
|
lastUserMessage = newMessages[lastUserIndex];
|
|
1034
1043
|
_lastUserMessage$text = lastUserMessage.text, text = _lastUserMessage$text === void 0 ? "" : _lastUserMessage$text, _lastUserMessage$file = lastUserMessage.fileData, fileData = _lastUserMessage$file === void 0 ? [] : _lastUserMessage$file;
|
|
1035
|
-
_context3.prev =
|
|
1036
|
-
_context3.next =
|
|
1044
|
+
_context3.prev = 17;
|
|
1045
|
+
_context3.next = 20;
|
|
1037
1046
|
return sendMessageRequest(_objectSpread({
|
|
1038
1047
|
stream: true,
|
|
1039
1048
|
sessionId: currentSessionId,
|
|
@@ -1053,15 +1062,15 @@ function useADKChat(_ref2) {
|
|
|
1053
1062
|
}, stateDeltaRef.current !== undefined && {
|
|
1054
1063
|
stateDelta: stateDeltaRef.current
|
|
1055
1064
|
}));
|
|
1056
|
-
case 17:
|
|
1057
|
-
_context3.prev = 17;
|
|
1058
|
-
sendingRef.current = false;
|
|
1059
|
-
return _context3.finish(17);
|
|
1060
1065
|
case 20:
|
|
1066
|
+
_context3.prev = 20;
|
|
1067
|
+
sendingRef.current = false;
|
|
1068
|
+
return _context3.finish(20);
|
|
1069
|
+
case 23:
|
|
1061
1070
|
case "end":
|
|
1062
1071
|
return _context3.stop();
|
|
1063
1072
|
}
|
|
1064
|
-
}, _callee3, null, [[
|
|
1073
|
+
}, _callee3, null, [[17,, 20, 23]]);
|
|
1065
1074
|
}));
|
|
1066
1075
|
return function reChat() {
|
|
1067
1076
|
return _ref6.apply(this, arguments);
|
|
@@ -1097,19 +1106,19 @@ function useADKChat(_ref2) {
|
|
|
1097
1106
|
var stopChat = useCallback(function () {
|
|
1098
1107
|
var _ctrl$current;
|
|
1099
1108
|
pendingSessionEventsRef.current = null;
|
|
1100
|
-
cancelSessionEventsFlush();
|
|
1101
|
-
sessionEventsSyncingRef.current = false;
|
|
1102
1109
|
(_ctrl$current = ctrl.current) === null || _ctrl$current === void 0 || _ctrl$current.abort();
|
|
1103
1110
|
ctrl.current = null;
|
|
1104
1111
|
setLoading(false);
|
|
1105
1112
|
textMsgRef.current = null;
|
|
1106
|
-
}, [
|
|
1113
|
+
}, [setLoading]);
|
|
1107
1114
|
|
|
1108
1115
|
// 清除/重置会话
|
|
1109
1116
|
var clearChat = function clearChat() {
|
|
1110
1117
|
var _appInfo$onboardingIn, _appInfo$onboardingIn2;
|
|
1111
1118
|
var newSessionId = v4();
|
|
1112
1119
|
setCurrentSessionId(newSessionId);
|
|
1120
|
+
// 清除 reChat 删除标记
|
|
1121
|
+
reChatRemovedInvocationIdsRef.current = new Set();
|
|
1113
1122
|
// 重置聊天内容
|
|
1114
1123
|
stopChat();
|
|
1115
1124
|
setPrologue((appInfo === null || appInfo === void 0 || (_appInfo$onboardingIn = appInfo.onboardingInfo) === null || _appInfo$onboardingIn === void 0 ? void 0 : _appInfo$onboardingIn.prologue) || "");
|
|
@@ -1129,12 +1138,12 @@ function useADKChat(_ref2) {
|
|
|
1129
1138
|
// 设置当前会话详情
|
|
1130
1139
|
var setCurrentSession = /*#__PURE__*/function () {
|
|
1131
1140
|
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(sessionId) {
|
|
1132
|
-
var prevSessionId, bg, _yield$fetchSessionDe, data, result, _appInfo$onboardingIn3, _appInfo$onboardingIn4;
|
|
1141
|
+
var prevSessionId, bg, isSseStillActive, _yield$fetchSessionDe, data, result, _appInfo$onboardingIn3, _appInfo$onboardingIn4;
|
|
1133
1142
|
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
|
1134
1143
|
while (1) switch (_context4.prev = _context4.next) {
|
|
1135
1144
|
case 0:
|
|
1136
1145
|
if (!sessionId) {
|
|
1137
|
-
_context4.next =
|
|
1146
|
+
_context4.next = 35;
|
|
1138
1147
|
break;
|
|
1139
1148
|
}
|
|
1140
1149
|
if (!(sessionId === currentSessionId)) {
|
|
@@ -1144,11 +1153,8 @@ function useADKChat(_ref2) {
|
|
|
1144
1153
|
return _context4.abrupt("return");
|
|
1145
1154
|
case 3:
|
|
1146
1155
|
pendingSessionEventsRef.current = null;
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
sessionEventsSyncingRef.current = false;
|
|
1150
|
-
setLoading(false);
|
|
1151
|
-
}
|
|
1156
|
+
// 切换会话时重置 reChat 删除标记
|
|
1157
|
+
reChatRemovedInvocationIdsRef.current = new Set();
|
|
1152
1158
|
|
|
1153
1159
|
// 1. 将当前会话挂起到后台(不中断 SSE 连接)
|
|
1154
1160
|
prevSessionId = currentSessionId;
|
|
@@ -1176,31 +1182,35 @@ function useADKChat(_ref2) {
|
|
|
1176
1182
|
// 2. 尝试从后台恢复目标会话
|
|
1177
1183
|
bg = backgroundRef.current.get(sessionId);
|
|
1178
1184
|
if (!bg) {
|
|
1179
|
-
_context4.next =
|
|
1185
|
+
_context4.next = 19;
|
|
1180
1186
|
break;
|
|
1181
1187
|
}
|
|
1182
1188
|
setMessages(bg.messages);
|
|
1183
|
-
|
|
1189
|
+
messagesRef.current = bg.messages;
|
|
1184
1190
|
textMsgRef.current = bg.textMsgRef;
|
|
1185
|
-
|
|
1191
|
+
// 仅当 SSE 连接还在运行时才恢复 loading 状态,
|
|
1192
|
+
// 避免 SSE 已关闭但 bg 快照中 loading 仍为 true 导致 sender 永久卡住
|
|
1193
|
+
isSseStillActive = bg.loading && !bg.ctrl.signal.aborted;
|
|
1194
|
+
setLoading(isSseStillActive);
|
|
1195
|
+
ctrl.current = isSseStillActive ? bg.ctrl : null;
|
|
1186
1196
|
setCurrentSessionId(sessionId);
|
|
1187
1197
|
setInitialized(true);
|
|
1188
1198
|
backgroundRef.current.delete(sessionId);
|
|
1189
1199
|
return _context4.abrupt("return");
|
|
1190
|
-
case
|
|
1200
|
+
case 19:
|
|
1191
1201
|
// 3. 后台没有目标 session,走 API 加载(原有逻辑)
|
|
1192
1202
|
setInitialized(false);
|
|
1193
1203
|
setCurrentSessionId(sessionId);
|
|
1194
1204
|
sessionDetailLoadingRef.current = true;
|
|
1195
|
-
_context4.prev =
|
|
1196
|
-
_context4.next =
|
|
1205
|
+
_context4.prev = 22;
|
|
1206
|
+
_context4.next = 25;
|
|
1197
1207
|
return fetchSessionDetail({
|
|
1198
1208
|
url: url,
|
|
1199
1209
|
appNo: appNo,
|
|
1200
1210
|
sessionId: sessionId,
|
|
1201
1211
|
token: tokenRef.current
|
|
1202
1212
|
});
|
|
1203
|
-
case
|
|
1213
|
+
case 25:
|
|
1204
1214
|
_yield$fetchSessionDe = _context4.sent;
|
|
1205
1215
|
data = _yield$fetchSessionDe.data;
|
|
1206
1216
|
result = _yield$fetchSessionDe.result;
|
|
@@ -1212,21 +1222,21 @@ function useADKChat(_ref2) {
|
|
|
1212
1222
|
setSuggestedQuestions((appInfo === null || appInfo === void 0 || (_appInfo$onboardingIn4 = appInfo.onboardingInfo) === null || _appInfo$onboardingIn4 === void 0 ? void 0 : _appInfo$onboardingIn4.suggested_questions) || []);
|
|
1213
1223
|
}
|
|
1214
1224
|
}
|
|
1215
|
-
case
|
|
1216
|
-
_context4.prev =
|
|
1225
|
+
case 29:
|
|
1226
|
+
_context4.prev = 29;
|
|
1217
1227
|
sessionDetailLoadingRef.current = false;
|
|
1218
1228
|
setInitialized(true);
|
|
1219
|
-
return _context4.finish(
|
|
1220
|
-
case
|
|
1221
|
-
_context4.next =
|
|
1229
|
+
return _context4.finish(29);
|
|
1230
|
+
case 33:
|
|
1231
|
+
_context4.next = 36;
|
|
1222
1232
|
break;
|
|
1223
|
-
case 34:
|
|
1224
|
-
setCurrentSessionId(v4());
|
|
1225
1233
|
case 35:
|
|
1234
|
+
setCurrentSessionId(v4());
|
|
1235
|
+
case 36:
|
|
1226
1236
|
case "end":
|
|
1227
1237
|
return _context4.stop();
|
|
1228
1238
|
}
|
|
1229
|
-
}, _callee4, null, [[
|
|
1239
|
+
}, _callee4, null, [[22,, 29, 33]]);
|
|
1230
1240
|
}));
|
|
1231
1241
|
return function setCurrentSession(_x2) {
|
|
1232
1242
|
return _ref7.apply(this, arguments);
|
|
@@ -1561,7 +1571,7 @@ function useADKChat(_ref2) {
|
|
|
1561
1571
|
return _regeneratorRuntime().wrap(function _callee10$(_context10) {
|
|
1562
1572
|
while (1) switch (_context10.prev = _context10.next) {
|
|
1563
1573
|
case 0:
|
|
1564
|
-
if (!(requesting || sessionDetailLoadingRef.current)) {
|
|
1574
|
+
if (!(disposed || requesting || sessionDetailLoadingRef.current)) {
|
|
1565
1575
|
_context10.next = 2;
|
|
1566
1576
|
break;
|
|
1567
1577
|
}
|
|
@@ -1602,7 +1612,8 @@ function useADKChat(_ref2) {
|
|
|
1602
1612
|
return _ref13.apply(this, arguments);
|
|
1603
1613
|
};
|
|
1604
1614
|
}();
|
|
1605
|
-
|
|
1615
|
+
|
|
1616
|
+
// 不立即执行首次 poll,避免与 initAppConversations / setCurrentSession / fetchSessionDetail 竞争。首次数据由初始化流程加载,轮询仅负责后续增量同步。
|
|
1606
1617
|
var timer = window.setInterval(poll, sessionEventsPollingInterval);
|
|
1607
1618
|
return function () {
|
|
1608
1619
|
disposed = true;
|
|
@@ -1614,7 +1625,6 @@ function useADKChat(_ref2) {
|
|
|
1614
1625
|
useEffect(function () {
|
|
1615
1626
|
return function () {
|
|
1616
1627
|
var _ctrl$current2;
|
|
1617
|
-
cancelSessionEventsFlush();
|
|
1618
1628
|
(_ctrl$current2 = ctrl.current) === null || _ctrl$current2 === void 0 || _ctrl$current2.abort();
|
|
1619
1629
|
backgroundRef.current.forEach(function (bg) {
|
|
1620
1630
|
var _bg$ctrl;
|
|
@@ -1622,7 +1632,7 @@ function useADKChat(_ref2) {
|
|
|
1622
1632
|
});
|
|
1623
1633
|
backgroundRef.current.clear();
|
|
1624
1634
|
};
|
|
1625
|
-
}, [
|
|
1635
|
+
}, []);
|
|
1626
1636
|
return {
|
|
1627
1637
|
appInfo: appInfo,
|
|
1628
1638
|
startChat: startChat,
|