@glodon-aiot/chat-app-sdk 0.0.14 → 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 +1204 -280
- package/libs/cn/index.js +7 -7
- package/package.json +1 -1
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
|
-
|
|
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,
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
407796
|
-
//
|
|
407797
|
-
|
|
407798
|
-
|
|
407799
|
-
|
|
407800
|
-
|
|
407801
|
-
|
|
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
|
-
|
|
407814
|
-
|
|
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
|
-
|
|
407828
|
-
|
|
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
|
-
|
|
407859
|
-
|
|
407860
|
-
|
|
407861
|
-
|
|
407862
|
-
|
|
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
|
-
|
|
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
|
-
|
|
407901
|
-
|
|
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,
|
|
@@ -408020,6 +408291,48 @@ const useGroupedConversations = (conversations)=>{
|
|
|
408020
408291
|
return groupedConversations;
|
|
408021
408292
|
};
|
|
408022
408293
|
|
|
408294
|
+
;// CONCATENATED MODULE: ../open-chat/src/util/conversation-display-name.ts
|
|
408295
|
+
/*
|
|
408296
|
+
* Copyright 2025 coze-dev Authors
|
|
408297
|
+
*
|
|
408298
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
408299
|
+
* you may not use this file except in compliance with the License.
|
|
408300
|
+
* You may obtain a copy of the License at
|
|
408301
|
+
*
|
|
408302
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
408303
|
+
*
|
|
408304
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
408305
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
408306
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
408307
|
+
* See the License for the specific language governing permissions and
|
|
408308
|
+
* limitations under the License.
|
|
408309
|
+
*/
|
|
408310
|
+
// UUID格式判断:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
408311
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
408312
|
+
const isUUID = (str)=>{
|
|
408313
|
+
if (!str) {
|
|
408314
|
+
return false;
|
|
408315
|
+
}
|
|
408316
|
+
return UUID_REGEX.test(str);
|
|
408317
|
+
};
|
|
408318
|
+
/**
|
|
408319
|
+
* 获取会话显示名称
|
|
408320
|
+
* 优先级:title(如果不是UUID)> name(如果不是UUID)> 新创建的会话
|
|
408321
|
+
* @param item 会话项
|
|
408322
|
+
* @returns 显示名称
|
|
408323
|
+
*/ const getConversationDisplayName = (item)=>{
|
|
408324
|
+
// 优先使用title,但需要检查是否是UUID
|
|
408325
|
+
if (item.title && !isUUID(item.title)) {
|
|
408326
|
+
return item.title;
|
|
408327
|
+
}
|
|
408328
|
+
// 如果name存在且不是UUID格式,使用name
|
|
408329
|
+
if (item.name && !isUUID(item.name)) {
|
|
408330
|
+
return item.name;
|
|
408331
|
+
}
|
|
408332
|
+
// 否则显示"新创建的会话"
|
|
408333
|
+
return intl_i18n.t('web_sdk_conversation_default_name', {}, '新创建的会话');
|
|
408334
|
+
};
|
|
408335
|
+
|
|
408023
408336
|
;// CONCATENATED MODULE: ../open-chat/src/components/conversation-list-sider/conversation-item/mobile/operate/index.tsx
|
|
408024
408337
|
/*
|
|
408025
408338
|
* Copyright 2025 coze-dev Authors
|
|
@@ -408220,7 +408533,7 @@ const MobileConversationItem = (param)=>{
|
|
|
408220
408533
|
ellipsis: {
|
|
408221
408534
|
showTooltip: {
|
|
408222
408535
|
opts: {
|
|
408223
|
-
content: item
|
|
408536
|
+
content: getConversationDisplayName(item),
|
|
408224
408537
|
style: {
|
|
408225
408538
|
wordBreak: 'break-all'
|
|
408226
408539
|
},
|
|
@@ -408229,7 +408542,7 @@ const MobileConversationItem = (param)=>{
|
|
|
408229
408542
|
}
|
|
408230
408543
|
}
|
|
408231
408544
|
},
|
|
408232
|
-
children: item
|
|
408545
|
+
children: getConversationDisplayName(item)
|
|
408233
408546
|
})
|
|
408234
408547
|
})
|
|
408235
408548
|
}),
|
|
@@ -408388,7 +408701,7 @@ const PcConversationItem = (param)=>{
|
|
|
408388
408701
|
ellipsis: {
|
|
408389
408702
|
showTooltip: {
|
|
408390
408703
|
opts: {
|
|
408391
|
-
content: item
|
|
408704
|
+
content: getConversationDisplayName(item),
|
|
408392
408705
|
style: {
|
|
408393
408706
|
wordBreak: 'break-all'
|
|
408394
408707
|
},
|
|
@@ -408397,7 +408710,7 @@ const PcConversationItem = (param)=>{
|
|
|
408397
408710
|
}
|
|
408398
408711
|
}
|
|
408399
408712
|
},
|
|
408400
|
-
children: item
|
|
408713
|
+
children: getConversationDisplayName(item)
|
|
408401
408714
|
}),
|
|
408402
408715
|
/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
408403
408716
|
className: conversation_item_pc_index_module["conversation-operate-wrapper"],
|
|
@@ -408513,6 +408826,16 @@ const ConversationList = /*#__PURE__*/ (0,react.forwardRef)(// eslint-disable-ne
|
|
|
408513
408826
|
]);
|
|
408514
408827
|
const listContainerRef = (0,react.useRef)(null);
|
|
408515
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
|
+
]);
|
|
408516
408839
|
const handleCreateConversation = ()=>{
|
|
408517
408840
|
if (!currentConversationInfo) {
|
|
408518
408841
|
return Promise.resolve();
|
|
@@ -408654,11 +408977,21 @@ const ConversationList = /*#__PURE__*/ (0,react.forwardRef)(// eslint-disable-ne
|
|
|
408654
408977
|
handleCreateConversation,
|
|
408655
408978
|
handleDeleteConversation
|
|
408656
408979
|
}));
|
|
408980
|
+
// 同步 loading 状态到 ref
|
|
408981
|
+
(0,react.useEffect)(()=>{
|
|
408982
|
+
isLoadingRef.current = loading;
|
|
408983
|
+
}, [
|
|
408984
|
+
loading
|
|
408985
|
+
]);
|
|
408657
408986
|
(0,react.useEffect)(()=>{
|
|
408658
408987
|
const observer = new IntersectionObserver((entries)=>{
|
|
408659
408988
|
const [entry] = entries;
|
|
408660
|
-
|
|
408661
|
-
|
|
408989
|
+
// 使用 ref 中的最新值,避免闭包问题
|
|
408990
|
+
// 注意:loadMore 函数内部已经有原子性检查,这里只需要检查基本条件
|
|
408991
|
+
if (entry.isIntersecting && hasMore && !isLoadingRef.current) {
|
|
408992
|
+
// 使用 ref 中的最新函数
|
|
408993
|
+
// loadMore 函数内部已经有原子性检查,可以安全地多次调用
|
|
408994
|
+
loadMoreRefFn.current();
|
|
408662
408995
|
}
|
|
408663
408996
|
}, {
|
|
408664
408997
|
root: listContainerRef.current,
|
|
@@ -408669,15 +409002,12 @@ const ConversationList = /*#__PURE__*/ (0,react.forwardRef)(// eslint-disable-ne
|
|
|
408669
409002
|
observer.observe(loadMoreRef.current);
|
|
408670
409003
|
}
|
|
408671
409004
|
return ()=>{
|
|
408672
|
-
|
|
408673
|
-
|
|
408674
|
-
}
|
|
409005
|
+
// 确保完全断开 observer 连接,防止旧的 observer 继续工作
|
|
409006
|
+
observer.disconnect();
|
|
408675
409007
|
};
|
|
408676
409008
|
}, [
|
|
408677
|
-
hasMore
|
|
408678
|
-
|
|
408679
|
-
loadMore
|
|
408680
|
-
]);
|
|
409009
|
+
hasMore
|
|
409010
|
+
]); // 只依赖 hasMore,不依赖 loading 和 loadMore
|
|
408681
409011
|
return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
|
|
408682
409012
|
className: conversation_list_sider_conversation_list_index_module.conversations,
|
|
408683
409013
|
style: {
|
|
@@ -409177,6 +409507,13 @@ const storageUtil = {
|
|
|
409177
409507
|
|
|
409178
409508
|
|
|
409179
409509
|
|
|
409510
|
+
|
|
409511
|
+
|
|
409512
|
+
|
|
409513
|
+
|
|
409514
|
+
|
|
409515
|
+
|
|
409516
|
+
|
|
409180
409517
|
const getDefaultUserInfo = (userInfo)=>{
|
|
409181
409518
|
if (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) {
|
|
409182
409519
|
return userInfo;
|
|
@@ -409188,6 +409525,7 @@ const getDefaultUserInfo = (userInfo)=>{
|
|
|
409188
409525
|
url: ''
|
|
409189
409526
|
};
|
|
409190
409527
|
};
|
|
409528
|
+
// eslint-disable-next-line @coze-arch/max-line-per-function -- Store creation function contains comprehensive state management logic
|
|
409191
409529
|
const createChatStore = (chatConfig, userInfo)=>{
|
|
409192
409530
|
var _chatConfig_auth, _chatConfig_auth1;
|
|
409193
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;
|
|
@@ -409314,9 +409652,20 @@ const createChatStore = (chatConfig, userInfo)=>{
|
|
|
409314
409652
|
}));
|
|
409315
409653
|
},
|
|
409316
409654
|
updateCurrentConversationNameByMessage: async (name)=>{
|
|
409655
|
+
var _chatConfigRef_current;
|
|
409317
409656
|
const { currentConversationInfo, updateCurrentConversationInfo, updateConversations, cozeApi } = get();
|
|
409318
|
-
// 如果没有 conversationInfo
|
|
409319
|
-
if (!currentConversationInfo
|
|
409657
|
+
// 如果没有 conversationInfo,直接返回
|
|
409658
|
+
if (!currentConversationInfo) {
|
|
409659
|
+
return Promise.resolve(false);
|
|
409660
|
+
}
|
|
409661
|
+
const isAppType = ((_chatConfigRef_current = chatConfigRef.current) === null || _chatConfigRef_current === void 0 ? void 0 : _chatConfigRef_current.type) === client_ChatType.APP;
|
|
409662
|
+
// 对于App模式,title应该只由chat接口的更新事件来设置,不应该主动PUT请求
|
|
409663
|
+
// 完全禁用App模式下的PUT请求,避免死循环
|
|
409664
|
+
if (isAppType) {
|
|
409665
|
+
return Promise.resolve(false);
|
|
409666
|
+
}
|
|
409667
|
+
// 对于Bot模式,如果已有名称,直接返回
|
|
409668
|
+
if (currentConversationInfo.name) {
|
|
409320
409669
|
return Promise.resolve(false);
|
|
409321
409670
|
}
|
|
409322
409671
|
// 如果 conversationId 不存在或为空,说明 conversation 还未创建成功,直接返回
|
|
@@ -409325,13 +409674,9 @@ const createChatStore = (chatConfig, userInfo)=>{
|
|
|
409325
409674
|
return Promise.resolve(false);
|
|
409326
409675
|
}
|
|
409327
409676
|
try {
|
|
409328
|
-
|
|
409329
|
-
|
|
409330
|
-
const
|
|
409331
|
-
// App 模式使用 title 字段,Bot 模式使用 name 字段
|
|
409332
|
-
const requestBody = isAppType ? {
|
|
409333
|
-
title: name
|
|
409334
|
-
} : {
|
|
409677
|
+
const url = `/v1/conversations/${currentConversationInfo.id}`;
|
|
409678
|
+
// Bot 模式使用 name 字段
|
|
409679
|
+
const requestBody = {
|
|
409335
409680
|
name
|
|
409336
409681
|
};
|
|
409337
409682
|
console.log('cozeApi?.put', url);
|
|
@@ -409355,12 +409700,37 @@ const createChatStore = (chatConfig, userInfo)=>{
|
|
|
409355
409700
|
updateConversations: (conversations, operate)=>{
|
|
409356
409701
|
set(immer_produce((s)=>{
|
|
409357
409702
|
if (operate === 'replace') {
|
|
409358
|
-
|
|
409703
|
+
// 修复:在replace时,保留store中已有的title字段
|
|
409704
|
+
// 因为服务器返回的数据可能不包含最新的title(title是通过chat接口更新事件更新的)
|
|
409705
|
+
// 需要将新数据与store中已有的数据合并,保留store中的title
|
|
409706
|
+
const existingConversationsMap = new Map(s.conversations.map((c)=>[
|
|
409707
|
+
c.id,
|
|
409708
|
+
c
|
|
409709
|
+
]));
|
|
409710
|
+
s.conversations = conversations.map((newConv)=>{
|
|
409711
|
+
const existingConv = existingConversationsMap.get(newConv.id);
|
|
409712
|
+
const existingConvWithTitle = existingConv;
|
|
409713
|
+
if (existingConvWithTitle === null || existingConvWithTitle === void 0 ? void 0 : existingConvWithTitle.title) {
|
|
409714
|
+
// 如果store中已有该会话且有title,保留title
|
|
409715
|
+
return Object.assign({
|
|
409716
|
+
...newConv
|
|
409717
|
+
}, {
|
|
409718
|
+
title: existingConvWithTitle.title
|
|
409719
|
+
});
|
|
409720
|
+
}
|
|
409721
|
+
return newConv;
|
|
409722
|
+
});
|
|
409359
409723
|
} else if (operate === 'add') {
|
|
409360
|
-
|
|
409361
|
-
|
|
409362
|
-
|
|
409363
|
-
|
|
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
|
+
}
|
|
409364
409734
|
} else if (operate === 'remove') {
|
|
409365
409735
|
conversations.forEach((conversation)=>{
|
|
409366
409736
|
const index = s.conversations.findIndex((c)=>c.id === conversation.id);
|
|
@@ -409372,8 +409742,12 @@ const createChatStore = (chatConfig, userInfo)=>{
|
|
|
409372
409742
|
conversations.forEach((conversation)=>{
|
|
409373
409743
|
const index = s.conversations.findIndex((c)=>c.id === conversation.id);
|
|
409374
409744
|
if (index !== -1) {
|
|
409745
|
+
// 修复:确保只更新传入的字段,保留原有字段
|
|
409746
|
+
// 先展开原有对象,再展开新对象,确保新对象的字段覆盖原有字段
|
|
409747
|
+
// 但不会丢失原有对象中的其他字段(如其他会话的title)
|
|
409748
|
+
const existingConversation = s.conversations[index];
|
|
409375
409749
|
s.conversations[index] = {
|
|
409376
|
-
...
|
|
409750
|
+
...existingConversation,
|
|
409377
409751
|
...conversation
|
|
409378
409752
|
};
|
|
409379
409753
|
}
|
|
@@ -413704,30 +414078,41 @@ studioOpenClientReporter.init(studio_open_client_reporter_slardarInstance);
|
|
|
413704
414078
|
|
|
413705
414079
|
|
|
413706
414080
|
|
|
414081
|
+
|
|
413707
414082
|
const useUpdateConversationNameByMessage = ()=>{
|
|
413708
414083
|
const currentConversationNameRef = (0,react.useRef)();
|
|
413709
414084
|
const { updateCurrentConversationNameByMessage, currentConversationInfo } = context_useChatAppStore(shallow_useShallow((s)=>({
|
|
413710
414085
|
updateCurrentConversationNameByMessage: s.updateCurrentConversationNameByMessage,
|
|
413711
414086
|
currentConversationInfo: s.currentConversationInfo
|
|
413712
414087
|
})));
|
|
414088
|
+
const { chatConfig: { type: chatType } } = context_useChatAppProps();
|
|
414089
|
+
const isAppType = chatType === client_ChatType.APP;
|
|
413713
414090
|
const { useMessagesStore } = use_chat_area_context_useChatAreaStoreSet();
|
|
413714
414091
|
const messages = useMessagesStore((s)=>s.messages, lodash_es_isEqual);
|
|
413715
414092
|
(0,react.useEffect)(()=>{
|
|
413716
|
-
|
|
414093
|
+
// 对于App模式,检查title;对于Bot模式,检查name
|
|
414094
|
+
if (isAppType) {
|
|
414095
|
+
currentConversationNameRef.current = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.title;
|
|
414096
|
+
} else {
|
|
414097
|
+
currentConversationNameRef.current = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.name;
|
|
414098
|
+
}
|
|
413717
414099
|
}, [
|
|
413718
|
-
currentConversationInfo
|
|
414100
|
+
currentConversationInfo,
|
|
414101
|
+
isAppType
|
|
413719
414102
|
]);
|
|
413720
414103
|
(0,react.useEffect)(()=>{
|
|
413721
414104
|
const message = messages[messages.length - 1];
|
|
413722
414105
|
const name = message === null || message === void 0 ? void 0 : message.content.slice(0, 100);
|
|
413723
414106
|
// 确保 conversation 已创建成功(有 id)且还没有名称时才更新
|
|
414107
|
+
// 对于App模式,如果title已经存在(通过chat接口更新事件设置的),不应该再PUT请求
|
|
413724
414108
|
if (message && !currentConversationNameRef.current && (currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id) && currentConversationInfo.id.trim() !== '') {
|
|
413725
414109
|
updateCurrentConversationNameByMessage(name);
|
|
413726
414110
|
currentConversationNameRef.current = name;
|
|
413727
414111
|
}
|
|
413728
414112
|
}, [
|
|
413729
414113
|
messages,
|
|
413730
|
-
currentConversationInfo
|
|
414114
|
+
currentConversationInfo,
|
|
414115
|
+
updateCurrentConversationNameByMessage
|
|
413731
414116
|
]);
|
|
413732
414117
|
};
|
|
413733
414118
|
|
|
@@ -416979,6 +417364,7 @@ const convertShortcutData = (shortcutCommands, botInfo)=>//@ts-expect-error: 不
|
|
|
416979
417364
|
|
|
416980
417365
|
|
|
416981
417366
|
|
|
417367
|
+
|
|
416982
417368
|
const microSeconds = 1000;
|
|
416983
417369
|
/**
|
|
416984
417370
|
* 从URL中提取文件名
|
|
@@ -417017,6 +417403,55 @@ const microSeconds = 1000;
|
|
|
417017
417403
|
};
|
|
417018
417404
|
// 消息转换成 Coze的消息,主要用于消息接收后,在页面显示。
|
|
417019
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
|
+
}
|
|
417020
417455
|
convertMessageListResponse(res) {
|
|
417021
417456
|
let botId = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : '';
|
|
417022
417457
|
const { data: messageList = [], has_more: hasMore, first_id: firstId, last_id: lastId } = res;
|
|
@@ -417035,7 +417470,11 @@ class MessageConverseToCoze {
|
|
|
417035
417470
|
const { content_type, content } = this.convertContent(message.content_type, message.content) || {};
|
|
417036
417471
|
const isQuestion = message.type === 'question';
|
|
417037
417472
|
const replyId = message.chat_id || `--custom-replyId--${index_browser_nanoid()}`;
|
|
417038
|
-
|
|
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,输出一个默认的
|
|
417039
417478
|
const senderId = isQuestion ? '' : message.bot_id || botId;
|
|
417040
417479
|
if (!content_type || !messageId || !replyId) {
|
|
417041
417480
|
return {};
|
|
@@ -417126,12 +417565,30 @@ class MessageConverseToCoze {
|
|
|
417126
417565
|
}
|
|
417127
417566
|
}
|
|
417128
417567
|
convertMixContent(content) {
|
|
417129
|
-
|
|
417130
|
-
|
|
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) {
|
|
417131
417588
|
return;
|
|
417132
417589
|
}
|
|
417133
|
-
console.log('convertMixContent
|
|
417134
|
-
const itemList =
|
|
417590
|
+
console.log('convertMixContent parsedContent', parsedContent);
|
|
417591
|
+
const itemList = parsedContent === null || parsedContent === void 0 ? void 0 : parsedContent.map((item)=>{
|
|
417135
417592
|
switch(item.type){
|
|
417136
417593
|
case 'text':
|
|
417137
417594
|
{
|
|
@@ -417200,9 +417657,52 @@ class MessageConverseToCoze {
|
|
|
417200
417657
|
}
|
|
417201
417658
|
}
|
|
417202
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
|
+
}
|
|
417203
417703
|
const contentResult = {
|
|
417204
|
-
item_list:
|
|
417205
|
-
refer_items:
|
|
417704
|
+
item_list: finalItemList.filter((item)=>!item.is_refer),
|
|
417705
|
+
refer_items: finalItemList.filter((item)=>item.is_refer)
|
|
417206
417706
|
};
|
|
417207
417707
|
return JSON.stringify(contentResult);
|
|
417208
417708
|
}
|
|
@@ -417470,11 +417970,19 @@ const useRequestInit = ()=>{
|
|
|
417470
417970
|
const updateShortcuts = context_useChatAppStore((s)=>s.updateShortcuts);
|
|
417471
417971
|
const setIsStartBotVoiceCall = context_useChatAppStore((s)=>s.setIsStartBotVoiceCall);
|
|
417472
417972
|
const updateBackgroundInfo = context_useChatAppStore((s)=>s.updateBackgroundInfo);
|
|
417473
|
-
const {
|
|
417474
|
-
|
|
417475
|
-
updateCurrentConversationInfo: s.updateCurrentConversationInfo,
|
|
417476
|
-
conversations: s.conversations
|
|
417973
|
+
const { updateCurrentConversationInfo } = context_useChatAppStore(shallow_useShallow((s)=>({
|
|
417974
|
+
updateCurrentConversationInfo: s.updateCurrentConversationInfo
|
|
417477
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
|
+
}));
|
|
417478
417986
|
const getMessageListByPairs = useGetMessageListByPairs();
|
|
417479
417987
|
const connectorId = (chatConfig === null || chatConfig === void 0 ? void 0 : (_chatConfig_auth = chatConfig.auth) === null || _chatConfig_auth === void 0 ? void 0 : _chatConfig_auth.connectorId) || '';
|
|
417480
417988
|
const { bot_id: botId = '', type: chatType, appInfo } = chatConfig;
|
|
@@ -417522,6 +418030,9 @@ const useRequestInit = ()=>{
|
|
|
417522
418030
|
const actualSectionId = requestDataConversationInfo.lastSectionId || '';
|
|
417523
418031
|
// 如果从 openRequestInit 返回了 conversationName,使用它
|
|
417524
418032
|
const actualConversationName = conversationName || '';
|
|
418033
|
+
// 从 ref 中获取最新的 currentConversationInfo 和 conversations
|
|
418034
|
+
const currentConversationInfo = currentConversationInfoRef.current;
|
|
418035
|
+
const conversations = conversationsRef.current;
|
|
417525
418036
|
if (actualConversationId) {
|
|
417526
418037
|
// 检查 currentConversationInfo 是否与实际的 conversationId 一致
|
|
417527
418038
|
// 如果 currentConversationInfo.id 为空字符串,说明是从空会话创建的,此时不应该更新
|
|
@@ -417569,14 +418080,21 @@ const useRequestInit = ()=>{
|
|
|
417569
418080
|
});
|
|
417570
418081
|
}
|
|
417571
418082
|
} else {
|
|
417572
|
-
// 如果 conversationId
|
|
418083
|
+
// 如果 conversationId 一致,只更新 sectionId(如果有变化)
|
|
418084
|
+
// 不更新 name,因为 name 会通过 conversation.update 事件自动更新
|
|
418085
|
+
// 这样可以避免 title/name 更新时触发重新初始化
|
|
417573
418086
|
const updates = {};
|
|
417574
418087
|
if (currentConversationInfo.last_section_id !== actualSectionId && actualSectionId) {
|
|
417575
418088
|
updates.last_section_id = actualSectionId;
|
|
417576
418089
|
}
|
|
417577
|
-
|
|
417578
|
-
|
|
417579
|
-
|
|
418090
|
+
// 移除 name 的更新,因为 name 会通过 conversation.update 事件自动更新
|
|
418091
|
+
// 这样可以避免 title/name 更新时触发重新初始化
|
|
418092
|
+
// if (
|
|
418093
|
+
// actualConversationName &&
|
|
418094
|
+
// currentConversationInfo.name !== actualConversationName
|
|
418095
|
+
// ) {
|
|
418096
|
+
// updates.name = actualConversationName;
|
|
418097
|
+
// }
|
|
417580
418098
|
if (Object.keys(updates).length > 0) {
|
|
417581
418099
|
updateCurrentConversationInfo({
|
|
417582
418100
|
...currentConversationInfo,
|
|
@@ -417630,8 +418148,8 @@ const useRequestInit = ()=>{
|
|
|
417630
418148
|
onDefaultHistoryClear,
|
|
417631
418149
|
chatType,
|
|
417632
418150
|
appInfo,
|
|
417633
|
-
currentConversationInfo
|
|
417634
|
-
|
|
418151
|
+
// 不再依赖 currentConversationInfo 和 conversations
|
|
418152
|
+
// 在函数内部通过 getState() 获取最新值,避免 title/name 更新时触发重新初始化
|
|
417635
418153
|
updateCurrentConversationInfo,
|
|
417636
418154
|
userInfo,
|
|
417637
418155
|
openRequestInit
|
|
@@ -417975,7 +418493,27 @@ class MessageConverterToSdk {
|
|
|
417975
418493
|
const contentType = messageBody.content_type;
|
|
417976
418494
|
const content = messageBody.query;
|
|
417977
418495
|
const shortcutCommand = messageBody.shortcut_command;
|
|
417978
|
-
|
|
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 = {
|
|
417979
418517
|
bot_id: messageBody.bot_id,
|
|
417980
418518
|
user_id: userInfo === null || userInfo === void 0 ? void 0 : userInfo.id,
|
|
417981
418519
|
stream: true,
|
|
@@ -417983,10 +418521,11 @@ class MessageConverterToSdk {
|
|
|
417983
418521
|
additional_messages: [
|
|
417984
418522
|
this.convertRequestMessage(contentType, content)
|
|
417985
418523
|
],
|
|
417986
|
-
parameters,
|
|
418524
|
+
parameters: parametersString,
|
|
417987
418525
|
shortcut_command: this.convertShortcuts(shortcuts || [], shortcutCommand),
|
|
417988
418526
|
enable_card: true
|
|
417989
|
-
}
|
|
418527
|
+
};
|
|
418528
|
+
return JSON.stringify(requestBody);
|
|
417990
418529
|
}
|
|
417991
418530
|
// 替换 chat请求中的 message部分
|
|
417992
418531
|
convertRequestMessage(contentType, content) {
|
|
@@ -419649,7 +420188,7 @@ const src_timeoutPromise = (ms)=>new Promise((resolve)=>{
|
|
|
419649
420188
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
419650
420189
|
* See the License for the specific language governing permissions and
|
|
419651
420190
|
* limitations under the License.
|
|
419652
|
-
*/ function message_parser_define_property(obj, key, value) {
|
|
420191
|
+
*/ /* eslint-disable max-lines */ function message_parser_define_property(obj, key, value) {
|
|
419653
420192
|
if (key in obj) {
|
|
419654
420193
|
Object.defineProperty(obj, key, {
|
|
419655
420194
|
value: value,
|
|
@@ -419671,6 +420210,7 @@ const src_timeoutPromise = (ms)=>new Promise((resolve)=>{
|
|
|
419671
420210
|
|
|
419672
420211
|
|
|
419673
420212
|
|
|
420213
|
+
|
|
419674
420214
|
// 消息解析,主要用于从服务端获取到消息后,解析成coze能适配的数据结构
|
|
419675
420215
|
var message_parser_ChunkEvent = /*#__PURE__*/ (/* unused pure expression or super */ null && (function(ChunkEvent) {
|
|
419676
420216
|
ChunkEvent["ERROR"] = "error";
|
|
@@ -419695,7 +420235,8 @@ class MessageParser {
|
|
|
419695
420235
|
}
|
|
419696
420236
|
case "conversation.message.delta":
|
|
419697
420237
|
{
|
|
419698
|
-
|
|
420238
|
+
// conversation.message.delta 不应该累积和合并,应该直接使用新内容
|
|
420239
|
+
const message = this.createMessage(data, false, false);
|
|
419699
420240
|
if (!message) {
|
|
419700
420241
|
return;
|
|
419701
420242
|
}
|
|
@@ -419703,7 +420244,8 @@ class MessageParser {
|
|
|
419703
420244
|
}
|
|
419704
420245
|
case "conversation.message.completed":
|
|
419705
420246
|
{
|
|
419706
|
-
|
|
420247
|
+
// conversation.message.completed 不应该累积和合并,应该直接使用新内容
|
|
420248
|
+
const messageResult = this.createMessage(data, true, false);
|
|
419707
420249
|
// 清理流式 JSON 累积内容
|
|
419708
420250
|
if (messageResult && typeof messageResult === 'object' && 'data' in messageResult) {
|
|
419709
420251
|
const messageData = messageResult.data;
|
|
@@ -419714,6 +420256,8 @@ class MessageParser {
|
|
|
419714
420256
|
if (contentKey) {
|
|
419715
420257
|
this.streamingJsonContent.delete(contentKey);
|
|
419716
420258
|
this.lastValidJsonContent.delete(contentKey);
|
|
420259
|
+
this.lastReturnedParsedContent.delete(contentKey);
|
|
420260
|
+
this.lastReturnedAccumulatedContent.delete(contentKey);
|
|
419717
420261
|
}
|
|
419718
420262
|
}
|
|
419719
420263
|
}
|
|
@@ -419760,7 +420304,7 @@ class MessageParser {
|
|
|
419760
420304
|
}
|
|
419761
420305
|
}
|
|
419762
420306
|
createMessage(data) {
|
|
419763
|
-
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;
|
|
419764
420308
|
const dataValue = catchParse(data);
|
|
419765
420309
|
if (!dataValue) {
|
|
419766
420310
|
return;
|
|
@@ -419771,31 +420315,124 @@ class MessageParser {
|
|
|
419771
420315
|
// 处理流式 JSON:当 content_type 是 object_string 且 type 是 answer 时
|
|
419772
420316
|
const isStreamingJson = dataValue.content_type === 'object_string' && dataValue.type === 'answer';
|
|
419773
420317
|
if (isStreamingJson && dataValue.content) {
|
|
419774
|
-
//
|
|
419775
|
-
|
|
420318
|
+
// 对于流式 object_string 消息,使用 id 作为 key 来累积内容
|
|
420319
|
+
// 这样可以确保不同 id 的消息不会被合并
|
|
420320
|
+
// 但是,只有 shouldAccumulate 为 true 时才累积(conversation.chat.* 事件)
|
|
420321
|
+
// conversation.message.delta 不应该累积,应该直接使用新内容
|
|
420322
|
+
const contentKey = dataValue.id || '';
|
|
419776
420323
|
if (contentKey) {
|
|
419777
|
-
|
|
419778
|
-
|
|
419779
|
-
|
|
419780
|
-
|
|
419781
|
-
|
|
419782
|
-
|
|
419783
|
-
if (parsedContent !== null) {
|
|
419784
|
-
// 如果解析成功,使用解析后的内容,并保存为最后一次有效内容
|
|
419785
|
-
dataValue.content = parsedContent;
|
|
419786
|
-
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);
|
|
419787
420330
|
} else {
|
|
419788
|
-
//
|
|
419789
|
-
|
|
419790
|
-
|
|
419791
|
-
|
|
419792
|
-
|
|
419793
|
-
|
|
419794
|
-
|
|
419795
|
-
|
|
419796
|
-
|
|
419797
|
-
|
|
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
|
+
}
|
|
419798
420431
|
}
|
|
420432
|
+
} else {
|
|
420433
|
+
// 数组不完整,使用累积的原始内容
|
|
420434
|
+
// convertMixContent 会尝试解析部分数组,如果失败会返回 undefined
|
|
420435
|
+
dataValue.content = newContent;
|
|
419799
420436
|
}
|
|
419800
420437
|
}
|
|
419801
420438
|
}
|
|
@@ -419806,7 +420443,8 @@ class MessageParser {
|
|
|
419806
420443
|
// 对于流式 JSON,如果 convertMixContent 返回 undefined(JSON 不完整),
|
|
419807
420444
|
// 且没有上一次成功解析的内容,不返回消息,避免重复渲染
|
|
419808
420445
|
if (isStreamingJson && !isComplete && message.content_type === types_ContentType.Mix && (!message.content || message.content === 'undefined')) {
|
|
419809
|
-
|
|
420446
|
+
// 对于流式 object_string 消息,使用 id 作为 key
|
|
420447
|
+
const contentKey = dataValue.id || '';
|
|
419810
420448
|
const lastValidContent = contentKey ? this.lastValidJsonContent.get(contentKey) : undefined;
|
|
419811
420449
|
// 如果没有上一次成功解析的内容,不返回消息
|
|
419812
420450
|
if (!lastValidContent) {
|
|
@@ -419815,15 +420453,30 @@ class MessageParser {
|
|
|
419815
420453
|
// 如果有上一次成功解析的内容,使用它
|
|
419816
420454
|
message.content = lastValidContent;
|
|
419817
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
|
+
}
|
|
419818
420476
|
if (isComplete && message.content_type === types_ContentType.Text && message.type === 'answer') {
|
|
419819
420477
|
message.content = '';
|
|
419820
|
-
} else if (isComplete && message.content_type === types_ContentType.Mix && message.type === 'answer') {
|
|
419821
|
-
message.content = JSON.stringify({
|
|
419822
|
-
item_list: []
|
|
419823
|
-
});
|
|
419824
420478
|
}
|
|
419825
420479
|
message.section_id = message.section_id || this.sectionId;
|
|
419826
|
-
console.log('createMessage message', message);
|
|
419827
420480
|
return {
|
|
419828
420481
|
event: 'message',
|
|
419829
420482
|
data: {
|
|
@@ -419839,6 +420492,127 @@ class MessageParser {
|
|
|
419839
420492
|
};
|
|
419840
420493
|
}
|
|
419841
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
|
+
/**
|
|
419842
420616
|
* 尝试解析流式 JSON 内容
|
|
419843
420617
|
* 如果 JSON 不完整,返回 null;如果解析成功,返回完整的 JSON 字符串
|
|
419844
420618
|
*/ tryParseStreamingJson(content) {
|
|
@@ -420052,6 +420826,10 @@ class MessageParser {
|
|
|
420052
420826
|
message_parser_define_property(this, "streamingJsonContent", new Map());
|
|
420053
420827
|
// 用于存储上一次成功解析的完整 JSON 内容,避免重复渲染
|
|
420054
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());
|
|
420055
420833
|
this.conversationId = requestMessageRawBody.conversation_id;
|
|
420056
420834
|
this.localMessageId = requestMessageRawBody.local_message_id;
|
|
420057
420835
|
this.sendMessageContent = requestMessageRawBody.query;
|
|
@@ -420134,36 +420912,85 @@ class MessageParser {
|
|
|
420134
420912
|
const currentConversation = refCurrentConversationInfo.current;
|
|
420135
420913
|
const updateConversationsFn = refUpdateConversations.current;
|
|
420136
420914
|
const updateCurrentConversationInfoFn = refUpdateCurrentConversationInfo.current;
|
|
420137
|
-
const conversationsList = refConversations.current;
|
|
420138
420915
|
const { title } = updates;
|
|
420139
420916
|
if (title !== undefined) {
|
|
420140
|
-
|
|
420141
|
-
const existingConversation = conversationsList.find((c)=>c.id === conversation_id);
|
|
420917
|
+
var _refPendingConversationInfo_current;
|
|
420142
420918
|
// 更新会话列表中的会话名称
|
|
420143
420919
|
// 注意:PC 端和 Mobile 端都优先使用 title,如果没有 title 则使用 name
|
|
420144
420920
|
// 对于 App 模式,需要同时更新 name 和 title
|
|
420145
420921
|
// 对于 Bot 模式,也需要更新 name 和 title(如果存在)
|
|
420146
|
-
|
|
420922
|
+
// 修复:使用函数式更新,确保从最新的store状态中获取并保留所有字段
|
|
420923
|
+
// 这样可以避免因为ref未及时更新而导致的数据丢失问题
|
|
420924
|
+
const updatedConversationObj = {
|
|
420147
420925
|
id: conversation_id,
|
|
420148
420926
|
name: title,
|
|
420149
420927
|
title,
|
|
420150
|
-
updated_at: Math.floor(updated_at / 1000)
|
|
420151
|
-
// 保留原有字段(如果存在),否则使用默认值
|
|
420152
|
-
created_at: (existingConversation === null || existingConversation === void 0 ? void 0 : existingConversation.created_at) ?? Math.floor(updated_at / 1000),
|
|
420153
|
-
meta_data: (existingConversation === null || existingConversation === void 0 ? void 0 : existingConversation.meta_data) ?? {},
|
|
420154
|
-
last_section_id: (existingConversation === null || existingConversation === void 0 ? void 0 : existingConversation.last_section_id) ?? ''
|
|
420928
|
+
updated_at: Math.floor(updated_at / 1000)
|
|
420155
420929
|
};
|
|
420156
|
-
updateConversationsFn
|
|
420157
|
-
|
|
420158
|
-
|
|
420930
|
+
if (updateConversationsFn) {
|
|
420931
|
+
updateConversationsFn([
|
|
420932
|
+
updatedConversationObj
|
|
420933
|
+
], 'update');
|
|
420934
|
+
}
|
|
420159
420935
|
// 如果当前会话是被更新的会话,同时更新 currentConversationInfo
|
|
420160
|
-
|
|
420161
|
-
|
|
420162
|
-
|
|
420163
|
-
|
|
420164
|
-
|
|
420165
|
-
|
|
420166
|
-
|
|
420936
|
+
// 修复:无论ref是否是最新的,都更新currentConversationInfo,确保header能显示title
|
|
420937
|
+
// updateCurrentConversationInfo函数会合并字段,所以即使ref不是最新的,title也会被正确设置
|
|
420938
|
+
// 从conversations列表中查找对应的会话,如果找到说明这个会话存在,可能是当前会话
|
|
420939
|
+
const conversationsList = refConversations.current;
|
|
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;
|
|
420946
|
+
// 如果ref中的id匹配,或者找到了对应的会话,就更新title
|
|
420947
|
+
// 这样可以确保即使ref不是最新的,也能正确更新title
|
|
420948
|
+
// 注意:只有当 conversation_id 与当前会话的 id 匹配时才更新 currentConversationInfo
|
|
420949
|
+
// 这样可以避免在更新其他会话的 title 时触发当前会话的重新初始化
|
|
420950
|
+
if (isCurrentConversation || isPendingConversation) {
|
|
420951
|
+
// 优先使用ref中的currentConversationInfo,保留其所有字段
|
|
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
|
+
}
|
|
420167
420994
|
}
|
|
420168
420995
|
}
|
|
420169
420996
|
};
|
|
@@ -420257,12 +421084,28 @@ class MessageParser {
|
|
|
420257
421084
|
conversationName: conversationResult.conversationName
|
|
420258
421085
|
});
|
|
420259
421086
|
}
|
|
420260
|
-
//
|
|
420261
|
-
//
|
|
420262
|
-
//
|
|
420263
|
-
//
|
|
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
|
|
420264
421107
|
messageBody.conversation_id = conversationId;
|
|
420265
|
-
console.log('onBeforeSendMessage: Conversation created,
|
|
421108
|
+
console.log('onBeforeSendMessage: Conversation created and selected, ready to send message', {
|
|
420266
421109
|
conversationId,
|
|
420267
421110
|
pendingInfo: refPendingConversationInfo.current
|
|
420268
421111
|
});
|
|
@@ -420278,7 +421121,7 @@ class MessageParser {
|
|
|
420278
421121
|
throw new Error('conversationId is required for sending message');
|
|
420279
421122
|
}
|
|
420280
421123
|
// 使用计算后的 API URL
|
|
420281
|
-
const url = `${finalApiUrl}/
|
|
421124
|
+
const url = `${finalApiUrl}/v1/workflows/chat?conversation_id=${conversationId}`;
|
|
420282
421125
|
// 根据 chatType 选择正确的 parameters 来源
|
|
420283
421126
|
// App 模式使用 appInfo.parameters,Bot 模式使用 botInfo.parameters
|
|
420284
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;
|
|
@@ -420423,6 +421266,8 @@ class MessageParser {
|
|
|
420423
421266
|
// 使用 setTimeout 确保在消息发送流程完全完成后更新状态
|
|
420424
421267
|
setTimeout(()=>{
|
|
420425
421268
|
if (refUpdateCurrentConversationInfo.current) {
|
|
421269
|
+
// 保留当前的 conversationListVisible 和 isLargeWidth,避免会话列表被收起
|
|
421270
|
+
const currentInfo = refCurrentConversationInfo.current;
|
|
420426
421271
|
refUpdateCurrentConversationInfo.current({
|
|
420427
421272
|
id: pendingInfo.conversationId,
|
|
420428
421273
|
last_section_id: pendingInfo.sectionId,
|
|
@@ -420431,8 +421276,10 @@ class MessageParser {
|
|
|
420431
421276
|
created_at: Math.floor(Date.now() / 1000),
|
|
420432
421277
|
updated_at: Math.floor(Date.now() / 1000),
|
|
420433
421278
|
meta_data: {},
|
|
420434
|
-
conversationListVisible
|
|
420435
|
-
|
|
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
|
|
420436
421283
|
});
|
|
420437
421284
|
}
|
|
420438
421285
|
if (refChatFunc === null || refChatFunc === void 0 ? void 0 : refChatFunc.current) {
|
|
@@ -423554,36 +424401,89 @@ const ChatProviderFuncComp = /*#__PURE__*/ (0,react.forwardRef)((param, ref)=>{
|
|
|
423554
424401
|
// 监听 currentConversationInfo 的变化,同步更新 chat-area 的 conversationId 和 sectionId
|
|
423555
424402
|
// 这样当切换会话时,可以避免出现"上下文已清除"提示
|
|
423556
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
|
+
});
|
|
423557
424449
|
(0,react.useEffect)(()=>{
|
|
423558
424450
|
var _chatConfig_ui_conversations, _chatConfig_ui;
|
|
423559
|
-
if (
|
|
423560
|
-
|
|
423561
|
-
|
|
423562
|
-
|
|
423563
|
-
|
|
423564
|
-
|
|
423565
|
-
|
|
423566
|
-
|
|
423567
|
-
|
|
423568
|
-
|
|
423569
|
-
|
|
423570
|
-
|
|
423571
|
-
|
|
423572
|
-
|
|
423573
|
-
|
|
423574
|
-
|
|
423575
|
-
|
|
423576
|
-
|
|
423577
|
-
|
|
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);
|
|
423578
424474
|
}
|
|
423579
424475
|
}, [
|
|
423580
|
-
|
|
423581
|
-
|
|
424476
|
+
stableConversationId,
|
|
424477
|
+
stableLastSectionId,
|
|
423582
424478
|
conversationId,
|
|
423583
424479
|
sectionId,
|
|
423584
424480
|
setConversationIdInArea,
|
|
423585
424481
|
chatCore,
|
|
423586
|
-
(_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
|
|
423587
424487
|
]);
|
|
423588
424488
|
useUpdateConversationNameByMessage();
|
|
423589
424489
|
const regenerateMessageByUserMessageId = useRegenerateMessageByUserMessageId();
|
|
@@ -435889,6 +436789,7 @@ var header_pc_index_module_update = injectStylesIntoStyleTag_default()(header_pc
|
|
|
435889
436789
|
|
|
435890
436790
|
|
|
435891
436791
|
|
|
436792
|
+
|
|
435892
436793
|
const ChatHeader = (param)=>{
|
|
435893
436794
|
let { iconUrl = coze_logo_namespaceObject, title = 'Coze Bot', extra, theme, isShowConversations, isNeedLogo = true } = param;
|
|
435894
436795
|
const { headerTopLeftOps } = useChatOpInfo();
|
|
@@ -435904,18 +436805,20 @@ const ChatHeader = (param)=>{
|
|
|
435904
436805
|
const [renameInputValue, setRenameInputValue] = (0,react.useState)('');
|
|
435905
436806
|
const [isRenameLoading, setIsRenameLoading] = (0,react.useState)(false);
|
|
435906
436807
|
// 使用 useMemo 计算显示文本,确保 title 变化时能及时更新
|
|
435907
|
-
const conversationTitle = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.title;
|
|
435908
|
-
const conversationName = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.name;
|
|
435909
436808
|
const conversationId = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id;
|
|
435910
436809
|
const displayTitle = (0,react.useMemo)(()=>{
|
|
435911
436810
|
if (conversationId === '') {
|
|
435912
436811
|
return title;
|
|
435913
436812
|
}
|
|
435914
|
-
|
|
436813
|
+
if (!currentConversationInfo) {
|
|
436814
|
+
return title;
|
|
436815
|
+
}
|
|
436816
|
+
// 使用 getConversationDisplayName 处理 UUID 检查
|
|
436817
|
+
const conversationItem = currentConversationInfo;
|
|
436818
|
+
return getConversationDisplayName(conversationItem) || title;
|
|
435915
436819
|
}, [
|
|
435916
436820
|
conversationId,
|
|
435917
|
-
|
|
435918
|
-
conversationName,
|
|
436821
|
+
currentConversationInfo,
|
|
435919
436822
|
title
|
|
435920
436823
|
]);
|
|
435921
436824
|
// 打开重命名弹窗
|
|
@@ -436141,6 +437044,7 @@ var header_mobile_index_module_update = injectStylesIntoStyleTag_default()(heade
|
|
|
436141
437044
|
|
|
436142
437045
|
|
|
436143
437046
|
|
|
437047
|
+
|
|
436144
437048
|
const ChatHeaderMobile = (param)=>{
|
|
436145
437049
|
let { iconUrl = coze_logo_namespaceObject, title = 'Coze Bot', extra, theme, isShowConversations, isNeedLogo = true } = param;
|
|
436146
437050
|
const { headerTopLeftOps } = useChatOpInfo();
|
|
@@ -436156,18 +437060,20 @@ const ChatHeaderMobile = (param)=>{
|
|
|
436156
437060
|
const [renameInputValue, setRenameInputValue] = (0,react.useState)('');
|
|
436157
437061
|
const [isRenameLoading, setIsRenameLoading] = (0,react.useState)(false);
|
|
436158
437062
|
// 使用 useMemo 计算显示文本,确保 title 变化时能及时更新
|
|
436159
|
-
const conversationTitle = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.title;
|
|
436160
|
-
const conversationName = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.name;
|
|
436161
437063
|
const conversationId = currentConversationInfo === null || currentConversationInfo === void 0 ? void 0 : currentConversationInfo.id;
|
|
436162
437064
|
const displayTitle = (0,react.useMemo)(()=>{
|
|
436163
437065
|
if (conversationId === '') {
|
|
436164
437066
|
return title;
|
|
436165
437067
|
}
|
|
436166
|
-
|
|
437068
|
+
if (!currentConversationInfo) {
|
|
437069
|
+
return title;
|
|
437070
|
+
}
|
|
437071
|
+
// 使用 getConversationDisplayName 处理 UUID 检查
|
|
437072
|
+
const conversationItem = currentConversationInfo;
|
|
437073
|
+
return getConversationDisplayName(conversationItem) || title;
|
|
436167
437074
|
}, [
|
|
436168
437075
|
conversationId,
|
|
436169
|
-
|
|
436170
|
-
conversationName,
|
|
437076
|
+
currentConversationInfo,
|
|
436171
437077
|
title
|
|
436172
437078
|
]);
|
|
436173
437079
|
// 打开重命名弹窗
|
|
@@ -437610,7 +438516,20 @@ const use_core_manager_useCoreManager = (props)=>{
|
|
|
437610
438516
|
bodyData.additional_messages = bodyDataOld.additional_messages || [];
|
|
437611
438517
|
bodyData.connector_id = bodyDataOld.connector_id;
|
|
437612
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;
|
|
437613
|
-
|
|
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
|
+
}
|
|
437614
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;
|
|
437615
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;
|
|
437616
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;
|
|
@@ -437626,8 +438545,13 @@ const use_core_manager_useCoreManager = (props)=>{
|
|
|
437626
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
|
|
437627
438546
|
} : undefined;
|
|
437628
438547
|
requestConfig.body = JSON.stringify(bodyData);
|
|
437629
|
-
//
|
|
437630
|
-
|
|
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
|
+
}
|
|
437631
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) || {}));
|
|
437632
438556
|
return {
|
|
437633
438557
|
...requestConfig
|