🐛 fix(message): prevent history loss when retrying imported messages with duplicate IDs

- Use object reference comparison first before falling back to ID matching
- Prevent incorrect message index lookup when duplicate IDs exist
- Apply fix to both handleMessageReset and handleMessageDelete functions
- Maintain backward compatibility with ID-based message identification

Previously, when importing messages that contained duplicate IDs, the
findIndex operation would match the first occurrence rather than the
intended message, causing history truncation on retry. This change uses
object reference comparison as the primary method, ensuring accurate
message identification and preserving conversation history.
This commit is contained in:
Apple\Apple
2025-06-03 00:32:42 +08:00
parent e5d0f26fb9
commit d459b03e84
2 changed files with 21 additions and 7 deletions

View File

@@ -41,7 +41,7 @@ const MessageActions = ({
icon={<RefreshCw size={styleState.isMobile ? 12 : 14} />}
onClick={() => !shouldDisableActions && onMessageReset(message)}
disabled={shouldDisableActions}
className={`!rounded-md ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : '!text-gray-400 hover:!text-blue-600 hover:!bg-blue-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
className={`!rounded-full ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : '!text-gray-400 hover:!text-blue-600 hover:!bg-blue-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
aria-label={t('重试')}
/>
</Tooltip>
@@ -55,7 +55,7 @@ const MessageActions = ({
size="small"
icon={<Copy size={styleState.isMobile ? 12 : 14} />}
onClick={() => onMessageCopy(message)}
className={`!rounded-md !text-gray-400 hover:!text-green-600 hover:!bg-green-50 ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
className={`!rounded-full !text-gray-400 hover:!text-green-600 hover:!bg-green-50 ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
aria-label={t('复制')}
/>
</Tooltip>
@@ -70,7 +70,7 @@ const MessageActions = ({
icon={<Edit size={styleState.isMobile ? 12 : 14} />}
onClick={() => !shouldDisableActions && onMessageEdit(message)}
disabled={shouldDisableActions}
className={`!rounded-md ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : '!text-gray-400 hover:!text-yellow-600 hover:!bg-yellow-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
className={`!rounded-full ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : '!text-gray-400 hover:!text-yellow-600 hover:!bg-yellow-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
aria-label={t('编辑')}
/>
</Tooltip>
@@ -94,7 +94,7 @@ const MessageActions = ({
icon={<UserCheck size={styleState.isMobile ? 12 : 14} />}
onClick={() => !shouldDisableActions && onRoleToggle && onRoleToggle(message)}
disabled={shouldDisableActions}
className={`!rounded-md ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : message.role === 'system' ? '!text-purple-500 hover:!text-purple-700 hover:!bg-purple-50' : '!text-gray-400 hover:!text-purple-600 hover:!bg-purple-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
className={`!rounded-full ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : message.role === 'system' ? '!text-purple-500 hover:!text-purple-700 hover:!bg-purple-50' : '!text-gray-400 hover:!text-purple-600 hover:!bg-purple-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
aria-label={message.role === 'assistant' ? t('切换为System角色') : t('切换为Assistant角色')}
/>
</Tooltip>
@@ -109,7 +109,7 @@ const MessageActions = ({
icon={<Trash2 size={styleState.isMobile ? 12 : 14} />}
onClick={() => !shouldDisableActions && onMessageDelete(message)}
disabled={shouldDisableActions}
className={`!rounded-md ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : '!text-gray-400 hover:!text-red-600 hover:!bg-red-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
className={`!rounded-full ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : '!text-gray-400 hover:!text-red-600 hover:!bg-red-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
aria-label={t('删除')}
/>
</Tooltip>

View File

@@ -88,7 +88,14 @@ export const useMessageActions = (message, setMessage, onMessageSend, saveMessag
// 重新生成消息
const handleMessageReset = useCallback((targetMessage) => {
setMessage(prevMessages => {
const messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id);
// 使用引用查找索引,防止重复 id 造成误匹配
let messageIndex = prevMessages.findIndex(msg => msg === targetMessage);
// 回退到 id 匹配(兼容不同引用场景)
if (messageIndex === -1) {
messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id);
}
if (messageIndex === -1) return prevMessages;
if (targetMessage.role === 'user') {
@@ -135,7 +142,14 @@ export const useMessageActions = (message, setMessage, onMessageSend, saveMessag
},
onOk: () => {
setMessage(prevMessages => {
const messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id);
// 使用引用查找索引,防止重复 id 造成误匹配
let messageIndex = prevMessages.findIndex(msg => msg === targetMessage);
// 回退到 id 匹配(兼容不同引用场景)
if (messageIndex === -1) {
messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id);
}
if (messageIndex === -1) return prevMessages;
let updatedMessages;