@glodon-aiot/chat-app-sdk 0.0.15 → 0.0.16

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/es/index.esm.js CHANGED
@@ -267864,6 +267864,43 @@ class PreSendLocalMessageFactory {
267864
267864
  }
267865
267865
  }
267866
267866
 
267867
+ ;// CONCATENATED MODULE: ../../../../../common/temp/default/node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isEqual.js
267868
+
267869
+
267870
+ /**
267871
+ * Performs a deep comparison between two values to determine if they are
267872
+ * equivalent.
267873
+ *
267874
+ * **Note:** This method supports comparing arrays, array buffers, booleans,
267875
+ * date objects, error objects, maps, numbers, `Object` objects, regexes,
267876
+ * sets, strings, symbols, and typed arrays. `Object` objects are compared
267877
+ * by their own, not inherited, enumerable properties. Functions and DOM
267878
+ * nodes are compared by strict equality, i.e. `===`.
267879
+ *
267880
+ * @static
267881
+ * @memberOf _
267882
+ * @since 0.1.0
267883
+ * @category Lang
267884
+ * @param {*} value The value to compare.
267885
+ * @param {*} other The other value to compare.
267886
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
267887
+ * @example
267888
+ *
267889
+ * var object = { 'a': 1 };
267890
+ * var other = { 'a': 1 };
267891
+ *
267892
+ * _.isEqual(object, other);
267893
+ * // => true
267894
+ *
267895
+ * object === other;
267896
+ * // => false
267897
+ */
267898
+ function lodash_es_isEqual_isEqual(value, other) {
267899
+ return _baseIsEqual(value, other);
267900
+ }
267901
+
267902
+ /* ESM default export */ const lodash_es_isEqual = (lodash_es_isEqual_isEqual);
267903
+
267867
267904
  ;// CONCATENATED MODULE: ../../../../../common/temp/default/node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_baseLodash.js
267868
267905
  /**
267869
267906
  * The function whose prototype chain sequence wrappers inherit from.
@@ -268366,10 +268403,126 @@ var flow = _createFlow();
268366
268403
 
268367
268404
  class StreamBufferHelper {
268368
268405
  /**
268406
+ * 合并两个 JSON 对象(深度合并)
268407
+ * - 如果两个值都是对象,递归合并
268408
+ * - 如果两个值都是字符串,追加字符串
268409
+ * - 如果两个值都是数组,合并数组(按索引合并)
268410
+ * - 否则使用 curr 的值(覆盖)
268411
+ */ mergeJsonObjects(prev, curr) {
268412
+ const merged = {
268413
+ ...prev
268414
+ };
268415
+ for(const key in curr){
268416
+ if (Object.prototype.hasOwnProperty.call(curr, key)) {
268417
+ const prevValue = prev[key];
268418
+ const currValue = curr[key];
268419
+ // 如果两个值都是对象,递归合并
268420
+ if (typeof prevValue === 'object' && prevValue !== null && !Array.isArray(prevValue) && typeof currValue === 'object' && currValue !== null && !Array.isArray(currValue)) {
268421
+ merged[key] = this.mergeJsonObjects(prevValue, currValue);
268422
+ } else if (typeof prevValue === 'string' && typeof currValue === 'string') {
268423
+ // 如果两个值都是字符串,追加字符串
268424
+ merged[key] = prevValue + currValue;
268425
+ } else if (Array.isArray(prevValue) && Array.isArray(currValue)) {
268426
+ // 如果两个值都是数组,按索引合并
268427
+ const mergedArray = [
268428
+ ...prevValue
268429
+ ];
268430
+ for(let i = 0; i < currValue.length; i++){
268431
+ const currItem = currValue[i];
268432
+ if (i < mergedArray.length) {
268433
+ // 如果索引已存在,尝试合并
268434
+ const prevItem = mergedArray[i];
268435
+ if (typeof prevItem === 'object' && prevItem !== null && !Array.isArray(prevItem) && typeof currItem === 'object' && currItem !== null && !Array.isArray(currItem)) {
268436
+ mergedArray[i] = this.mergeJsonObjects(prevItem, currItem);
268437
+ } else {
268438
+ mergedArray[i] = currItem;
268439
+ }
268440
+ } else {
268441
+ // 如果索引超出范围,追加新元素
268442
+ mergedArray.push(currItem);
268443
+ }
268444
+ }
268445
+ merged[key] = mergedArray;
268446
+ } else {
268447
+ // 否则使用 curr 的值(覆盖)
268448
+ merged[key] = currValue;
268449
+ }
268450
+ }
268451
+ }
268452
+ return merged;
268453
+ }
268454
+ /**
268369
268455
  * Added Chunk message cache
268370
268456
  */ pushChunk(chunk) {
268371
268457
  this.streamChunkBuffer.push(chunk);
268372
268458
  }
268459
+ /**
268460
+ * Merge item_list arrays by index, handling JSON items specially
268461
+ */ mergeItemList(prevItemList, currItemList) {
268462
+ const mergedItemList = [
268463
+ ...prevItemList
268464
+ ];
268465
+ for(let i = 0; i < currItemList.length; i++){
268466
+ const currItem = currItemList[i];
268467
+ if (i < mergedItemList.length) {
268468
+ const prevItem = mergedItemList[i];
268469
+ // Special handling: if both items are JSON items, merge their json fields
268470
+ if (typeof prevItem === 'object' && prevItem !== null && typeof currItem === 'object' && currItem !== null && 'type' in prevItem && 'type' in currItem && prevItem.type === types_ContentType.Json && currItem.type === types_ContentType.Json && 'json' in prevItem && 'json' in currItem) {
268471
+ const prevJson = prevItem.json;
268472
+ const currJson = currItem.json;
268473
+ // If both json fields are arrays, merge arrays by index
268474
+ if (Array.isArray(prevJson) && Array.isArray(currJson)) {
268475
+ const prevJsonArray = prevJson;
268476
+ const currJsonArray = currJson;
268477
+ const mergedJsonArray = [
268478
+ ...prevJsonArray
268479
+ ];
268480
+ for(let j = 0; j < currJsonArray.length; j++){
268481
+ if (j < mergedJsonArray.length) {
268482
+ mergedJsonArray[j] = currJsonArray[j];
268483
+ } else {
268484
+ mergedJsonArray.push(currJsonArray[j]);
268485
+ }
268486
+ }
268487
+ mergedItemList[i] = {
268488
+ ...currItem,
268489
+ json: mergedJsonArray
268490
+ };
268491
+ } else if (typeof prevJson === 'object' && prevJson !== null && !Array.isArray(prevJson) && typeof currJson === 'object' && currJson !== null && !Array.isArray(currJson)) {
268492
+ // If both json fields are objects, deep merge them
268493
+ const mergedJson = this.mergeJsonObjects(prevJson, currJson);
268494
+ mergedItemList[i] = {
268495
+ ...currItem,
268496
+ json: mergedJson
268497
+ };
268498
+ } else if (!lodash_es_isEqual(prevItem, currItem)) {
268499
+ mergedItemList[i] = currItem;
268500
+ }
268501
+ } else if (!lodash_es_isEqual(prevItem, currItem)) {
268502
+ mergedItemList[i] = currItem;
268503
+ }
268504
+ } else {
268505
+ mergedItemList.push(currItem);
268506
+ }
268507
+ }
268508
+ return mergedItemList;
268509
+ }
268510
+ /**
268511
+ * Merge refer_items arrays by index
268512
+ */ mergeReferItems(prevReferItems, currReferItems) {
268513
+ const mergedReferItems = [
268514
+ ...prevReferItems
268515
+ ];
268516
+ for(let i = 0; i < currReferItems.length; i++){
268517
+ const currReferItem = currReferItems[i];
268518
+ if (i < mergedReferItems.length) {
268519
+ mergedReferItems[i] = currReferItem;
268520
+ } else {
268521
+ mergedReferItems.push(currReferItem);
268522
+ }
268523
+ }
268524
+ return mergedReferItems;
268525
+ }
268373
268526
  concatContentAndUpdateMessage(message) {
268374
268527
  const previousIndex = this.streamMessageBuffer.findIndex((item)=>item.message_id === message.message_id);
268375
268528
  // new
@@ -268379,27 +268532,45 @@ class StreamBufferHelper {
268379
268532
  }
268380
268533
  // update
268381
268534
  const previousMessage = this.streamMessageBuffer.at(previousIndex);
268535
+ // 如果是 completed 消息(is_finish = true),直接替换,不合并
268536
+ if (message.is_finish) {
268537
+ this.streamMessageBuffer[previousIndex] = message;
268538
+ return;
268539
+ }
268382
268540
  // For Mix type (object_string), merge item_list arrays instead of string concatenation
268541
+ // Support streaming messages: when receiving message.delta data with object_string content,
268542
+ // merge it with previous data of the same message using append rule
268543
+ // IMPORTANT: Current content may contain the full accumulated array, so we need to compare
268544
+ // and only add new items that don't exist in the previous content
268383
268545
  if (message.content_type === types_ContentType.Mix) {
268384
268546
  try {
268385
- var _prevContent_value, _currContent_value;
268547
+ var _prevContent_value, _currContent_value, _prevContent_value1, _currContent_value1;
268386
268548
  const prevContent = safeJSONParse((previousMessage === null || previousMessage === void 0 ? void 0 : previousMessage.content) || '{}', {
268387
- item_list: []
268549
+ item_list: [],
268550
+ refer_items: []
268388
268551
  });
268389
268552
  const currContent = safeJSONParse(message.content, {
268390
- item_list: []
268553
+ item_list: [],
268554
+ refer_items: []
268391
268555
  });
268556
+ const prevItemList = ((_prevContent_value = prevContent.value) === null || _prevContent_value === void 0 ? void 0 : _prevContent_value.item_list) || [];
268557
+ const currItemList = ((_currContent_value = currContent.value) === null || _currContent_value === void 0 ? void 0 : _currContent_value.item_list) || [];
268558
+ const prevReferItems = ((_prevContent_value1 = prevContent.value) === null || _prevContent_value1 === void 0 ? void 0 : _prevContent_value1.refer_items) || [];
268559
+ const currReferItems = ((_currContent_value1 = currContent.value) === null || _currContent_value1 === void 0 ? void 0 : _currContent_value1.refer_items) || [];
268560
+ // Merge item_list by index: update items at the same index, keep previous items if not updated
268561
+ // For arrays, merge by index position: update existing items, keep others unchanged
268562
+ // Special handling: if both prevItem and currItem are JSON items with array json fields, merge the arrays
268563
+ const mergedItemList = this.mergeItemList(prevItemList, currItemList);
268564
+ const mergedReferItems = this.mergeReferItems(prevReferItems, currReferItems);
268392
268565
  const mergedContent = {
268393
- item_list: [
268394
- ...((_prevContent_value = prevContent.value) === null || _prevContent_value === void 0 ? void 0 : _prevContent_value.item_list) || [],
268395
- ...((_currContent_value = currContent.value) === null || _currContent_value === void 0 ? void 0 : _currContent_value.item_list) || []
268396
- ],
268397
- refer_items: []
268566
+ item_list: mergedItemList,
268567
+ refer_items: mergedReferItems
268398
268568
  };
268399
268569
  message.content = JSON.stringify(mergedContent);
268400
268570
  message.content_obj = mergedContent;
268401
268571
  } catch (e) {
268402
268572
  // Fallback to string concatenation if parsing fails
268573
+ // Error is intentionally ignored as we fallback to string concatenation
268403
268574
  message.content = ((previousMessage === null || previousMessage === void 0 ? void 0 : previousMessage.content) || '') + message.content;
268404
268575
  message.content_obj = message.content;
268405
268576
  }
@@ -268510,7 +268681,8 @@ class ChunkProcessor {
268510
268681
  const { message } = chunk;
268511
268682
  // Find all corresponding replies
268512
268683
  const replyMessages = this.getReplyMessagesByReplyId(message.reply_id);
268513
- // Find if there is a verbose message, and identify the end of the answer, and filter out the finish of the interrupt scene
268684
+ // Find if there is a verbose message, and identify the end of the answer,
268685
+ // and filter out the finish of the interrupt scene
268514
268686
  const finalAnswerVerboseMessage = replyMessages.find((replyMessage)=>{
268515
268687
  const { type, content } = replyMessage;
268516
268688
  if (type !== 'verbose') {
@@ -268521,7 +268693,9 @@ class ChunkProcessor {
268521
268693
  return false;
268522
268694
  }
268523
268695
  const { value: verboseContentData } = safeJSONParse(verboseContent.data, null);
268524
- // At present, there may be a finish package in a group. If you need to filter out the interrupt scene through finish_reason, you will get the finish that answers all the ends.
268696
+ // At present, there may be a finish package in a group.
268697
+ // If you need to filter out the interrupt scene through finish_reason,
268698
+ // you will get the finish that answers all the ends.
268525
268699
  return verboseContent.msg_type === types_VerboseMsgType.GENERATE_ANSWER_FINISH && (verboseContentData === null || verboseContentData === void 0 ? void 0 : verboseContentData.finish_reason) !== types_FinishReasonType.INTERRUPT;
268526
268700
  });
268527
268701
  return Boolean(finalAnswerVerboseMessage);
@@ -269345,6 +269519,14 @@ class HttpChunk extends CustomEventEmitter {
269345
269519
  }
269346
269520
  await fetchStream(channelFetchInfo.url, {
269347
269521
  onStart: (response)=>{
269522
+ // 如果状态码是错误状态码(>= HTTP_BAD_REQUEST),尝试读取响应体以获取错误信息
269523
+ const HTTP_BAD_REQUEST = 400;
269524
+ if (response.status >= HTTP_BAD_REQUEST) {
269525
+ const cloneResponse = response.clone();
269526
+ cloneResponse.text().catch(()=>{
269527
+ // 忽略读取错误
269528
+ });
269529
+ }
269348
269530
  fetchDataHelper.setLogID(response.headers.get('x-tt-logid'));
269349
269531
  return Promise.resolve();
269350
269532
  },
@@ -269392,7 +269574,8 @@ class HttpChunk extends CustomEventEmitter {
269392
269574
  streamParser: (onGetMessageStreamParser === null || onGetMessageStreamParser === void 0 ? void 0 : onGetMessageStreamParser(value)) || utils_streamParser,
269393
269575
  dataClump: fetchDataHelper,
269394
269576
  body: channelFetchInfo.body,
269395
- headers: channelFetchInfo.headers,
269577
+ // 将 headers 数组转换为 Headers 对象,因为 fetch API 需要 Headers 对象或普通对象
269578
+ headers: new Headers(channelFetchInfo.headers),
269396
269579
  method: channelFetchInfo.method,
269397
269580
  signal: fetchDataHelper.abortSignal.signal,
269398
269581
  totalFetchTimeout: fetchDataHelper.totalFetchTimeout,
@@ -269418,7 +269601,8 @@ class HttpChunk extends CustomEventEmitter {
269418
269601
  }
269419
269602
  this.customEmit(http_chunk_events_HttpChunkEvents.READ_STREAM_ERROR, errorInfo);
269420
269603
  return;
269421
- // TODO: The following should be the logic to re-pull the message. The server level did not have time to do it in this issue.
269604
+ // TODO: The following should be the logic to re-pull the message.
269605
+ // The server level did not have time to do it in this issue.
269422
269606
  // if (dataClump.retryCounter.matchMaxRetryAttempts()) {
269423
269607
  // this.customOnError?.(errorInfo);
269424
269608
  // //give up trying and try again
@@ -271827,43 +272011,6 @@ function isError_isError(value) {
271827
272011
 
271828
272012
  /* ESM default export */ const lodash_es_isError = (isError_isError);
271829
272013
 
271830
- ;// CONCATENATED MODULE: ../../../../../common/temp/default/node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isEqual.js
271831
-
271832
-
271833
- /**
271834
- * Performs a deep comparison between two values to determine if they are
271835
- * equivalent.
271836
- *
271837
- * **Note:** This method supports comparing arrays, array buffers, booleans,
271838
- * date objects, error objects, maps, numbers, `Object` objects, regexes,
271839
- * sets, strings, symbols, and typed arrays. `Object` objects are compared
271840
- * by their own, not inherited, enumerable properties. Functions and DOM
271841
- * nodes are compared by strict equality, i.e. `===`.
271842
- *
271843
- * @static
271844
- * @memberOf _
271845
- * @since 0.1.0
271846
- * @category Lang
271847
- * @param {*} value The value to compare.
271848
- * @param {*} other The other value to compare.
271849
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
271850
- * @example
271851
- *
271852
- * var object = { 'a': 1 };
271853
- * var other = { 'a': 1 };
271854
- *
271855
- * _.isEqual(object, other);
271856
- * // => true
271857
- *
271858
- * object === other;
271859
- * // => false
271860
- */
271861
- function lodash_es_isEqual_isEqual(value, other) {
271862
- return _baseIsEqual(value, other);
271863
- }
271864
-
271865
- /* ESM default export */ const lodash_es_isEqual = (lodash_es_isEqual_isEqual);
271866
-
271867
272014
  ;// CONCATENATED MODULE: ../../../../../common/temp/default/node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/head.js
271868
272015
  /**
271869
272016
  * Gets the first element of `array`.
@@ -297547,6 +297694,9 @@ const JsonItemList = (param)=>{
297547
297694
  }
297548
297695
  return /*#__PURE__*/ (0,jsx_runtime.jsx)(jsx_runtime.Fragment, {
297549
297696
  children: jsonItemList.map((item, idx)=>{
297697
+ // Use a stable key based on item content and index to avoid React reusing components incorrectly
297698
+ // This ensures that when items are updated, React correctly updates the component instead of reusing it
297699
+ const itemKey = `json-${message.message_id}-${idx}-${JSON.stringify(item.json).slice(0, 50)}`;
297550
297700
  if (JsonItem) {
297551
297701
  return /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
297552
297702
  // className={typeSafeMessageBoxInnerVariants({
@@ -297563,7 +297713,7 @@ const JsonItemList = (param)=>{
297563
297713
  schemaVersion: item.schema_version,
297564
297714
  message: message
297565
297715
  })
297566
- }, `json-${idx}`);
297716
+ }, itemKey);
297567
297717
  }
297568
297718
  // Default fallback: use built-in JSON viewer
297569
297719
  return /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
@@ -297574,7 +297724,7 @@ const JsonItemList = (param)=>{
297574
297724
  data: item.json,
297575
297725
  schemaVersion: item.schema_version
297576
297726
  })
297577
- }, `json-${idx}`);
297727
+ }, itemKey);
297578
297728
  })
