@ai-group/chat-sdk 3.5.0 → 3.5.1

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.
@@ -44,6 +44,9 @@ var combineTextParts = function combineTextParts(parts) {
44
44
  }
45
45
  return result;
46
46
  };
47
+
48
+ // 后台会话连接状态
49
+
47
50
  function useADKChat(_ref) {
48
51
  var _ref$url = _ref.url,
49
52
  url = _ref$url === void 0 ? window.location.origin : _ref$url,
@@ -119,6 +122,13 @@ function useADKChat(_ref) {
119
122
  setMessages = _useState20[1];
120
123
  // 用户自定义业务参数 (stateDelta),每次发送请求时携带
121
124
  var stateDeltaRef = useRef(undefined);
125
+
126
+ // ===== 多会话后台连接管理 =====
127
+ var backgroundRef = useRef(new Map());
128
+ var messagesRef = useRef(messages);
129
+ messagesRef.current = messages;
130
+ var currentSessionIdRef = useRef(currentSessionId);
131
+ currentSessionIdRef.current = currentSessionId;
122
132
  var mergedMessages = useMemo(function () {
123
133
  var fnResMap = {};
124
134
  messages.forEach(function (msg) {
@@ -366,15 +376,24 @@ function useADKChat(_ref) {
366
376
  // 发送消息请求
367
377
  var sendMessageRequest = useCallback(function (values) {
368
378
  return new Promise(function (resolve) {
369
- if (ctrl.current) {
379
+ var targetSessionId = values.sessionId || currentSessionIdRef.current;
380
+
381
+ // 只 abort 同一 session 的旧连接
382
+ if (targetSessionId === currentSessionIdRef.current && ctrl.current) {
370
383
  ctrl.current.abort();
371
384
  }
372
- setLoading(true);
373
- ctrl.current = new AbortController();
385
+ var newCtrl = new AbortController();
386
+ if (targetSessionId === currentSessionIdRef.current) {
387
+ setLoading(true);
388
+ ctrl.current = newCtrl;
389
+ }
374
390
  var requestUrl = "".concat(url, "/api/gateway-web/openApi/v1/aizt/app/").concat(appNo, "/sendMsgStreaming");
391
+
392
+ // 后台流式文本拼接
393
+ var bgTextMsg = null;
375
394
  fetchEventSource(requestUrl, {
376
395
  method: "POST",
377
- signal: ctrl.current.signal,
396
+ signal: newCtrl.signal,
378
397
  body: JSON.stringify(values),
379
398
  openWhenHidden: true,
380
399
  headers: {
@@ -418,7 +437,6 @@ function useADKChat(_ref) {
418
437
  // 转换为旧格式
419
438
  chunkJson = _objectSpread(_objectSpread({}, rawData.data), {}, {
420
439
  content: rawData.data,
421
- // data 本身就是 content
422
440
  invocationId: rawData.result.invocationId,
423
441
  sessionId: rawData.result.sessionId,
424
442
  id: rawData.result.invocationId
@@ -428,6 +446,84 @@ function useADKChat(_ref) {
428
446
  message.warning(chunkJson.error);
429
447
  return;
430
448
  }
449
+
450
+ // 判断是否为后台 session
451
+ var isBackground = currentSessionIdRef.current !== targetSessionId;
452
+ if (isBackground) {
453
+ // 后台 session:更新 backgroundRef 中的消息
454
+ var bg = backgroundRef.current.get(targetSessionId);
455
+ if (!bg) return;
456
+ if (chunkJson.content) {
457
+ if (chunkJson.content.role === "followup") return;
458
+ var _iterator2 = _createForOfIteratorHelper(combineTextParts(chunkJson.content.parts)),
459
+ _step2;
460
+ try {
461
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
462
+ var part = _step2.value;
463
+ var isPureText = part.text && !part.fileData;
464
+ if (isPureText) {
465
+ var _chunkJson, _bgTextMsg;
466
+ if (((_chunkJson = chunkJson) === null || _chunkJson === void 0 ? void 0 : _chunkJson.partial) === false) continue;
467
+ var newChunk = part.text || "";
468
+ if (!bgTextMsg || ((_bgTextMsg = bgTextMsg) === null || _bgTextMsg === void 0 ? void 0 : _bgTextMsg.thought) !== part.thought) {
469
+ var newMessage = {
470
+ id: v4(),
471
+ author: chunkJson.author,
472
+ invocationId: chunkJson.invocationId,
473
+ eventId: chunkJson.id,
474
+ timestamp: chunkJson.timestamp,
475
+ role: "bot",
476
+ text: newChunk,
477
+ thought: part.thought
478
+ };
479
+ bgTextMsg = newMessage;
480
+ bg.messages = [].concat(_toConsumableArray(bg.messages), [newMessage]);
481
+ } else {
482
+ bgTextMsg = _objectSpread(_objectSpread({}, bgTextMsg), {}, {
483
+ text: (bgTextMsg.text || "") + newChunk
484
+ });
485
+ bg.messages = bg.messages.map(function (m) {
486
+ return m.id === bgTextMsg.id ? bgTextMsg : m;
487
+ });
488
+ if (chunkJson.finishReason === "stop") {
489
+ bgTextMsg = null;
490
+ }
491
+ }
492
+ } else {
493
+ bgTextMsg = null;
494
+ var msg = {
495
+ id: v4(),
496
+ author: chunkJson.author,
497
+ invocationId: chunkJson.invocationId,
498
+ eventId: chunkJson.id,
499
+ timestamp: chunkJson.timestamp,
500
+ role: "bot"
501
+ };
502
+ 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 {
503
+ msg.text = part.text;
504
+ msg.thought = part.thought;
505
+ if (part.fileData) msg.fileData = [part.fileData];
506
+ }
507
+ bg.messages = [].concat(_toConsumableArray(bg.messages), [msg]);
508
+ }
509
+ }
510
+ } catch (err) {
511
+ _iterator2.e(err);
512
+ } finally {
513
+ _iterator2.f();
514
+ }
515
+ } else if (chunkJson.errorMessage) {
516
+ bg.messages = [].concat(_toConsumableArray(bg.messages), [{
517
+ id: v4(),
518
+ text: chunkJson.errorMessage,
519
+ role: "bot"
520
+ }]);
521
+ }
522
+ bg.textMsgRef = bgTextMsg;
523
+ return;
524
+ }
525
+
526
+ // 前台 session:正常处理
431
527
  onStream === null || onStream === void 0 || onStream(chunkJson);
432
528
  updateLastBotEventMeta(chunkJson);
433
529
  if (chunkJson.content) {
@@ -437,19 +533,19 @@ function useADKChat(_ref) {
437
533
  return;
438
534
  }
439
535
  // eslint-disable-next-line no-restricted-syntax
440
- var _iterator2 = _createForOfIteratorHelper(combineTextParts(chunkJson.content.parts)),
441
- _step2;
536
+ var _iterator3 = _createForOfIteratorHelper(combineTextParts(chunkJson.content.parts)),
537
+ _step3;
442
538
  try {
443
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
444
- var _chunkJson;
445
- var part = _step2.value;
539
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
540
+ var _chunkJson2;
541
+ var _part = _step3.value;
446
542
  // partial为 true 时忽略该条消息文本
447
- processPart(chunkJson, part, ((_chunkJson = chunkJson) === null || _chunkJson === void 0 ? void 0 : _chunkJson.partial) === false);
543
+ processPart(chunkJson, _part, ((_chunkJson2 = chunkJson) === null || _chunkJson2 === void 0 ? void 0 : _chunkJson2.partial) === false);
448
544
  }
449
545
  } catch (err) {
450
- _iterator2.e(err);
546
+ _iterator3.e(err);
451
547
  } finally {
452
- _iterator2.f();
548
+ _iterator3.f();
453
549
  }
454
550
  } else if (chunkJson.errorMessage) {
455
551
  processErrorMessage(chunkJson);
@@ -458,16 +554,31 @@ function useADKChat(_ref) {
458
554
  }
459
555
  },
460
556
  onclose: function onclose() {
461
- setLoading(false);
462
- if (textMsgRef.current) {
463
- var _textMsgRef$current;
464
- onMessage === null || onMessage === void 0 || onMessage(((_textMsgRef$current = textMsgRef.current) === null || _textMsgRef$current === void 0 ? void 0 : _textMsgRef$current.text) || "", textMsgRef.current);
557
+ var isBackground = currentSessionIdRef.current !== targetSessionId;
558
+ if (isBackground) {
559
+ var bg = backgroundRef.current.get(targetSessionId);
560
+ if (bg) {
561
+ bg.loading = false;
562
+ bg.textMsgRef = null;
563
+ }
564
+ } else {
565
+ setLoading(false);
566
+ if (textMsgRef.current) {
567
+ var _textMsgRef$current;
568
+ onMessage === null || onMessage === void 0 || onMessage(((_textMsgRef$current = textMsgRef.current) === null || _textMsgRef$current === void 0 ? void 0 : _textMsgRef$current.text) || "", textMsgRef.current);
569
+ }
570
+ textMsgRef.current = null;
465
571
  }
466
- textMsgRef.current = null;
467
572
  resolve();
468
573
  },
469
574
  onerror: function onerror(error) {
470
- setLoading(false);
575
+ var isBackground = currentSessionIdRef.current !== targetSessionId;
576
+ if (isBackground) {
577
+ var bg = backgroundRef.current.get(targetSessionId);
578
+ if (bg) bg.loading = false;
579
+ } else {
580
+ setLoading(false);
581
+ }
471
582
  resolve();
472
583
  console.error("EventSource failed:", error);
473
584
  throw error;
@@ -678,13 +789,14 @@ function useADKChat(_ref) {
678
789
  });
679
790
  };
680
791
 
681
- // 停止会话
792
+ // 停止会话(只中断前台连接)
682
793
  var stopChat = useCallback(function () {
683
794
  var _ctrl$current;
684
795
  (_ctrl$current = ctrl.current) === null || _ctrl$current === void 0 || _ctrl$current.abort();
796
+ ctrl.current = null;
685
797
  setLoading(false);
686
798
  textMsgRef.current = null;
687
- }, [ctrl]);
799
+ }, []);
688
800
 
689
801
  // 清除/重置会话
690
802
  var clearChat = function clearChat() {
@@ -737,11 +849,11 @@ function useADKChat(_ref) {
737
849
  finishReason: item.finishReason,
738
850
  raw: item
739
851
  };
740
- var _iterator3 = _createForOfIteratorHelper(textParts),
741
- _step3;
852
+ var _iterator4 = _createForOfIteratorHelper(textParts),
853
+ _step4;
742
854
  try {
743
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
744
- var part = _step3.value;
855
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
856
+ var part = _step4.value;
745
857
  if (part.inlineData) {
746
858
  msg.inlineData = {
747
859
  displayName: part.inlineData.displayName,
@@ -758,9 +870,9 @@ function useADKChat(_ref) {
758
870
  }
759
871
  }
760
872
  } catch (err) {
761
- _iterator3.e(err);
873
+ _iterator4.e(err);
762
874
  } finally {
763
- _iterator3.f();
875
+ _iterator4.f();
764
876
  }
765
877
  if (fileDataParts.length > 0) {
766
878
  msg.fileData = fileDataParts.map(function (part) {
@@ -815,12 +927,12 @@ function useADKChat(_ref) {
815
927
  // 设置当前会话详情
816
928
  var setCurrentSession = /*#__PURE__*/function () {
817
929
  var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(sessionId) {
818
- var _yield$fetchSessionDe, data, result, _appInfo$onboardingIn3, _appInfo$onboardingIn4;
930
+ var prevSessionId, bg, _yield$fetchSessionDe, data, result, _appInfo$onboardingIn3, _appInfo$onboardingIn4;
819
931
  return _regeneratorRuntime().wrap(function _callee4$(_context4) {
820
932
  while (1) switch (_context4.prev = _context4.next) {
821
933
  case 0:
822
934
  if (!sessionId) {
823
- _context4.next = 15;
935
+ _context4.next = 26;
824
936
  break;
825
937
  }
826
938
  if (!(sessionId === currentSessionId)) {
@@ -829,39 +941,72 @@ function useADKChat(_ref) {
829
941
  }
830
942
  return _context4.abrupt("return");
831
943
  case 3:
832
- // 切换会话时,abort 当前流式请求,防止数据污染和 loading 状态泄漏
833
- stopChat();
834
- // 重置 initialized 以便 XAdkChatbot 能重新触发置底滚动
944
+ // 1. 将当前会话挂起到后台(不中断 SSE 连接)
945
+ prevSessionId = currentSessionId;
946
+ if (ctrl.current) {
947
+ // 有活跃流式连接,保存到后台
948
+ backgroundRef.current.set(prevSessionId, {
949
+ ctrl: ctrl.current,
950
+ messages: _toConsumableArray(messagesRef.current),
951
+ loading: true,
952
+ textMsgRef: textMsgRef.current
953
+ });
954
+ ctrl.current = null;
955
+ textMsgRef.current = null;
956
+ setLoading(false);
957
+ } else if (messagesRef.current.length > 0) {
958
+ // 无活跃连接但有消息,缓存用于切回
959
+ backgroundRef.current.set(prevSessionId, {
960
+ ctrl: new AbortController(),
961
+ messages: _toConsumableArray(messagesRef.current),
962
+ loading: false,
963
+ textMsgRef: null
964
+ });
965
+ }
966
+
967
+ // 2. 尝试从后台恢复目标会话
968
+ bg = backgroundRef.current.get(sessionId);
969
+ if (!bg) {
970
+ _context4.next = 15;
971
+ break;
972
+ }
973
+ setMessages(bg.messages);
974
+ setLoading(bg.loading);
975
+ textMsgRef.current = bg.textMsgRef;
976
+ ctrl.current = bg.loading ? bg.ctrl : null;
977
+ setCurrentSessionId(sessionId);
978
+ setInitialized(true);
979
+ backgroundRef.current.delete(sessionId);
980
+ return _context4.abrupt("return");
981
+ case 15:
982
+ // 3. 后台没有目标 session,走 API 加载(原有逻辑)
835
983
  setInitialized(false);
836
- setCurrentSessionId(sessionId); // 设置当前会话 id;
837
- _context4.next = 8;
984
+ setCurrentSessionId(sessionId);
985
+ _context4.next = 19;
838
986
  return fetchSessionDetail({
839
987
  url: url,
840
988
  appNo: appNo,
841
989
  sessionId: sessionId,
842
990
  token: token
843
991
  });
844
- case 8:
992
+ case 19:
845
993
  _yield$fetchSessionDe = _context4.sent;
846
994
  data = _yield$fetchSessionDe.data;
847
995
  result = _yield$fetchSessionDe.result;
848
996
  if ((result === null || result === void 0 ? void 0 : result.code) === API_SUCCESS_CODE) {
849
997
  setPrologue((appInfo === null || appInfo === void 0 || (_appInfo$onboardingIn3 = appInfo.onboardingInfo) === null || _appInfo$onboardingIn3 === void 0 ? void 0 : _appInfo$onboardingIn3.prologue) || "");
850
- // 新接口直接返回按 event/item 结构的数组,传入 formatMessages 处理
851
998
  if (Array.isArray(data) && data.length > 0) {
852
999
  formatMessages(data, true);
853
1000
  } else {
854
1001
  setSuggestedQuestions((appInfo === null || appInfo === void 0 || (_appInfo$onboardingIn4 = appInfo.onboardingInfo) === null || _appInfo$onboardingIn4 === void 0 ? void 0 : _appInfo$onboardingIn4.suggested_questions) || []);
855
1002
  }
856
1003
  }
857
- // 恢复 initialized,触发 XAdkChatbot 的初始化置底逻辑
858
1004
  setInitialized(true);
859
- _context4.next = 16;
1005
+ _context4.next = 27;
860
1006
  break;
861
- case 15:
862
- // 兼容 无 session异常
1007
+ case 26:
863
1008
  setCurrentSessionId(v4());
864
- case 16:
1009
+ case 27:
865
1010
  case "end":
866
1011
  return _context4.stop();
867
1012
  }
@@ -1179,6 +1324,19 @@ function useADKChat(_ref) {
1179
1324
  initAppConversations(true);
1180
1325
  }
1181
1326
  }, [appInfo]);
1327
+
1328
+ // 组件卸载时清理所有连接(前台 + 后台)
1329
+ useEffect(function () {
1330
+ return function () {
1331
+ var _ctrl$current2;
1332
+ (_ctrl$current2 = ctrl.current) === null || _ctrl$current2 === void 0 || _ctrl$current2.abort();
1333
+ backgroundRef.current.forEach(function (bg) {
1334
+ var _bg$ctrl;
1335
+ return (_bg$ctrl = bg.ctrl) === null || _bg$ctrl === void 0 ? void 0 : _bg$ctrl.abort();
1336
+ });
1337
+ backgroundRef.current.clear();
1338
+ };
1339
+ }, []);
1182
1340
  return {
1183
1341
  appInfo: appInfo,
1184
1342
  startChat: startChat,