297579
297729
  });
297580
297730
  };
@@ -407437,6 +407587,8 @@ const usePaginationRequest = (param)=>{
407437
407587
  const [currentPage, setCurrentPage] = (0,react.useState)(initialPageNum);
407438
407588
  const [allData, setAllData] = (0,react.useState)([]);
407439
407589
  const [hasMore, setHasMore] = (0,react.useState)(true);
407590
+ // 使用 ref 跟踪是否已经自动加载过,避免重复请求
407591
+ const hasAutoLoadedRef = (0,react.useRef)(false);
407440
407592
  const { loading, error, run } = es_useRequest(async (pageNum)=>{
407441
407593
  const targetPage = pageNum ?? currentPage;
407442
407594
  const params = {
@@ -407526,8 +407678,10 @@ const usePaginationRequest = (param)=>{
407526
407678
  });
407527
407679
  }, []);
407528
407680
  // 组件挂载时自动加载第一页
407681
+ // 修复:使用 ref 跟踪是否已加载,避免重复请求
407529
407682
  (0,react.useEffect)(()=>{
407530
- if (autoLoad) {
407683
+ if (autoLoad && !hasAutoLoadedRef.current) {
407684
+ hasAutoLoadedRef.current = true;
407531
407685
  run(initialPageNum);
407532
407686
  }
407533
407687
  }, [
@@ -407551,7 +407705,7 @@ const usePaginationRequest = (param)=>{
407551
407705
  };
407552
407706
 
407553
407707
  ;// CONCATENATED MODULE: ../open-chat/src/components/studio-open-chat/hooks/use-conversation-list.ts
407554
- /*
407708
+ /* eslint-disable max-lines -- This file handles complex conversation list synchronization logic that requires many lines */ /*
407555
407709
  * Copyright 2025 coze-dev Authors
407556
407710
  *
407557
407711
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -407581,7 +407735,7 @@ const usePaginationRequest = (param)=>{
407581
407735
 
407582
407736
 
407583
407737
 
407584
- // eslint-disable-next-line @coze-arch/max-line-per-function
407738
+ // eslint-disable-next-line @coze-arch/max-line-per-function -- This hook handles complex conversation list management logic that requires many lines
407585
407739
  const useConversationList = (conversationListParams)=>{
407586
407740
  const { pageSize = 20, initialPageNum = 1, order = 'updated_at' } = conversationListParams ?? {};
407587
407741
  const { chatConfig: { bot_id: botId, appInfo, type: chatType, auth: { connectorId } = {} } } = context_useChatAppProps();
@@ -407601,15 +407755,29 @@ const useConversationList = (conversationListParams)=>{
407601
407755
  // 使用 ref 来跟踪是否正在同步,避免循环更新
407602
407756
  const isSyncingRef = (0,react.useRef)(false);
407603
407757
  const lastStoreIdsRef = (0,react.useRef)('');
407758
+ // 使用 ref 原子性地跟踪 App 模式的加载状态,防止竞态条件
407759
+ const appModeLoadingRef = (0,react.useRef)(false);
407604
407760
  // App 模式:使用基于 before_updated_at 和 limit 的加载逻辑
407605
407761
  const [appModeData, setAppModeData] = (0,react.useState)([]);
407606
407762
  const [appModeLoading, setAppModeLoading] = (0,react.useState)(false);
407607
407763
  const [appModeHasMore, setAppModeHasMore] = (0,react.useState)(true);
407608
407764
  const [beforeUpdatedAt, setBeforeUpdatedAt] = (0,react.useState)(undefined);
407765
+ // 同步 appModeLoading 状态到 ref
407766
+ (0,react.useEffect)(()=>{
407767
+ appModeLoadingRef.current = appModeLoading;
407768
+ }, [
407769
+ appModeLoading
407770
+ ]);
407609
407771
  const loadAppModeConversations = (0,react.useCallback)(async (beforeTimestamp)=>{
407610
- if (!cozeApiSdk || !hasValidId || !isAppType || appModeLoading) {
407772
+ if (!cozeApiSdk || !hasValidId || !isAppType) {
407773
+ return;
407774
+ }
407775
+ // 原子性检查:如果已经在加载,直接返回
407776
+ if (appModeLoadingRef.current) {
407611
407777
  return;
407612
407778
  }
407779
+ // 原子性设置:立即设置 ref,防止并发调用
407780
+ appModeLoadingRef.current = true;
407613
407781
  setAppModeLoading(true);
407614
407782
  try {
407615
407783
  var _res_data, _res_data1;
@@ -407674,6 +407842,8 @@ const useConversationList = (conversationListParams)=>{
407674
407842
  console.error(e);
407675
407843
  setAppModeHasMore(false);
407676
407844
  } finally{
407845
+ // 原子性重置:先重置 ref,再更新状态
407846
+ appModeLoadingRef.current = false;
407677
407847
  setAppModeLoading(false);
407678
407848
  }
407679
407849
  }, [
@@ -407787,18 +407957,36 @@ const useConversationList = (conversationListParams)=>{
407787
407957
  // 同步 finalData 到 store(只在本地数据源变化时更新 store,避免循环)
407788
407958
  // 注意:这个 useEffect 只在从服务器加载数据时触发,不会在 store 同步到本地数据源时触发
407789
407959
  (0,react.useEffect)(()=>{
407790
- if (finalData && !isSyncingRef.current) {
407960
+ // 如果正在同步,跳过,避免循环更新
407961
+ if (isSyncingRef.current) {
407962
+ return;
407963
+ }
407964
+ if (finalData && finalData.length > 0) {
407791
407965
  // 比较数据是否真的变化了,避免不必要的更新
407792
407966
  const currentIds = conversations.map((c)=>c.id).sort().join(',');
407793
407967
  const newIds = finalData.map((c)=>c.id).sort().join(',');
407968
+ // 只有在 ID 列表真的发生变化时才更新 store
407969
+ // 这样可以避免因为对象引用变化导致的重复更新
407794
407970
  if (currentIds !== newIds) {
407795
- // 只有在本地数据源是从服务器加载的新数据时才更新 store
407796
- // 如果是因为 store 同步导致的 finalData 变化,不应该再次更新 store
407797
- isSyncingRef.current = true;
407798
- updateConversations(finalData, 'replace');
407799
- setTimeout(()=>{
407800
- isSyncingRef.current = false;
407801
- }, 0);
407971
+ // 检查是否是store新增了会话(store的ID数量增加了)
407972
+ // 如果是store新增,不应该在这里更新store,应该让监听store的useEffect处理
407973
+ const storeCount = conversations.length;
407974
+ const finalDataCount = finalData.length;
407975
+ const isStoreNewer = storeCount > finalDataCount;
407976
+ // 只有在finalData比store新(从服务器加载了新数据)时才更新store
407977
+ // 如果store比finalData新(store新增了会话),不应该更新store
407978
+ if (!isStoreNewer) {
407979
+ // 只有在本地数据源是从服务器加载的新数据时才更新 store
407980
+ // 如果是因为 store 同步导致的 finalData 变化,不应该再次更新 store
407981
+ isSyncingRef.current = true;
407982
+ updateConversations(finalData, 'replace');
407983
+ // 使用 requestAnimationFrame 确保在下一个事件循环中重置标志
407984
+ requestAnimationFrame(()=>{
407985
+ setTimeout(()=>{
407986
+ isSyncingRef.current = false;
407987
+ }, 0);
407988
+ });
407989
+ }
407802
407990
  }
407803
407991
  }
407804
407992
  }, [
@@ -407806,99 +407994,182 @@ const useConversationList = (conversationListParams)=>{
407806
407994
  updateConversations,
407807
407995
  conversations
407808
407996
  ]);
407997
+ // 检查会话是否有更新的辅助函数
407998
+ const checkConversationUpdates = (0,react.useCallback)((storeConversations, localConversations)=>{
407999
+ const localMap = new Map(localConversations.map((c)=>[
408000
+ c.id,
408001
+ c
408002
+ ]));
408003
+ return storeConversations.some((storeConv)=>{
408004
+ const localConv = localMap.get(storeConv.id);
408005
+ if (!localConv) {
408006
+ return false;
408007
+ }
408008
+ const storeConvWithTitle = storeConv;
408009
+ const localConvWithTitle = localConv;
408010
+ return storeConvWithTitle.title !== localConvWithTitle.title || storeConv.name !== localConv.name || storeConv.updated_at !== localConv.updated_at;
408011
+ });
408012
+ }, []);
408013
+ // 同步 App 模式更新的辅助函数
408014
+ const syncAppModeUpdates = (0,react.useCallback)(()=>{
408015
+ isSyncingRef.current = true;
408016
+ setAppModeData((prev)=>{
408017
+ const prevMap = new Map(prev.map((c)=>[
408018
+ c.id,
408019
+ c
408020
+ ]));
408021
+ return conversations.map((storeConv)=>{
408022
+ const prevConv = prevMap.get(storeConv.id);
408023
+ return prevConv ? {
408024
+ ...prevConv,
408025
+ ...storeConv
408026
+ } : storeConv;
408027
+ });
408028
+ });
408029
+ requestAnimationFrame(()=>{
408030
+ setTimeout(()=>{
408031
+ isSyncingRef.current = false;
408032
+ }, 0);
408033
+ });
408034
+ }, [
408035
+ conversations
408036
+ ]);
408037
+ // 同步 Bot 模式更新的辅助函数
408038
+ const syncBotModeUpdates = (0,react.useCallback)(()=>{
408039
+ isSyncingRef.current = true;
408040
+ const localMap = new Map(data.map((c)=>[
408041
+ c.id,
408042
+ c
408043
+ ]));
408044
+ const updatedConversations = conversations.filter((storeConv)=>localMap.has(storeConv.id)).map((storeConv)=>{
408045
+ const localConv = localMap.get(storeConv.id);
408046
+ return localConv ? {
408047
+ ...localConv,
408048
+ ...storeConv
408049
+ } : storeConv;
408050
+ });
408051
+ updatedConversations.forEach((conv)=>{
408052
+ removeBotModeItem((c)=>c.id === conv.id);
408053
+ });
408054
+ updatedConversations.reverse().forEach((conv)=>{
408055
+ addBotModeItem(conv, 'start');
408056
+ });
408057
+ requestAnimationFrame(()=>{
408058
+ setTimeout(()=>{
408059
+ isSyncingRef.current = false;
408060
+ }, 0);
408061
+ });
408062
+ }, [
408063
+ conversations,
408064
+ data,
408065
+ removeBotModeItem,
408066
+ addBotModeItem
408067
+ ]);
408068
+ // 处理删除的辅助函数
408069
+ const handleDeletions = (0,react.useCallback)((storeIds, localIds)=>{
408070
+ const deletedIds = Array.from(localIds).filter((id)=>!storeIds.has(id));
408071
+ if (deletedIds.length === 0) {
408072
+ return;
408073
+ }
408074
+ isSyncingRef.current = true;
408075
+ if (isAppType) {
408076
+ setAppModeData((prev)=>prev.filter((c)=>!deletedIds.includes(c.id)));
408077
+ } else {
408078
+ removeBotModeItem((c)=>deletedIds.includes(c.id));
408079
+ }
408080
+ requestAnimationFrame(()=>{
408081
+ setTimeout(()=>{
408082
+ isSyncingRef.current = false;
408083
+ }, 0);
408084
+ });
408085
+ }, [
408086
+ isAppType,
408087
+ removeBotModeItem
408088
+ ]);
408089
+ // 处理新增会话的辅助函数
408090
+ const handleNewConversations = (0,react.useCallback)((newConversations)=>{
408091
+ if (newConversations.length === 0) {
408092
+ return;
408093
+ }
408094
+ isSyncingRef.current = true;
408095
+ try {
408096
+ if (isAppType) {
408097
+ setAppModeData((prev)=>[
408098
+ ...newConversations,
408099
+ ...prev
408100
+ ]);
408101
+ } else {
408102
+ newConversations.forEach((conv)=>{
408103
+ addBotModeItem(conv, 'start');
408104
+ });
408105
+ }
408106
+ } finally{
408107
+ requestAnimationFrame(()=>{
408108
+ setTimeout(()=>{
408109
+ isSyncingRef.current = false;
408110
+ }, 50);
408111
+ });
408112
+ }
408113
+ }, [
408114
+ isAppType,
408115
+ addBotModeItem
408116
+ ]);
407809
408117
  // 监听 store 的 conversations 变化,同步更新本地数据源
407810
408118
  // 只在 store 有新增会话时才同步,避免循环更新
407811
408119
  (0,react.useEffect)(()=>{
408120
+ if (isSyncingRef.current) {
408121
+ return;
408122
+ }
407812
408123
  const currentStoreIds = conversations.map((c)=>c.id).sort().join(',');
407813
- // 如果 store ID 列表没有变化,跳过
407814
- if (currentStoreIds === lastStoreIdsRef.current) {
408124
+ const localConversations = isAppType ? appModeData : data;
408125
+ const hasUpdates = checkConversationUpdates(conversations, localConversations);
408126
+ if (currentStoreIds === lastStoreIdsRef.current && currentStoreIds !== '' && !hasUpdates) {
408127
+ return;
408128
+ }
408129
+ if (hasUpdates && (currentStoreIds === lastStoreIdsRef.current && currentStoreIds !== '' || lastStoreIdsRef.current === '' && currentStoreIds !== '')) {
408130
+ if (isAppType) {
408131
+ syncAppModeUpdates();
408132
+ } else {
408133
+ syncBotModeUpdates();
408134
+ }
408135
+ lastStoreIdsRef.current = currentStoreIds;
407815
408136
  return;
407816
408137
  }
407817
- // 检查是否有新增(store 的数量增加了)
407818
408138
  const storeCount = conversations.length;
407819
- const lastStoreCount = lastStoreIdsRef.current.split(',').filter(Boolean).length;
408139
+ const lastStoreCount = lastStoreIdsRef.current ? lastStoreIdsRef.current.split(',').filter(Boolean).length : 0;
407820
408140
  const hasNewConversations = storeCount > lastStoreCount;
407821
408141
  const hasDeletedConversations = storeCount < lastStoreCount;
407822
- // 更新 ref
407823
408142
  lastStoreIdsRef.current = currentStoreIds;
407824
- // 如果有删除,同步到本地数据源
407825
408143
  if (hasDeletedConversations) {
407826
- // 如果正在同步(可能是删除操作触发的),跳过
407827
- if (isSyncingRef.current) {
407828
- return;
407829
- }
407830
- if (isAppType) {
407831
- const storeIds = new Set(conversations.map((c)=>c.id));
407832
- const localIds = new Set(appModeData.map((c)=>c.id));
407833
- const deletedIds = Array.from(localIds).filter((id)=>!storeIds.has(id));
407834
- if (deletedIds.length > 0) {
407835
- isSyncingRef.current = true;
407836
- setAppModeData((prev)=>prev.filter((c)=>!deletedIds.includes(c.id)));
407837
- setTimeout(()=>{
407838
- isSyncingRef.current = false;
407839
- }, 0);
407840
- }
407841
- } else {
407842
- const storeIds = new Set(conversations.map((c)=>c.id));
407843
- const localIds = new Set(data.map((c)=>c.id));
407844
- const deletedIds = Array.from(localIds).filter((id)=>!storeIds.has(id));
407845
- if (deletedIds.length > 0) {
407846
- isSyncingRef.current = true;
407847
- removeBotModeItem((c)=>deletedIds.includes(c.id));
407848
- setTimeout(()=>{
407849
- isSyncingRef.current = false;
407850
- }, 0);
407851
- }
407852
- }
408144
+ const storeIds = new Set(conversations.map((c)=>c.id));
408145
+ const localIds = new Set(localConversations.map((c)=>c.id));
408146
+ handleDeletions(storeIds, localIds);
407853
408147
  return;
407854
408148
  }
407855
- // 只在有新增会话时才同步,避免其他变化导致的循环
407856
408149
  if (!hasNewConversations && storeCount === lastStoreCount) {
407857
- // 可能是更新,不需要同步
407858
- return;
407859
- }
407860
- // 有新增会话,同步到本地数据源
407861
- // 注意:即使 isSyncingRef.current 为 true,也要处理新增,因为删除和新增可能同时发生
407862
- isSyncingRef.current = true;
407863
- try {
407864
- if (isAppType) {
407865
- // App 模式:检查 store 中是否有新会话不在本地数据源中
407866
- const localIds = new Set(appModeData.map((c)=>c.id));
407867
- // 找出 store 中有但本地没有的会话(新添加的)
407868
- const newConversations = conversations.filter((c)=>!localIds.has(c.id));
407869
- if (newConversations.length > 0) {
407870
- // 将新会话添加到本地数据源的开头(最新的会话应该在前面)
407871
- setAppModeData((prev)=>[
407872
- ...newConversations,
407873
- ...prev
407874
- ]);
407875
- }
407876
- } else {
407877
- // Bot 模式:检查 store 中是否有新会话不在本地数据源中
407878
- const localIds = new Set(data.map((c)=>c.id));
407879
- // 找出 store 中有但本地没有的会话(新添加的)
407880
- const newConversations = conversations.filter((c)=>!localIds.has(c.id));
407881
- if (newConversations.length > 0) {
407882
- // 将新会话添加到本地数据源的开头(最新的会话应该在前面)
407883
- newConversations.forEach((conv)=>{
407884
- addBotModeItem(conv, 'start');
407885
- });
408150
+ const hasLocalUpdates = checkConversationUpdates(conversations, localConversations);
408151
+ if (hasLocalUpdates) {
408152
+ if (isAppType) {
408153
+ syncAppModeUpdates();
408154
+ } else {
408155
+ syncBotModeUpdates();
407886
408156
  }
407887
408157
  }
407888
- } finally{
407889
- // 使用 setTimeout 确保状态更新完成后再重置标志
407890
- // 延迟时间稍微长一点,确保第一个 useEffect 不会触发
407891
- setTimeout(()=>{
407892
- isSyncingRef.current = false;
407893
- }, 100);
408158
+ return;
407894
408159
  }
408160
+ const localIds = new Set(localConversations.map((c)=>c.id));
408161
+ const newConversations = conversations.filter((c)=>!localIds.has(c.id));
408162
+ handleNewConversations(newConversations);
407895
408163
  }, [
407896
408164
  conversations,
407897
408165
  isAppType,
407898
408166
  appModeData,
407899
408167
  data,
407900
- removeBotModeItem,
407901
- addBotModeItem
408168
+ checkConversationUpdates,
408169
+ syncAppModeUpdates,
408170
+ syncBotModeUpdates,
408171
+ handleDeletions,
408172
+ handleNewConversations
407902
408173
  ]);
407903
408174
  (0,react.useEffect)(()=>{
407904
408175
  if (!currentConversationInfo) {
@@ -407935,7 +408206,7 @@ const useConversationList = (conversationListParams)=>{
407935
408206
  updateCurrentConversationInfo
407936
408207
  ]);
407937
408208
  return {
407938
- conversations,
408209
+ conversations: finalData,
407939
408210
  loading: finalLoading,
407940
408211
  hasMore: finalHasMore,
407941
408212
  loadMore: finalLoadMore,
@@ -408046,12 +408317,12 @@ const isUUID = (str)=>{
408046
408317
  };
408047
408318
  /**
408048
408319
  * 获取会话显示名称
408049
- * 优先级:title > name(如果不是UUID)> 新创建的会话
408320
+ * 优先级:title(如果不是UUID)> name(如果不是UUID)> 新创建的会话
408050
408321
  * @param item 会话项
408051
408322
  * @returns 显示名称
408052
408323
  */ const getConversationDisplayName = (item)=>{
408053
- // 优先使用title
408054
- if (item.title) {
408324
+ // 优先使用title,但需要检查是否是UUID
408325
+ if (item.title && !isUUID(item.title)) {
408055
408326
  return item.title;
408056
408327
  }
408057
408328
  // 如果name存在且不是UUID格式,使用name
@@ -408059,7 +408330,7 @@ const isUUID = (str)=>{
408059
408330
  return item.name;
408060
408331
  }
408061
408332
  // 否则显示"新创建的会话"
408062
- return intl_i18n.t('web_sdk_conversation_default_name');
408333
+ return intl_i18n.t('web_sdk_conversation_default_name', {}, '新创建的会话');
408063
408334
  };
408064
408335
 
408065
408336
  ;// CONCATENATED MODULE: ../open-chat/src/components/conversation-list-sider/conversation-item/mobile/operate/index.tsx
@@ -408555,6 +408826,16 @@ const ConversationList = /*#__PURE__*/ (0,react.forwardRef)(// eslint-disable-ne
408555
408826
  ]);
408556
408827
  const listContainerRef = (0,react.useRef)(null);
408557
408828
  const loadMoreRef = (0,react.useRef)(null);
408829
+ // 使用 ref 存储 loadMore 函数,避免 useEffect 依赖项变化导致 observer 重新创建
408830
+ const loadMoreRefFn = (0,react.useRef)(loadMore);
408831
+ // 使用 ref 跟踪是否正在加载,防止重复调用
408832
+ const isLoadingRef = (0,react.useRef)(false);
408833
+ // 更新 loadMoreRefFn 当 loadMore 变化时
408834
+ (0,react.useEffect)(()=>{
408835
+ loadMoreRefFn.current = loadMore;
408836
+ }, [
408837
+ loadMore
408838
+ ]);
408558
408839
  const handleCreateConversation = ()=>{
408559
408840
  if (!currentConversationInfo) {
408560
408841
  return Promise.resolve();
@@ -408696,11 +408977,21 @@ const ConversationList = /*#__PURE__*/ (0,react.forwardRef)(// eslint-disable-ne
408696
408977
  handleCreateConversation,
408697
408978
  handleDeleteConversation
408698
408979
  }));
408980
+ // 同步 loading 状态到 ref
408981
+ (0,react.useEffect)(()=>{
408982
+ isLoadingRef.current = loading;
408983
+ }, [
408984
+ loading
408985
+ ]);
408699
408986
  (0,react.useEffect)(()=>{
408700
408987
  const observer = new IntersectionObserver((entries)=>{
408701
408988
  const [entry] = entries;
408702
- if (entry.isIntersecting && hasMore && !loading) {
408703
- loadMore();
408989
+ // 使用 ref 中的最新值,避免闭包问题
408990
+ // 注意:loadMore 函数内部已经有原子性检查,这里只需要检查基本条件
408991
+ if (entry.isIntersecting && hasMore && !isLoadingRef.current) {
408992
+ // 使用 ref 中的最新函数
408993
+ // loadMore 函数内部已经有原子性检查,可以安全地多次调用
408994
+ loadMoreRefFn.current();
408704
408995
  }
408705
408996
  }, {
408706
408997
  root: listContainerRef.current,
@@ -408711,15 +409002,12 @@ const ConversationList = /*#__PURE__*/ (0,react.forwardRef)(// eslint-disable-ne
408711
409002
  observer.observe(loadMoreRef.current);
408712
409003
  }
408713
409004
  return ()=>{
408714
- if (loadMoreRef.current) {
408715
- observer.unobserve(loadMoreRef.current);
408716
- }
409005
+ // 确保完全断开 observer 连接,防止旧的 observer 继续工作
409006
+ observer.disconnect();
408717
409007
  };
408718
409008
  }, [
408719
- hasMore,
408720
- loading,
408721
- loadMore
408722
- ]);
409009
+ hasMore
409010
+ ]); // 只依赖 hasMore,不依赖 loading 和 loadMore
408723
409011
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
408724
409012
  className: conversation_list_sider_conversation_list_index_module.conversations,
408725
409013
  style: {
@@ -409219,6 +409507,13 @@ const storageUtil = {
409219
409507
 
409220
409508
 
409221
409509
 
409510
+
409511
+
409512
+
409513
+
409514
+
409515
+
409516
+
409222
409517
  const getDefaultUserInfo = (userInfo)=>{
409223
409518
  if (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) {
409224
409519
  return userInfo;
@@ -409230,6 +409525,7 @@ const getDefaultUserInfo = (userInfo)=>{
409230
409525
  url: ''
409231
409526
  };
409232
409527
  };
409528
+ // eslint-disable-next-line @coze-arch/max-line-per-function -- Store creation function contains comprehensive state management logic
409233
409529
  const createChatStore = (chatConfig, userInfo)=>{
409234
409530
  var _chatConfig_auth, _chatConfig_auth1;
409235
409531
  const isNeedToken = (chatConfig === null || chatConfig === void 0 ? void 0 : (_chatConfig_auth = chatConfig.auth) === null || _chatConfig_auth === void 0 ? void 0 : _chatConfig_auth.type) === client_AuthType.TOKEN;
@@ -409413,20 +409709,28 @@ const createChatStore = (chatConfig, userInfo)=>{
409413
409709
  ]));
409414
409710
  s.conversations = conversations.map((newConv)=>{
409415
409711
  const existingConv = existingConversationsMap.get(newConv.id);
409416
- if (existingConv && existingConv.title) {
409712
+ const existingConvWithTitle = existingConv;
409713
+ if (existingConvWithTitle === null || existingConvWithTitle === void 0 ? void 0 : existingConvWithTitle.title) {
409417
409714
  // 如果store中已有该会话且有title,保留title
409418
- return {
409419
- ...newConv,
409420
- title: existingConv.title
409421
- };
409715
+ return Object.assign({
409716
+ ...newConv
409717
+ }, {
409718
+ title: existingConvWithTitle.title
409719
+ });
409422
409720
  }
409423
409721
  return newConv;
409424
409722
  });
409425
409723
  } else if (operate === 'add') {
409426
- s.conversations = [
409427
- ...s.conversations,
409428
- ...conversations
409429
- ];
409724
+ // 修复:添加去重逻辑,避免重复添加相同的会话
409725
+ const existingIds = new Set(s.conversations.map((c)=>c.id));
409726
+ const newConversations = conversations.filter((c)=>c.id && !existingIds.has(c.id));
409727
+ if (newConversations.length > 0) {
409728
+ // 将新会话添加到列表开头(最新的会话应该在前面)
409729
+ s.conversations = [
409730
+ ...newConversations,
409731
+ ...s.conversations
409732
+ ];
409733
+ }
409430
409734
  } else if (operate === 'remove') {
409431
409735
  conversations.forEach((conversation)=>{
409432
409736
  const index = s.conversations.findIndex((c)=>c.id === conversation.id);
@@ -417060,6 +417364,7 @@ const convertShortcutData = (shortcutCommands, botInfo)=>//@ts-expect-error: 不
417060
417364
 
417061
417365
 
417062
417366
 
417367
+
417063
417368
  const microSeconds = 1000;
417064
417369
  /**
417065
417370
  * 从URL中提取文件名
@@ -417098,6 +417403,55 @@ const microSeconds = 1000;
417098
417403
  };
417099
417404
  // 消息转换成 Coze的消息,主要用于消息接收后,在页面显示。
417100
417405
  class MessageConverseToCoze {
417406
+ /**
417407
+ * 合并两个 JSON 对象(深度合并)
417408
+ * - 如果两个值都是对象,递归合并
417409
+ * - 如果两个值都是字符串,追加字符串
417410
+ * - 如果两个值都是数组,合并数组(按索引合并)
417411
+ * - 否则使用 curr 的值(覆盖)
417412
+ */ mergeJsonObjects(prev, curr) {
417413
+ const merged = {
417414
+ ...prev
417415
+ };
417416
+ for(const key in curr){
417417
+ if (Object.prototype.hasOwnProperty.call(curr, key)) {
417418
+ const prevValue = prev[key];
417419
+ const currValue = curr[key];
417420
+ // 如果两个值都是对象,递归合并
417421
+ if (typeof prevValue === 'object' && prevValue !== null && !Array.isArray(prevValue) && typeof currValue === 'object' && currValue !== null && !Array.isArray(currValue)) {
417422
+ merged[key] = this.mergeJsonObjects(prevValue, currValue);
417423
+ } else if (typeof prevValue === 'string' && typeof currValue === 'string') {
417424
+ // 如果两个值都是字符串,追加字符串
417425
+ merged[key] = prevValue + currValue;
417426
+ } else if (Array.isArray(prevValue) && Array.isArray(currValue)) {
417427
+ // 如果两个值都是数组,按索引合并
417428
+ const mergedArray = [
417429
+ ...prevValue
417430
+ ];
417431
+ for(let i = 0; i < currValue.length; i++){
417432
+ const currItem = currValue[i];
417433
+ if (i < mergedArray.length) {
417434
+ // 如果索引已存在,尝试合并
417435
+ const prevItem = mergedArray[i];
417436
+ if (typeof prevItem === 'object' && prevItem !== null && !Array.isArray(prevItem) && typeof currItem === 'object' && currItem !== null && !Array.isArray(currItem)) {
417437
+ mergedArray[i] = this.mergeJsonObjects(prevItem, currItem);
417438
+ } else {
417439
+ mergedArray[i] = currItem;
417440
+ }
417441
+ } else {
417442
+ // 如果索引超出范围,追加新元素
417443
+ mergedArray.push(currItem);
417444
+ }
417445
+ }
417446
+ merged[key] = mergedArray;
417447
+ } else {
417448
+ // 否则使用 curr 的值(覆盖)
417449
+ merged[key] = currValue;
417450
+ }
417451
+ }
417452
+ }
417453
+ return merged;
417454
+ }
417101
417455
  convertMessageListResponse(res) {
417102
417456
  let botId = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : '';
417103
417457
  const { data: messageList = [], has_more: hasMore, first_id: firstId, last_id: lastId } = res;
@@ -417116,7 +417470,11 @@ class MessageConverseToCoze {
417116
417470
  const { content_type, content } = this.convertContent(message.content_type, message.content) || {};
417117
417471
  const isQuestion = message.type === 'question';
417118
417472
  const replyId = message.chat_id || `--custom-replyId--${index_browser_nanoid()}`;
417119
- const messageId = isQuestion ? replyId : message.id || `--custom-messageId-${index_browser_nanoid()}`; // 无messageId,输出一个默认的
417473
+ // 对于流式的 object_string 消息,使用 message.id 作为 message_id
417474
+ // 这样可以确保不同 id 的消息不会被合并
417475
+ const isStreamingObjectString = message.content_type === 'object_string' && message.type === 'answer';
417476
+ const messageId = isQuestion ? replyId : isStreamingObjectString ? message.id || `--custom-messageId-${index_browser_nanoid()}` // 对于流式 object_string,使用 message.id 作为 message_id
417477
+ : message.id || `--custom-messageId-${index_browser_nanoid()}`; // 无messageId,输出一个默认的
417120
417478
  const senderId = isQuestion ? '' : message.bot_id || botId;
417121
417479
  if (!content_type || !messageId || !replyId) {
417122
417480
  return {};
@@ -417207,12 +417565,30 @@ class MessageConverseToCoze {
417207
417565
  }
417208
417566
  }
417209
417567
  convertMixContent(content) {
417210
- const contentObj = catchParse(content);
417211
- if (!contentObj) {
417568
+ // 先尝试解析 JSON 字符串为数组
417569
+ // 对于流式 object_string 消息,content 可能是 JSON 数组字符串,需要先解析
417570
+ let parsedContent;
417571
+ try {
417572
+ const trimmedContent = content.trim();
417573
+ // 尝试解析为 JSON 数组
417574
+ const parsed = JSON.parse(trimmedContent);
417575
+ if (Array.isArray(parsed)) {
417576
+ parsedContent = parsed;
417577
+ } else {
417578
+ // 如果不是数组,尝试作为单个对象解析
417579
+ parsedContent = [
417580
+ parsed
417581
+ ];
417582
+ }
417583
+ } catch (e) {
417584
+ // 解析失败,尝试使用 catchParse(可能是不完整的 JSON)
417585
+ parsedContent = catchParse(content);
417586
+ }
417587
+ if (!parsedContent) {
417212
417588
  return;
417213
417589
  }
417214
- console.log('convertMixContent contentObj', contentObj);
417215
- const itemList = contentObj === null || contentObj === void 0 ? void 0 : contentObj.map((item)=>{
417590
+ console.log('convertMixContent parsedContent', parsedContent);
417591
+ const itemList = parsedContent === null || parsedContent === void 0 ? void 0 : parsedContent.map((item)=>{
417216
417592
  switch(item.type){
417217
417593
  case 'text':
417218
417594
  {
@@ -417281,9 +417657,52 @@ class MessageConverseToCoze {
417281
417657
  }
417282
417658
  }
417283
417659
  }).filter((item)=>!!item);
417660
+ // 合并所有 JSON item 为一个 item
417661
+ // 如果 item_list 中有多个 JSON item,将它们合并为一个 JSON item
417662
+ const jsonItems = itemList.filter((item)=>item.type === types_ContentType.Json);
417663
+ const nonJsonItems = itemList.filter((item)=>item.type !== types_ContentType.Json);
417664
+ let mergedJsonItem;
417665
+ if (jsonItems.length > 0) {
417666
+ // 如果只有一个 JSON item,直接使用它
417667
+ if (jsonItems.length === 1) {
417668
+ mergedJsonItem = jsonItems[0];
417669
+ } else {
417670
+ // 如果有多个 JSON item,合并它们的 json 字段
417671
+ // 如果所有 json 字段都是对象,深度合并它们;否则合并为数组
417672
+ const jsonValues = jsonItems.map((item)=>item.json);
417673
+ const allAreObjects = jsonValues.every((json)=>typeof json === 'object' && json !== null && !Array.isArray(json));
417674
+ let mergedJson;
417675
+ if (allAreObjects) {
417676
+ // 深度合并所有对象
417677
+ mergedJson = jsonValues.reduce((acc, curr)=>{
417678
+ if (typeof acc === 'object' && acc !== null && !Array.isArray(acc) && typeof curr === 'object' && curr !== null && !Array.isArray(curr)) {
417679
+ return this.mergeJsonObjects(acc, curr);
417680
+ }
417681
+ return curr;
417682
+ }, jsonValues[0]);
417683
+ } else {
417684
+ // 如果有一个不是对象,合并为数组
417685
+ mergedJson = jsonValues.length === 1 ? jsonValues[0] : jsonValues;
417686
+ }
417687
+ // 使用第一个 JSON item 的 schema_version
417688
+ const schemaVersion = jsonItems[0].schema_version;
417689
+ mergedJsonItem = {
417690
+ type: types_ContentType.Json,
417691
+ json: mergedJson,
417692
+ schema_version: schemaVersion
417693
+ };
417694
+ }
417695
+ }
417696
+ // 合并所有 item:非 JSON item + 合并后的 JSON item
417697
+ const finalItemList = [
417698
+ ...nonJsonItems
417699
+ ];
417700
+ if (mergedJsonItem) {
417701
+ finalItemList.push(mergedJsonItem);
417702
+ }
417284
417703
  const contentResult = {
417285
- item_list: itemList.filter((item)=>!item.is_refer),
417286
- refer_items: itemList.filter((item)=>item.is_refer)
417704
+ item_list: finalItemList.filter((item)=>!item.is_refer),
417705
+ refer_items: finalItemList.filter((item)=>item.is_refer)
417287
417706
  };
417288
417707
  return JSON.stringify(contentResult);
417289
417708
  }
@@ -417551,11 +417970,19 @@ const useRequestInit = ()=>{
417551
417970
  const updateShortcuts = context_useChatAppStore((s)=>s.updateShortcuts);
417552
417971
  const setIsStartBotVoiceCall = context_useChatAppStore((s)=>s.setIsStartBotVoiceCall);
417553
417972
  const updateBackgroundInfo = context_useChatAppStore((s)=>s.updateBackgroundInfo);
417554
- const { currentConversationInfo, updateCurrentConversationInfo, conversations } = context_useChatAppStore(shallow_useShallow((s)=>({
417555
- currentConversationInfo: s.currentConversationInfo,
417556
- updateCurrentConversationInfo: s.updateCurrentConversationInfo,
417557
- conversations: s.conversations
417973
+ const { updateCurrentConversationInfo } = context_useChatAppStore(shallow_useShallow((s)=>({
417974
+ updateCurrentConversationInfo: s.updateCurrentConversationInfo
417558
417975
  })));
417976
+ // 使用 ref 来存储最新的 currentConversationInfo 和 conversations
417977
+ // 这样可以避免将它们放在依赖数组中,从而避免 title/name 更新时触发重新初始化
417978
+ const currentConversationInfoRef = (0,react.useRef)();
417979
+ const conversationsRef = (0,react.useRef)([]);
417980
+ // 通过 hook 获取值并更新 ref
417981
+ context_useChatAppStore(shallow_useShallow((s)=>{
417982
+ currentConversationInfoRef.current = s.currentConversationInfo;
417983
+ conversationsRef.current = s.conversations;
417984
+ return null; // 不返回任何值,只用于同步 ref
417985
+ }));
417559
417986
  const getMessageListByPairs = useGetMessageListByPairs();
417560
417987
  const connectorId = (chatConfig === null || chatConfig === void 0 ? void 0 : (_chatConfig_auth = chatConfig.auth) === null || _chatConfig_auth === void 0 ? void 0 : _chatConfig_auth.connectorId) || '';
417561
417988
  const { bot_id: botId = '', type: chatType, appInfo } = chatConfig;
@@ -417603,6 +418030,9 @@ const useRequestInit = ()=>{
417603
418030
  const actualSectionId = requestDataConversationInfo.lastSectionId || '';
417604
418031
  // 如果从 openRequestInit 返回了 conversationName,使用它
417605
418032
  const actualConversationName = conversationName || '';
418033
+ // 从 ref 中获取最新的 currentConversationInfo 和 conversations
418034
+ const currentConversationInfo = currentConversationInfoRef.current;
418035
+ const conversations = conversationsRef.current;
417606
418036
  if (actualConversationId) {
417607
418037
  // 检查 currentConversationInfo 是否与实际的 conversationId 一致
417608
418038
  // 如果 currentConversationInfo.id 为空字符串,说明是从空会话创建的,此时不应该更新
@@ -417650,14 +418080,21 @@ const useRequestInit = ()=>{
417650
418080
  });
417651
418081
  }
417652
418082
  } else {
417653
- // 如果 conversationId 一致,更新 sectionId 和 name(如果有)
418083
+ // 如果 conversationId 一致,只更新 sectionId(如果有变化)
418084
+ // 不更新 name,因为 name 会通过 conversation.update 事件自动更新
418085
+ // 这样可以避免 title/name 更新时触发重新初始化
417654
418086
  const updates = {};
417655
418087
  if (currentConversationInfo.last_section_id !== actualSectionId && actualSectionId) {
417656
418088
  updates.last_section_id = actualSectionId;
417657
418089
  }
417658
- if (actualConversationName && currentConversationInfo.name !== actualConversationName) {
417659
- updates.name = actualConversationName;
417660
- }
418090
+ // 移除 name 的更新,因为 name 会通过 conversation.update 事件自动更新
418091
+ // 这样可以避免 title/name 更新时触发重新初始化
418092
+ // if (
418093
+ // actualConversationName &&
418094
+ // currentConversationInfo.name !== actualConversationName
418095
+ // ) {
418096
+ // updates.name = actualConversationName;
418097
+ // }
417661
418098
  if (Object.keys(updates).length > 0) {
417662
418099
  updateCurrentConversationInfo({
417663
418100
  ...currentConversationInfo,
@@ -417711,8 +418148,8 @@ const useRequestInit = ()=>{
417711
418148
  onDefaultHistoryClear,
417712
418149
  chatType,
417713
418150
  appInfo,
417714
- currentConversationInfo,
417715
- conversations,
418151
+ // 不再依赖 currentConversationInfo 和 conversations
418152
+ // 在函数内部通过 getState() 获取最新值,避免 title/name 更新时触发重新初始化
417716
418153
  updateCurrentConversationInfo,
417717
418154
  userInfo,
417718
418155
  openRequestInit
@@ -418056,7 +418493,27 @@ class MessageConverterToSdk {
418056
418493
  const contentType = messageBody.content_type;
418057
418494
  const content = messageBody.query;
418058
418495
  const shortcutCommand = messageBody.shortcut_command;
418059
- return JSON.stringify({
418496
+ // API 要求 parameters 是 string 类型,如果传入的是对象,需要转换为 JSON 字符串
418497
+ // 如果 parameters 是对象,需要递归序列化所有嵌套对象(包括 SETTING 等字段)
418498
+ let parametersString;
418499
+ if (parameters) {
418500
+ if (typeof parameters === 'string') {
418501
+ // 如果已经是字符串,尝试解析并重新序列化,确保内部对象(如 SETTING)也被序列化
418502
+ try {
418503
+ const parsed = JSON.parse(parameters);
418504
+ parametersString = JSON.stringify(parsed);
418505
+ } catch {
418506
+ // 如果解析失败,说明不是有效的 JSON 字符串,直接使用原值
418507
+ parametersString = parameters;
418508
+ }
418509
+ } else if (typeof parameters === 'object') {
418510
+ // 如果是对象,直接序列化(JSON.stringify 会递归序列化所有嵌套对象)
418511
+ parametersString = JSON.stringify(parameters);
418512
+ } else {
418513
+ parametersString = String(parameters);
418514
+ }
418515
+ }
418516
+ const requestBody = {
418060
418517
  bot_id: messageBody.bot_id,
418061
418518
  user_id: userInfo === null || userInfo === void 0 ? void 0 : userInfo.id,
418062
418519
  stream: true,
@@ -418064,10 +418521,11 @@ class MessageConverterToSdk {
418064
418521
  additional_messages: [
418065
418522
  this.convertRequestMessage(contentType, content)
418066
418523
  ],
418067
- parameters,
418524
+ parameters: parametersString,
418068
418525
  shortcut_command: this.convertShortcuts(shortcuts || [], shortcutCommand),
418069
418526
  enable_card: true
418070
- });
418527
+ };
418528
+ return JSON.stringify(requestBody);
418071
418529
  }
418072
418530
  // 替换 chat请求中的 message部分
418073
418531
  convertRequestMessage(contentType, content) {
@@ -419730,7 +420188,7 @@ const src_timeoutPromise = (ms)=>new Promise((resolve)=>{
419730
420188
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
419731
420189
  * See the License for the specific language governing permissions and
419732
420190
  * limitations under the License.
419733
- */ function message_parser_define_property(obj, key, value) {
420191
+ */ /* eslint-disable max-lines */ function message_parser_define_property(obj, key, value) {
419734
420192
  if (key in obj) {
419735
420193
  Object.defineProperty(obj, key, {
419736
420194
  value: value,
@@ -419752,6 +420210,7 @@ const src_timeoutPromise = (ms)=>new Promise((resolve)=>{
419752
420210
 
419753
420211
 
419754
420212
 
420213
+
419755
420214
  // 消息解析,主要用于从服务端获取到消息后,解析成coze能适配的数据结构
419756
420215
  var message_parser_ChunkEvent = /*#__PURE__*/ (/* unused pure expression or super */ null && (function(ChunkEvent) {
419757
420216
  ChunkEvent["ERROR"] = "error";
@@ -419776,7 +420235,8 @@ class MessageParser {
419776
420235
  }
419777
420236
  case "conversation.message.delta":
419778
420237
  {
419779
- const message = this.createMessage(data, false);
420238
+ // conversation.message.delta 不应该累积和合并,应该直接使用新内容
420239
+ const message = this.createMessage(data, false, false);
419780
420240
  if (!message) {
419781
420241
  return;
419782
420242
  }
@@ -419784,7 +420244,8 @@ class MessageParser {
419784
420244
  }
419785
420245
  case "conversation.message.completed":
419786
420246
  {
419787
- const messageResult = this.createMessage(data, true);
420247
+ // conversation.message.completed 不应该累积和合并,应该直接使用新内容
420248
+ const messageResult = this.createMessage(data, true, false);
419788
420249
  // 清理流式 JSON 累积内容
419789
420250
  if (messageResult && typeof messageResult === 'object' && 'data' in messageResult) {
419790
420251
  const messageData = messageResult.data;
@@ -419795,6 +420256,8 @@ class MessageParser {
419795
420256
  if (contentKey) {
419796
420257
  this.streamingJsonContent.delete(contentKey);
419797
420258
  this.lastValidJsonContent.delete(contentKey);
420259
+ this.lastReturnedParsedContent.delete(contentKey);
420260
+ this.lastReturnedAccumulatedContent.delete(contentKey);
419798
420261
  }
419799
420262
  }
419800
420263
  }
@@ -419841,7 +420304,7 @@ class MessageParser {
419841
420304
  }
419842
420305
  }
419843
420306
  createMessage(data) {
419844
- let isComplete = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
420307
+ let isComplete = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false, shouldAccumulate = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : true;
419845
420308
  const dataValue = catchParse(data);
419846
420309
  if (!dataValue) {
419847
420310
  return;
@@ -419852,31 +420315,124 @@ class MessageParser {
419852
420315
  // 处理流式 JSON:当 content_type 是 object_string 且 type 是 answer 时
419853
420316
  const isStreamingJson = dataValue.content_type === 'object_string' && dataValue.type === 'answer';
419854
420317
  if (isStreamingJson && dataValue.content) {
419855
- // 使用 messageId chatId 作为 key 来累积内容
419856
- const contentKey = dataValue.id || dataValue.chat_id || '';
420318
+ // 对于流式 object_string 消息,使用 id 作为 key 来累积内容
420319
+ // 这样可以确保不同 id 的消息不会被合并
420320
+ // 但是,只有 shouldAccumulate 为 true 时才累积(conversation.chat.* 事件)
420321
+ // conversation.message.delta 不应该累积,应该直接使用新内容
420322
+ const contentKey = dataValue.id || '';
419857
420323
  if (contentKey) {
419858
- // 累积流式 JSON 内容
419859
- const accumulatedContent = this.streamingJsonContent.get(contentKey) || '';
419860
- const newContent = accumulatedContent + dataValue.content;
419861
- this.streamingJsonContent.set(contentKey, newContent);
419862
- // 尝试解析累积的内容
419863
- const parsedContent = this.tryParseStreamingJson(newContent);
419864
- if (parsedContent !== null) {
419865
- // 如果解析成功,使用解析后的内容,并保存为最后一次有效内容
419866
- dataValue.content = parsedContent;
419867
- this.lastValidJsonContent.set(contentKey, parsedContent);
420324
+ let newContent;
420325
+ if (shouldAccumulate) {
420326
+ // 累积流式 JSON 内容(conversation.chat.* 事件)
420327
+ const accumulatedContent = this.streamingJsonContent.get(contentKey) || '';
420328
+ newContent = accumulatedContent + dataValue.content;
420329
+ this.streamingJsonContent.set(contentKey, newContent);
419868
420330
  } else {
419869
- // 如果解析失败(JSON 不完整),使用上一次成功解析的内容(如果有)
419870
- // 这样可以避免每次 delta 都创建新消息,导致重复渲染
419871
- const lastValidContent = this.lastValidJsonContent.get(contentKey);
419872
- if (lastValidContent) {
419873
- // 使用上一次成功解析的内容,避免重复渲染
419874
- dataValue.content = lastValidContent;
419875
- } else {
419876
- // 如果完全没有成功解析的内容,使用累积的原始内容
419877
- // 但这样可能会导致 convertMixContent 失败,返回 undefined
419878
- dataValue.content = newContent;
420331
+ // 不累积,直接使用新内容(conversation.message.delta 事件)
420332
+ newContent = dataValue.content;
420333
+ }
420334
+ // 对于流式数组,我们需要传递完整的累积内容,而不是部分解析的内容
420335
+ // 检查数组是否完整(以 ] 结尾)
420336
+ const trimmedContent = newContent.trim();
420337
+ const isArrayComplete = trimmedContent.startsWith('[') && trimmedContent.endsWith(']');
420338
+ if (isArrayComplete) {
420339
+ // 数组完整,尝试解析完整的数组
420340
+ try {
420341
+ const parsed = JSON.parse(trimmedContent);
420342
+ if (Array.isArray(parsed)) {
420343
+ // 解析成功
420344
+ // 如果是 completed 消息,直接使用新的内容,不合并
420345
+ // 如果是 delta 消息,合并数组中元素的 json 字段
420346
+ let mergedArray = parsed;
420347
+ if (!isComplete && shouldAccumulate) {
420348
+ // 只对 delta 消息且 shouldAccumulate 为 true 时进行合并
420349
+ // 获取上一次解析的内容
420350
+ const lastValidContent = this.lastValidJsonContent.get(contentKey);
420351
+ if (lastValidContent) {
420352
+ try {
420353
+ const lastParsed = JSON.parse(lastValidContent);
420354
+ if (Array.isArray(lastParsed) && lastParsed.length > 0 && parsed.length > 0) {
420355
+ // 合并第一个元素的 json 字段
420356
+ const lastFirstItem = lastParsed[0];
420357
+ const currFirstItem = parsed[0];
420358
+ if (typeof lastFirstItem === 'object' && lastFirstItem !== null && typeof currFirstItem === 'object' && currFirstItem !== null && 'json' in lastFirstItem && 'json' in currFirstItem && typeof lastFirstItem.json === 'object' && lastFirstItem.json !== null && typeof currFirstItem.json === 'object' && currFirstItem.json !== null) {
420359
+ // 合并 json 字段(深度合并对象)
420360
+ const mergedJson = this.mergeJsonObjects(lastFirstItem.json, currFirstItem.json);
420361
+ // 创建合并后的第一个元素
420362
+ mergedArray = [
420363
+ {
420364
+ ...currFirstItem,
420365
+ json: mergedJson
420366
+ },
420367
+ ...parsed.slice(1)
420368
+ ];
420369
+ }
420370
+ }
420371
+ } catch (parseError) {
420372
+ // 解析上一次内容失败,使用当前解析的内容
420373
+ // Error is intentionally ignored as we fallback to current parsed content
420374
+ void parseError;
420375
+ }
420376
+ }
420377
+ } else {
420378
+ // completed 消息:直接使用新的内容,不合并
420379
+ }
420380
+ const parsedContent = JSON.stringify(mergedArray);
420381
+ dataValue.content = parsedContent;
420382
+ this.lastValidJsonContent.set(contentKey, parsedContent);
420383
+ } else {
420384
+ // 不是数组,使用原始内容
420385
+ dataValue.content = newContent;
420386
+ }
420387
+ } catch (e) {
420388
+ // 解析失败,可能是多个数组拼接(如 [{...}][{...}]),尝试合并
420389
+ const mergedArray = this.mergeStreamingArrays(trimmedContent);
420390
+ if (mergedArray !== null) {
420391
+ // 如果是 completed 消息,直接使用新的内容,不合并
420392
+ // 如果是 delta 消息,合并数组中元素的 json 字段
420393
+ let finalMergedArray = mergedArray;
420394
+ if (!isComplete && shouldAccumulate) {
420395
+ // 只对 delta 消息且 shouldAccumulate 为 true 时进行合并
420396
+ const lastValidContent = this.lastValidJsonContent.get(contentKey);
420397
+ if (lastValidContent) {
420398
+ try {
420399
+ const lastParsed = JSON.parse(lastValidContent);
420400
+ if (Array.isArray(lastParsed) && lastParsed.length > 0 && mergedArray.length > 0) {
420401
+ // 合并第一个元素的 json 字段
420402
+ const lastFirstItem = lastParsed[0];
420403
+ const currFirstItem = mergedArray[0];
420404
+ if (typeof lastFirstItem === 'object' && lastFirstItem !== null && typeof currFirstItem === 'object' && currFirstItem !== null && 'json' in lastFirstItem && 'json' in currFirstItem && typeof lastFirstItem.json === 'object' && lastFirstItem.json !== null && typeof currFirstItem.json === 'object' && currFirstItem.json !== null) {
420405
+ // 合并 json 字段(深度合并对象)
420406
+ const mergedJson = this.mergeJsonObjects(lastFirstItem.json, currFirstItem.json);
420407
+ // 创建合并后的第一个元素
420408
+ finalMergedArray = [
420409
+ {
420410
+ ...currFirstItem,
420411
+ json: mergedJson
420412
+ },
420413
+ ...mergedArray.slice(1)
420414
+ ];
420415
+ }
420416
+ }
420417
+ } catch (parseError) {
420418
+ // 解析上一次内容失败,使用当前合并的数组
420419
+ // Error is intentionally ignored as we fallback to current merged array
420420
+ void parseError;
420421
+ }
420422
+ }
420423
+ }
420424
+ const parsedContent = JSON.stringify(finalMergedArray);
420425
+ dataValue.content = parsedContent;
420426
+ this.lastValidJsonContent.set(contentKey, parsedContent);
420427
+ } else {
420428
+ // 合并失败,使用原始内容
420429
+ dataValue.content = newContent;
420430
+ }
419879
420431
  }
420432
+ } else {
420433
+ // 数组不完整,使用累积的原始内容
420434
+ // convertMixContent 会尝试解析部分数组,如果失败会返回 undefined
420435
+ dataValue.content = newContent;
419880
420436
  }
419881
420437
  }
419882
420438
  }
@@ -419887,7 +420443,8 @@ class MessageParser {
419887
420443
  // 对于流式 JSON,如果 convertMixContent 返回 undefined(JSON 不完整),
419888
420444
  // 且没有上一次成功解析的内容,不返回消息,避免重复渲染
419889
420445
  if (isStreamingJson && !isComplete && message.content_type === types_ContentType.Mix && (!message.content || message.content === 'undefined')) {
419890
- const contentKey = dataValue.id || dataValue.chat_id || '';
420446
+ // 对于流式 object_string 消息,使用 id 作为 key
420447
+ const contentKey = dataValue.id || '';
419891
420448
  const lastValidContent = contentKey ? this.lastValidJsonContent.get(contentKey) : undefined;
419892
420449
  // 如果没有上一次成功解析的内容,不返回消息
419893
420450
  if (!lastValidContent) {
@@ -419896,15 +420453,30 @@ class MessageParser {
419896
420453
  // 如果有上一次成功解析的内容,使用它
419897
420454
  message.content = lastValidContent;
419898
420455
  }
420456
+ // 对于流式 object_string 消息,检查内容是否真正变化
420457
+ // 如果内容没有变化,且不是完成消息,则不返回消息,避免重复渲染
420458
+ if (isStreamingJson && !isComplete && message.message_id) {
420459
+ // 对于流式 object_string 消息,使用 id 作为 key
420460
+ const contentKey = dataValue.id || '';
420461
+ if (contentKey) {
420462
+ // 比较转换后的 message.content(这是最终传递给 UI 的内容)
420463
+ const currentMessageContent = message.content || '';
420464
+ const lastReturnedMessageContent = this.lastReturnedParsedContent.get(contentKey) || '';
420465
+ // 如果转换后的内容没有变化,不返回消息
420466
+ if (currentMessageContent && lastReturnedMessageContent && currentMessageContent === lastReturnedMessageContent) {
420467
+ // 内容没有变化,不返回消息
420468
+ return;
420469
+ }
420470
+ // 更新上一次返回的转换后的内容
420471
+ if (currentMessageContent) {
420472
+ this.lastReturnedParsedContent.set(contentKey, currentMessageContent);
420473
+ }
420474
+ }
420475
+ }
419899
420476
  if (isComplete && message.content_type === types_ContentType.Text && message.type === 'answer') {
419900
420477
  message.content = '';
419901
- } else if (isComplete && message.content_type === types_ContentType.Mix && message.type === 'answer') {
419902
- message.content = JSON.stringify({
419903
- item_list: []
419904
- });
419905
420478
  }
419906
420479
  message.section_id = message.section_id || this.sectionId;
419907
- console.log('createMessage message', message);
419908
420480
  return {
419909
420481
  event: 'message',
419910
420482
  data: {
@@ -419920,6 +420492,127 @@ class MessageParser {
419920
420492
  };
419921
420493
  }
419922
420494
  /**
420495
+ * 合并两个 JSON 对象(深度合并)
420496
+ * - 如果两个值都是对象,递归合并
420497
+ * - 如果两个值都是字符串,追加字符串
420498
+ * - 如果两个值都是数组,合并数组(按索引合并)
420499
+ * - 否则使用 curr 的值(覆盖)
420500
+ */ mergeJsonObjects(prev, curr) {
420501
+ const merged = {
420502
+ ...prev
420503
+ };
420504
+ for(const key in curr){
420505
+ if (Object.prototype.hasOwnProperty.call(curr, key)) {
420506
+ const prevValue = prev[key];
420507
+ const currValue = curr[key];
420508
+ // 如果两个值都是对象,递归合并
420509
+ if (typeof prevValue === 'object' && prevValue !== null && !Array.isArray(prevValue) && typeof currValue === 'object' && currValue !== null && !Array.isArray(currValue)) {
420510
+ merged[key] = this.mergeJsonObjects(prevValue, currValue);
420511
+ } else if (typeof prevValue === 'string' && typeof currValue === 'string') {
420512
+ // 如果两个值都是字符串,追加字符串
420513
+ merged[key] = prevValue + currValue;
420514
+ } else if (Array.isArray(prevValue) && Array.isArray(currValue)) {
420515
+ // 如果两个值都是数组,按索引合并
420516
+ const mergedArray = [
420517
+ ...prevValue
420518
+ ];
420519
+ for(let i = 0; i < currValue.length; i++){
420520
+ const currItem = currValue[i];
420521
+ if (i < mergedArray.length) {
420522
+ // 如果索引已存在,尝试合并
420523
+ const prevItem = mergedArray[i];
420524
+ if (typeof prevItem === 'object' && prevItem !== null && !Array.isArray(prevItem) && typeof currItem === 'object' && currItem !== null && !Array.isArray(currItem)) {
420525
+ mergedArray[i] = this.mergeJsonObjects(prevItem, currItem);
420526
+ } else {
420527
+ mergedArray[i] = currItem;
420528
+ }
420529
+ } else {
420530
+ // 如果索引超出范围,追加新元素
420531
+ mergedArray.push(currItem);
420532
+ }
420533
+ }
420534
+ merged[key] = mergedArray;
420535
+ } else {
420536
+ // 否则使用 curr 的值(覆盖)
420537
+ merged[key] = currValue;
420538
+ }
420539
+ }
420540
+ }
420541
+ return merged;
420542
+ }
420543
+ /**
420544
+ * 合并多个流式数组(如 [{...}][{...}] 合并为 [{...},{...}])
420545
+ * 返回合并后的数组,如果无法合并则返回 null
420546
+ */ mergeStreamingArrays(content) {
420547
+ if (!content || !content.trim().startsWith('[')) {
420548
+ return null;
420549
+ }
420550
+ const trimmed = content.trim();
420551
+ const arrays = [];
420552
+ let currentIndex = 0;
420553
+ while(currentIndex < trimmed.length){
420554
+ // 跳过空白字符
420555
+ while(currentIndex < trimmed.length && /\s/.test(trimmed[currentIndex])){
420556
+ currentIndex++;
420557
+ }
420558
+ if (currentIndex >= trimmed.length || trimmed[currentIndex] !== '[') {
420559
+ break;
420560
+ }
420561
+ // 找到完整的数组
420562
+ let bracketCount = 0;
420563
+ let inString = false;
420564
+ let escapeNext = false;
420565
+ let arrayEndIndex = -1;
420566
+ for(let i = currentIndex; i < trimmed.length; i++){
420567
+ const char = trimmed[i];
420568
+ if (escapeNext) {
420569
+ escapeNext = false;
420570
+ continue;
420571
+ }
420572
+ if (char === '\\') {
420573
+ escapeNext = true;
420574
+ continue;
420575
+ }
420576
+ if (char === '"') {
420577
+ inString = !inString;
420578
+ continue;
420579
+ }
420580
+ if (inString) {
420581
+ continue;
420582
+ }
420583
+ if (char === '[') {
420584
+ bracketCount++;
420585
+ } else if (char === ']') {
420586
+ bracketCount--;
420587
+ if (bracketCount === 0) {
420588
+ arrayEndIndex = i;
420589
+ break;
420590
+ }
420591
+ }
420592
+ }
420593
+ if (arrayEndIndex > currentIndex) {
420594
+ try {
420595
+ const arrayStr = trimmed.substring(currentIndex, arrayEndIndex + 1);
420596
+ const parsed = JSON.parse(arrayStr);
420597
+ if (Array.isArray(parsed)) {
420598
+ arrays.push(...parsed);
420599
+ } else {
420600
+ arrays.push(parsed);
420601
+ }
420602
+ currentIndex = arrayEndIndex + 1;
420603
+ } catch (parseError) {
420604
+ // 解析失败,停止合并
420605
+ // Error is intentionally ignored as we break the loop
420606
+ void parseError;
420607
+ break;
420608
+ }
420609
+ } else {
420610
+ break;
420611
+ }
420612
+ }
420613
+ return arrays.length > 0 ? arrays : null;
420614
+ }
420615
+ /**
419923
420616
  * 尝试解析流式 JSON 内容
419924
420617
  * 如果 JSON 不完整,返回 null;如果解析成功,返回完整的 JSON 字符串
419925
420618
  */ tryParseStreamingJson(content) {
@@ -420133,6 +420826,10 @@ class MessageParser {
420133
420826
  message_parser_define_property(this, "streamingJsonContent", new Map());
420134
420827
  // 用于存储上一次成功解析的完整 JSON 内容,避免重复渲染
420135
420828
  message_parser_define_property(this, "lastValidJsonContent", new Map());
420829
+ // 用于存储上一次返回的解析后的 JSON 内容,用于检测内容是否真正变化
420830
+ message_parser_define_property(this, "lastReturnedParsedContent", new Map());
420831
+ // 用于存储上一次返回的原始累积内容,用于检测 JSON 不完整时内容是否变化
420832
+ message_parser_define_property(this, "lastReturnedAccumulatedContent", new Map());
420136
420833
  this.conversationId = requestMessageRawBody.conversation_id;
420137
420834
  this.localMessageId = requestMessageRawBody.local_message_id;
420138
420835
  this.sendMessageContent = requestMessageRawBody.query;
@@ -420217,6 +420914,7 @@ class MessageParser {
420217
420914
  const updateCurrentConversationInfoFn = refUpdateCurrentConversationInfo.current;
420218
420915
  const { title } = updates;
420219
420916
  if (title !== undefined) {
420917
+ var _refPendingConversationInfo_current;
420220
420918
  // 更新会话列表中的会话名称
420221
420919
  // 注意:PC 端和 Mobile 端都优先使用 title,如果没有 title 则使用 name
420222
420920
  // 对于 App 模式,需要同时更新 name 和 title
@@ -420229,30 +420927,70 @@ class MessageParser {
420229
420927
  title,
420230
420928
  updated_at: Math.floor(updated_at / 1000)
420231
420929
  };
420232
- updateConversationsFn([
420233
- updatedConversationObj
420234
- ], 'update');
420930
+ if (updateConversationsFn) {
420931
+ updateConversationsFn([
420932
+ updatedConversationObj
420933
+ ], 'update');
420934
+ }
420235
420935
  // 如果当前会话是被更新的会话,同时更新 currentConversationInfo
420236
420936
  // 修复:无论ref是否是最新的,都更新currentConversationInfo,确保header能显示title
420237
420937
  // updateCurrentConversationInfo函数会合并字段,所以即使ref不是最新的,title也会被正确设置
420238
420938
  // 从conversations列表中查找对应的会话,如果找到说明这个会话存在,可能是当前会话
420239
420939
  const conversationsList = refConversations.current;
420240
420940
  const foundConversation = conversationsList.find((c)=>c.id === conversation_id);
420941
+ // 检查是否是当前会话或待处理的会话
420942
+ // 1. 如果 refCurrentConversationInfo.current.id 匹配,说明是当前会话
420943
+ // 2. 如果 refPendingConversationInfo.current.conversationId 匹配,说明是新创建的会话,但 currentConversationInfo 还没有更新
420944
+ const isCurrentConversation = (currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.id) === conversation_id;
420945
+ const isPendingConversation = ((_refPendingConversationInfo_current = refPendingConversationInfo.current) === null || _refPendingConversationInfo_current === void 0 ? void 0 : _refPendingConversationInfo_current.conversationId) === conversation_id;
420241
420946
  // 如果ref中的id匹配,或者找到了对应的会话,就更新title
420242
420947
  // 这样可以确保即使ref不是最新的,也能正确更新title
420243
- if ((currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.id) === conversation_id || foundConversation) {
420948
+ // 注意:只有当 conversation_id 与当前会话的 id 匹配时才更新 currentConversationInfo
420949
+ // 这样可以避免在更新其他会话的 title 时触发当前会话的重新初始化
420950
+ if (isCurrentConversation || isPendingConversation) {
420244
420951
  // 优先使用ref中的currentConversationInfo,保留其所有字段
420245
- // 如果ref中没有,使用conversations列表中的信息
420246
- const baseInfo = currentConversation || foundConversation;
420247
- updateCurrentConversationInfoFn({
420248
- ...baseInfo || {},
420249
- id: conversation_id,
420250
- name: title,
420251
- title,
420252
- // 保留currentConversationInfo特有的字段
420253
- conversationListVisible: (currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.conversationListVisible) ?? false,
420254
- isLargeWidth: (currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.isLargeWidth) ?? false
420255
- });
420952
+ // 只更新 title 和 name,不改变其他字段,避免触发不必要的重新初始化
420953
+ if (currentConversation) {
420954
+ // 只有当 title 或 name 真的发生变化时才更新,避免创建不必要的对象引用
420955
+ if (currentConversation.title !== title || currentConversation.name !== title) {
420956
+ updateCurrentConversationInfoFn({
420957
+ ...currentConversation,
420958
+ name: title,
420959
+ title,
420960
+ updated_at: Math.floor(updated_at / 1000)
420961
+ });
420962
+ }
420963
+ } else if (foundConversation) {
420964
+ // 如果 currentConversation 不存在但找到了会话,使用找到的会话信息
420965
+ // 注意:foundConversation 是 Conversation 类型,不包含 conversationListVisible 和 isLargeWidth
420966
+ // 这些字段只在 currentConversationInfo 中存在,所以使用默认值
420967
+ updateCurrentConversationInfoFn({
420968
+ ...foundConversation,
420969
+ name: title,
420970
+ title,
420971
+ updated_at: Math.floor(updated_at / 1000),
420972
+ // 使用默认值,因为 foundConversation 不包含这些字段
420973
+ conversationListVisible: false,
420974
+ isLargeWidth: false
420975
+ });
420976
+ } else if (isPendingConversation && refPendingConversationInfo.current) {
420977
+ // 如果是待处理的会话,但 currentConversation 和 foundConversation 都不存在
420978
+ // 使用 refPendingConversationInfo 中的信息创建新的 currentConversationInfo
420979
+ const pendingInfo = refPendingConversationInfo.current;
420980
+ // 从 refCurrentConversationInfo 获取保留的字段(如果存在)
420981
+ const existingInfo = refCurrentConversationInfo.current;
420982
+ updateCurrentConversationInfoFn({
420983
+ id: pendingInfo.conversationId,
420984
+ last_section_id: pendingInfo.sectionId,
420985
+ name: title,
420986
+ title,
420987
+ created_at: Math.floor(Date.now() / 1000),
420988
+ updated_at: Math.floor(updated_at / 1000),
420989
+ meta_data: {},
420990
+ conversationListVisible: (existingInfo === null || existingInfo === void 0 ? void 0 : existingInfo.conversationListVisible) ?? false,
420991
+ isLargeWidth: (existingInfo === null || existingInfo === void 0 ? void 0 : existingInfo.isLargeWidth) ?? false
420992
+ });
420993
+ }
420256
420994
  }
420257
420995
  }
420258
420996
  };
@@ -420346,12 +421084,28 @@ class MessageParser {
420346
421084
  conversationName: conversationResult.conversationName
420347
421085
  });
420348
421086
  }
420349
- // 只更新 messageBody 中的 conversation_id
420350
- // 不在这里更新 currentConversationInfo 或调用 setConversationId
420351
- // 这些更新会在消息发送成功后通过消息解析器进行
420352
- // 避免在消息发送前触发状态更新,导致 SDK 重新初始化
421087
+ // 选中新创建的会话:先更新 currentConversationInfo,确保会话被选中
421088
+ // 不立即调用 updateCurrentConversationInfo,避免触发组件卸载
421089
+ // 将在消息流完成(DONE 事件)时更新 currentConversationInfo
421090
+ // 这样可以避免触发 useRequestInit 的依赖变化,防止重新初始化
421091
+ // 会话列表中的新会话已经通过 updateConversations 添加,可以正常显示
421092
+ console.log('onBeforeSendMessage: Conversation created, will update currentConversationInfo after stream completes', {
421093
+ conversationId: conversationResult.conversationId
421094
+ });
421095
+ // 确保 pendingInfo 被设置,以便在 DONE 事件时更新
421096
+ if (refPendingConversationInfo) {
421097
+ refPendingConversationInfo.current = {
421098
+ conversationId: conversationResult.conversationId,
421099
+ sectionId: conversationResult.sectionId || ''
421100
+ };
421101
+ }
421102
+ // 注意:不在这里调用 setConversationId,因为它会触发额外的 updateConversations 调用
421103
+ // 这会导致 useConversationList 的同步逻辑被触发,设置 isSyncing = true
421104
+ // 当真正的 store 更新发生时,isSyncing 仍然是 true,导致 useEffect 被跳过
421105
+ // setConversationId 会在消息流完成时被调用(在 onGetMessageStreamParser 的 DONE 事件中)
421106
+ // 更新 messageBody 中的 conversation_id
420353
421107
  messageBody.conversation_id = conversationId;
420354
- console.log('onBeforeSendMessage: Conversation created, will update state after message sent', {
421108
+ console.log('onBeforeSendMessage: Conversation created and selected, ready to send message', {
420355
421109
  conversationId,
420356
421110
  pendingInfo: refPendingConversationInfo.current
420357
421111
  });
@@ -420367,7 +421121,7 @@ class MessageParser {
420367
421121
  throw new Error('conversationId is required for sending message');
420368
421122
  }
420369
421123
  // 使用计算后的 API URL
420370
- const url = `${finalApiUrl}/v3/chat?conversation_id=${conversationId}`;
421124
+ const url = `${finalApiUrl}/v1/workflows/chat?conversation_id=${conversationId}`;
420371
421125
  // 根据 chatType 选择正确的 parameters 来源
420372
421126
  // App 模式使用 appInfo.parameters,Bot 模式使用 botInfo.parameters
420373
421127
  const parameters = ((_refChatConfig_current = refChatConfig.current) === null || _refChatConfig_current === void 0 ? void 0 : _refChatConfig_current.type) === client_ChatType.APP ? (_refChatConfig_current_appInfo = refChatConfig.current.appInfo) === null || _refChatConfig_current_appInfo === void 0 ? void 0 : _refChatConfig_current_appInfo.parameters : (_refChatConfig_current_botInfo = refChatConfig.current.botInfo) === null || _refChatConfig_current_botInfo === void 0 ? void 0 : _refChatConfig_current_botInfo.parameters;
@@ -420512,6 +421266,8 @@ class MessageParser {
420512
421266
  // 使用 setTimeout 确保在消息发送流程完全完成后更新状态
420513
421267
  setTimeout(()=>{
420514
421268
  if (refUpdateCurrentConversationInfo.current) {
421269
+ // 保留当前的 conversationListVisible 和 isLargeWidth,避免会话列表被收起
421270
+ const currentInfo = refCurrentConversationInfo.current;
420515
421271
  refUpdateCurrentConversationInfo.current({
420516
421272
  id: pendingInfo.conversationId,
420517
421273
  last_section_id: pendingInfo.sectionId,
@@ -420520,8 +421276,10 @@ class MessageParser {
420520
421276
  created_at: Math.floor(Date.now() / 1000),
420521
421277
  updated_at: Math.floor(Date.now() / 1000),
420522
421278
  meta_data: {},
420523
- conversationListVisible: false,
420524
- isLargeWidth: false
421279
+ // 保留当前的 conversationListVisible,避免会话列表被收起
421280
+ conversationListVisible: (currentInfo === null || currentInfo === void 0 ? void 0 : currentInfo.conversationListVisible) ?? false,
421281
+ // 保留当前的 isLargeWidth
421282
+ isLargeWidth: (currentInfo === null || currentInfo === void 0 ? void 0 : currentInfo.isLargeWidth) ?? false
420525
421283
  });
420526
421284
  }
420527
421285
  if (refChatFunc === null || refChatFunc === void 0 ? void 0 : refChatFunc.current) {
@@ -423643,36 +424401,89 @@ const ChatProviderFuncComp = /*#__PURE__*/ (0,react.forwardRef)((param, ref)=>{
423643
424401
  // 监听 currentConversationInfo 的变化,同步更新 chat-area 的 conversationId 和 sectionId
423644
424402
  // 这样当切换会话时,可以避免出现"上下文已清除"提示
423645
424403
  // 注意:必须在消息加载之前更新 sectionId,否则会触发上下文分隔线
424404
+ // 使用 ref 来存储上一次的 id 和 last_section_id,避免 title/name 更新时触发重新初始化
424405
+ const prevConversationIdRef = (0,react.useRef)(undefined);
424406
+ const prevSectionIdRef = (0,react.useRef)(undefined);
424407
+ // 使用 useMemo 来稳定 id 和 last_section_id 的值,避免对象引用变化导致 useEffect 触发
424408
+ const stableConversationId = (0,react.useMemo)(()=>currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id, [
424409
+ currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id
424410
+ ]);
424411
+ const stableLastSectionId = (0,react.useMemo)(()=>currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.last_section_id, [
424412
+ currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.last_section_id
424413
+ ]);
424414
+ // 更新 sectionId 的辅助函数
424415
+ const updateSectionIdIfNeeded = useMemoizedFn((targetSectionId, currentSectionId)=>{
424416
+ if (targetSectionId && targetSectionId !== currentSectionId) {
424417
+ const { setLatestSectionId } = useSectionIdStore.getState();
424418
+ setLatestSectionId(targetSectionId);
424419
+ }
424420
+ });
424421
+ // 检查是否需要更新的辅助函数
424422
+ const shouldSkipUpdate = useMemoizedFn((currentId, currentSectionId, refs)=>{
424423
+ const isFirstRun = refs.prevIdRef.current === undefined && refs.prevSectionIdRef.current === undefined;
424424
+ const hasIdChanged = !isFirstRun && currentId !== refs.prevIdRef.current;
424425
+ const hasSectionIdChanged = !isFirstRun && currentSectionId !== refs.prevSectionIdRef.current;
424426
+ if (!isFirstRun && !hasIdChanged && !hasSectionIdChanged) {
424427
+ refs.prevIdRef.current = currentId;
424428
+ refs.prevSectionIdRef.current = currentSectionId;
424429
+ return true;
424430
+ }
424431
+ refs.prevIdRef.current = currentId;
424432
+ refs.prevSectionIdRef.current = currentSectionId;
424433
+ return false;
424434
+ });
424435
+ // 更新 conversationId 的辅助函数
424436
+ const updateConversationId = useMemoizedFn((currentId, currentSectionId, isNewConversationFromEmpty)=>{
424437
+ if (isNewConversationFromEmpty) {
424438
+ // 只更新 chatCore 的 conversationId,不调用 setConversationIdInArea
424439
+ // 这样可以避免触发重新初始化,导致正在进行的请求被中止
424440
+ chatCore === null || chatCore === void 0 ? void 0 : chatCore.updateConversationId(currentId);
424441
+ updateSectionIdIfNeeded(currentSectionId, sectionId);
424442
+ } else {
424443
+ // 正常切换会话,立即更新
424444
+ setConversationIdInArea(currentId);
424445
+ chatCore === null || chatCore === void 0 ? void 0 : chatCore.updateConversationId(currentId);
424446
+ updateSectionIdIfNeeded(currentSectionId, sectionId);
424447
+ }
424448
+ });
423646
424449
  (0,react.useEffect)(()=>{
423647
424450
  var _chatConfig_ui_conversations, _chatConfig_ui;
423648
- if ((currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id) && ((_chatConfig_ui = chatConfig.ui) === null || _chatConfig_ui === void 0 ? void 0 : (_chatConfig_ui_conversations = _chatConfig_ui.conversations) === null || _chatConfig_ui_conversations === void 0 ? void 0 : _chatConfig_ui_conversations.isNeed)) {
423649
- const currentId = currentConversationInfo.id;
423650
- const currentConversationWithSectionId = currentConversationInfo;
423651
- const currentSectionId = currentConversationInfo.last_section_id || currentConversationWithSectionId.sectionId || '';
423652
- // 先更新 sectionId,再更新 conversationId,确保消息加载时使用正确的 sectionId
423653
- if (currentSectionId && currentSectionId !== sectionId) {
423654
- const { setLatestSectionId } = useSectionIdStore.getState();
423655
- setLatestSectionId(currentSectionId);
423656
- }
423657
- // 只有当 conversationId 发生变化时才更新
423658
- if (currentId !== conversationId) {
423659
- setConversationIdInArea(currentId);
423660
- chatCore === null || chatCore === void 0 ? void 0 : chatCore.updateConversationId(currentId);
423661
- // 如果 conversationId 变化了,确保 sectionId 也同步更新
423662
- if (currentSectionId && currentSectionId !== sectionId) {
423663
- const { setLatestSectionId } = useSectionIdStore.getState();
423664
- setLatestSectionId(currentSectionId);
423665
- }
423666
- }
424451
+ if (!stableConversationId || !((_chatConfig_ui = chatConfig.ui) === null || _chatConfig_ui === void 0 ? void 0 : (_chatConfig_ui_conversations = _chatConfig_ui.conversations) === null || _chatConfig_ui_conversations === void 0 ? void 0 : _chatConfig_ui_conversations.isNeed)) {
424452
+ return;
424453
+ }
424454
+ const currentId = stableConversationId;
424455
+ const currentConversationWithSectionId = currentConversationInfo;
424456
+ const currentSectionId = stableLastSectionId || currentConversationWithSectionId.sectionId || '';
424457
+ // 先更新 sectionId,再更新 conversationId,确保消息加载时使用正确的 sectionId
424458
+ updateSectionIdIfNeeded(currentSectionId, sectionId);
424459
+ // 检查是否需要跳过更新
424460
+ if (shouldSkipUpdate(currentId, currentSectionId, {
424461
+ prevIdRef: prevConversationIdRef,
424462
+ prevSectionIdRef
424463
+ })) {
424464
+ return;
424465
+ }
424466
+ // 只有当 conversationId 发生变化时才更新
424467
+ if (currentId !== conversationId) {
424468
+ // 如果 conversationId 从空字符串或null变为新ID,说明是从空会话创建的新会话
424469
+ // 此时不应该立即调用 setConversationIdInArea,因为它可能触发重新初始化
424470
+ // 导致正在进行的请求被中止
424471
+ // setConversationIdInArea 会在消息流完成时被调用(在 onGetMessageStreamParser 的 DONE 事件中)
424472
+ const isNewConversationFromEmpty = conversationId === '' || conversationId === null;
424473
+ updateConversationId(currentId, currentSectionId, isNewConversationFromEmpty);
423667
424474
  }
423668
424475
  }, [
423669
- currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id,
423670
- currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.last_section_id,
424476
+ stableConversationId,
424477
+ stableLastSectionId,
423671
424478
  conversationId,
423672
424479
  sectionId,
423673
424480
  setConversationIdInArea,
423674
424481
  chatCore,
423675
- (_chatConfig_ui = chatConfig.ui) === null || _chatConfig_ui === void 0 ? void 0 : (_chatConfig_ui_conversations = _chatConfig_ui.conversations) === null || _chatConfig_ui_conversations === void 0 ? void 0 : _chatConfig_ui_conversations.isNeed
424482
+ (_chatConfig_ui = chatConfig.ui) === null || _chatConfig_ui === void 0 ? void 0 : (_chatConfig_ui_conversations = _chatConfig_ui.conversations) === null || _chatConfig_ui_conversations === void 0 ? void 0 : _chatConfig_ui_conversations.isNeed,
424483
+ updateSectionIdIfNeeded,
424484
+ shouldSkipUpdate,
424485
+ updateConversationId,
424486
+ currentConversationInfo
423676
424487
  ]);
423677
424488
  useUpdateConversationNameByMessage();
423678
424489
  const regenerateMessageByUserMessageId = useRegenerateMessageByUserMessageId();
@@ -435978,6 +436789,7 @@ var header_pc_index_module_update = injectStylesIntoStyleTag_default()(header_pc
435978
436789
 
435979
436790
 
435980
436791
 
436792
+
435981
436793
  const ChatHeader = (param)=>{
435982
436794
  let { iconUrl = coze_logo_namespaceObject, title = 'Coze Bot', extra, theme, isShowConversations, isNeedLogo = true } = param;
435983
436795
  const { headerTopLeftOps } = useChatOpInfo();
@@ -435993,18 +436805,20 @@ const ChatHeader = (param)=>{
435993
436805
  const [renameInputValue, setRenameInputValue] = (0,react.useState)('');
435994
436806
  const [isRenameLoading, setIsRenameLoading] = (0,react.useState)(false);
435995
436807
  // 使用 useMemo 计算显示文本,确保 title 变化时能及时更新
435996
- const conversationTitle = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.title;
435997
- const conversationName = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.name;
435998
436808
  const conversationId = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id;
435999
436809
  const displayTitle = (0,react.useMemo)(()=>{
436000
436810
  if (conversationId === '') {
436001
436811
  return title;
436002
436812
  }
436003
- return conversationTitle || conversationName || title;
436813
+ if (!currentConversationInfo) {
436814
+ return title;
436815
+ }
436816
+ // 使用 getConversationDisplayName 处理 UUID 检查
436817
+ const conversationItem = currentConversationInfo;
436818
+ return getConversationDisplayName(conversationItem) || title;
436004
436819
  }, [
436005
436820
  conversationId,
436006
- conversationTitle,
436007
- conversationName,
436821
+ currentConversationInfo,
436008
436822
  title
436009
436823
  ]);
436010
436824
  // 打开重命名弹窗
@@ -436230,6 +437044,7 @@ var header_mobile_index_module_update = injectStylesIntoStyleTag_default()(heade
436230
437044
 
436231
437045
 
436232
437046
 
437047
+
436233
437048
  const ChatHeaderMobile = (param)=>{
436234
437049
  let { iconUrl = coze_logo_namespaceObject, title = 'Coze Bot', extra, theme, isShowConversations, isNeedLogo = true } = param;
436235
437050
  const { headerTopLeftOps } = useChatOpInfo();
@@ -436245,18 +437060,20 @@ const ChatHeaderMobile = (param)=>{
436245
437060
  const [renameInputValue, setRenameInputValue] = (0,react.useState)('');
436246
437061
  const [isRenameLoading, setIsRenameLoading] = (0,react.useState)(false);
436247
437062
  // 使用 useMemo 计算显示文本,确保 title 变化时能及时更新
436248
- const conversationTitle = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.title;
436249
- const conversationName = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.name;
436250
437063
  const conversationId = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id;
436251
437064
  const displayTitle = (0,react.useMemo)(()=>{
436252
437065
  if (conversationId === '') {
436253
437066
  return title;
436254
437067
  }
436255
- return conversationTitle || conversationName || title;
437068
+ if (!currentConversationInfo) {
437069
+ return title;
437070
+ }
437071
+ // 使用 getConversationDisplayName 处理 UUID 检查
437072
+ const conversationItem = currentConversationInfo;
437073
+ return getConversationDisplayName(conversationItem) || title;
436256
437074
  }, [
436257
437075
  conversationId,
436258
- conversationTitle,
436259
- conversationName,
437076
+ currentConversationInfo,
436260
437077
  title
436261
437078
  ]);
436262
437079
  // 打开重命名弹窗
@@ -437699,7 +438516,20 @@ const use_core_manager_useCoreManager = (props)=>{
437699
438516
  bodyData.additional_messages = bodyDataOld.additional_messages || [];
437700
438517
  bodyData.connector_id = bodyDataOld.connector_id;
437701
438518
  bodyData.workflow_id = refProps === null || refProps === void 0 ? void 0 : (_refProps_current = refProps.current) === null || _refProps_current === void 0 ? void 0 : (_refProps_current_workflow = _refProps_current.workflow) === null || _refProps_current_workflow === void 0 ? void 0 : _refProps_current_workflow.id;
437702
- bodyData.parameters = refProps === null || refProps === void 0 ? void 0 : (_refProps_current1 = refProps.current) === null || _refProps_current1 === void 0 ? void 0 : (_refProps_current_workflow1 = _refProps_current1.workflow) === null || _refProps_current_workflow1 === void 0 ? void 0 : _refProps_current_workflow1.parameters;
438519
+ // parameters 应该是一个对象,但 SETTING 字段的值需要序列化为字符串
438520
+ const workflowParameters = refProps === null || refProps === void 0 ? void 0 : (_refProps_current1 = refProps.current) === null || _refProps_current1 === void 0 ? void 0 : (_refProps_current_workflow1 = _refProps_current1.workflow) === null || _refProps_current_workflow1 === void 0 ? void 0 : _refProps_current_workflow1.parameters;
438521
+ if (workflowParameters && typeof workflowParameters === 'object') {
438522
+ // 复制 parameters 对象,只序列化 SETTING 字段的值
438523
+ const processedParameters = {
438524
+ ...workflowParameters
438525
+ };
438526
+ if (processedParameters.SETTING && typeof processedParameters.SETTING === 'object') {
438527
+ processedParameters.SETTING = JSON.stringify(processedParameters.SETTING);
438528
+ }
438529
+ bodyData.parameters = processedParameters;
438530
+ } else {
438531
+ bodyData.parameters = workflowParameters;
438532
+ }
437703
438533
  bodyData.version = (refProps === null || refProps === void 0 ? void 0 : (_refProps_current2 = refProps.current) === null || _refProps_current2 === void 0 ? void 0 : (_refProps_current_project = _refProps_current2.project) === null || _refProps_current_project === void 0 ? void 0 : _refProps_current_project.version) || undefined;
437704
438534
  bodyData.execute_mode = (refProps === null || refProps === void 0 ? void 0 : (_refProps_current3 = refProps.current) === null || _refProps_current3 === void 0 ? void 0 : (_refProps_current_project1 = _refProps_current3.project) === null || _refProps_current_project1 === void 0 ? void 0 : _refProps_current_project1.mode) === 'draft' ? 'DEBUG' : undefined;
437705
438535
  bodyData.app_id = (refProps === null || refProps === void 0 ? void 0 : (_refProps_current4 = refProps.current) === null || _refProps_current4 === void 0 ? void 0 : (_refProps_current_project2 = _refProps_current4.project) === null || _refProps_current_project2 === void 0 ? void 0 : _refProps_current_project2.type) === 'app' ? refProps === null || refProps === void 0 ? void 0 : (_refProps_current5 = refProps.current) === null || _refProps_current5 === void 0 ? void 0 : (_refProps_current_project3 = _refProps_current5.project) === null || _refProps_current_project3 === void 0 ? void 0 : _refProps_current_project3.id : undefined;
@@ -437715,8 +438545,13 @@ const use_core_manager_useCoreManager = (props)=>{
437715
438545
  customized_suggest_prompt: (_refAppData_current2 = refAppData.current) === null || _refAppData_current2 === void 0 ? void 0 : (_refAppData_current_suggestPromoteInfo1 = _refAppData_current2.suggestPromoteInfo) === null || _refAppData_current_suggestPromoteInfo1 === void 0 ? void 0 : _refAppData_current_suggestPromoteInfo1.customizedSuggestPrompt
437716
438546
  } : undefined;
437717
438547
  requestConfig.body = JSON.stringify(bodyData);
437718
- // 使用计算后的 finalApiUrl
437719
- requestConfig.url = `${finalApiUrl}/v1/workflows/chat`;
438548
+ // 只有在URL还没有被其他hook设置时才设置URL
438549
+ // 如果URL已经包含conversation_id参数(说明已经被useSendMessageAdapter设置了),保留原URL
438550
+ const urlHasConversationId = new URL(requestConfig.url, 'http://dummy.com').searchParams.has('conversation_id');
438551
+ if (!urlHasConversationId) {
438552
+ // 使用计算后的 finalApiUrl
438553
+ requestConfig.url = `${finalApiUrl}/v1/workflows/chat`;
438554
+ }
437720
438555
  requestConfig.headers.push(...Object.entries(((_refProps_current9 = refProps.current) === null || _refProps_current9 === void 0 ? void 0 : (_refProps_current_workflow2 = _refProps_current9.workflow) === null || _refProps_current_workflow2 === void 0 ? void 0 : _refProps_current_workflow2.header) || {}));
437721
438556
  return {
437722
438557
  ...requestConfig