mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 18:10:26 +08:00
Merge branch 'fix/next-release-bugs' of github.com:CherryHQ/cherry-studio into fix/next-release-bugs
This commit is contained in:
commit
9ba630b5e8
@ -79,7 +79,7 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑消息。(目前仅更新 Redux state)。 / Edits a message. (Currently only updates Redux state).
|
* 编辑消息。 / Edits a message.
|
||||||
* 使用 newMessagesActions.updateMessage.
|
* 使用 newMessagesActions.updateMessage.
|
||||||
*/
|
*/
|
||||||
const editMessage = useCallback(
|
const editMessage = useCallback(
|
||||||
@ -92,17 +92,12 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
|
|
||||||
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
||||||
id: messageId,
|
id: messageId,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
...updates
|
...updates
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the thunk with topic.id and only message updates
|
// Call the thunk with topic.id and only message updates
|
||||||
const success = await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, []))
|
await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, []))
|
||||||
|
|
||||||
if (success) {
|
|
||||||
console.log(`[useMessageOperations] Successfully edited message ${messageId} properties.`)
|
|
||||||
} else {
|
|
||||||
console.error(`[useMessageOperations] Failed to edit message ${messageId} properties.`)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[dispatch, topic.id]
|
[dispatch, topic.id]
|
||||||
)
|
)
|
||||||
@ -133,9 +128,16 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
const files = findFileBlocks(message).map((block) => block.file)
|
const files = findFileBlocks(message).map((block) => block.file)
|
||||||
|
|
||||||
const usage = await estimateUserPromptUsage({ content: editedContent, files })
|
const usage = await estimateUserPromptUsage({ content: editedContent, files })
|
||||||
|
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
||||||
|
id: message.id,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
|
||||||
await dispatch(updateMessageAndBlocksThunk(topic.id, { id: message.id, usage }, []))
|
await dispatch(
|
||||||
|
newMessagesActions.updateMessage({ topicId: topic.id, messageId: message.id, updates: messageUpdates })
|
||||||
|
)
|
||||||
|
// 对于message的修改会在下面的thunk中保存
|
||||||
await dispatch(resendUserMessageWithEditThunk(topic.id, message, mainTextBlockId, editedContent, assistant))
|
await dispatch(resendUserMessageWithEditThunk(topic.id, message, mainTextBlockId, editedContent, assistant))
|
||||||
},
|
},
|
||||||
[dispatch, topic.id]
|
[dispatch, topic.id]
|
||||||
@ -313,29 +315,23 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
* Uses the generalized thunk for persistence.
|
* Uses the generalized thunk for persistence.
|
||||||
*/
|
*/
|
||||||
const editMessageBlocks = useCallback(
|
const editMessageBlocks = useCallback(
|
||||||
// messageId?: string
|
async (messageId: string, updates: Partial<MessageBlock>) => {
|
||||||
async (blockUpdatesListRaw: Partial<MessageBlock>[]) => {
|
|
||||||
if (!topic?.id) {
|
if (!topic?.id) {
|
||||||
console.error('[editMessageBlocks] Topic prop is not valid.')
|
console.error('[editMessageBlocks] Topic prop is not valid.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!blockUpdatesListRaw || blockUpdatesListRaw.length === 0) {
|
|
||||||
console.warn('[editMessageBlocks] Received empty block updates list.')
|
const blockUpdatesListProcessed = {
|
||||||
return
|
updatedAt: new Date().toISOString(),
|
||||||
|
...updates
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockUpdatesListProcessed = blockUpdatesListRaw.map((update) => ({
|
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
||||||
...update,
|
id: messageId,
|
||||||
updatedAt: new Date().toISOString()
|
updatedAt: new Date().toISOString()
|
||||||
}))
|
|
||||||
|
|
||||||
const success = await dispatch(updateMessageAndBlocksThunk(topic.id, null, blockUpdatesListProcessed))
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
// console.log(`[useMessageOperations] Successfully processed block updates for message ${messageId}.`)
|
|
||||||
} else {
|
|
||||||
// console.error(`[useMessageOperations] Failed to process block updates for message ${messageId}.`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, [blockUpdatesListProcessed]))
|
||||||
},
|
},
|
||||||
[dispatch, topic.id]
|
[dispatch, topic.id]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -107,14 +107,6 @@ export const autoRenameTopic = async (assistant: Assistant, topicId: string) =>
|
|||||||
// Convert class to object with functions since class only has static methods
|
// Convert class to object with functions since class only has static methods
|
||||||
// 只有静态方法,没必要用class,可以export {}
|
// 只有静态方法,没必要用class,可以export {}
|
||||||
export const TopicManager = {
|
export const TopicManager = {
|
||||||
async getTopicLimit(limit: number) {
|
|
||||||
return await db.topics
|
|
||||||
.orderBy('updatedAt') // 按 updatedAt 排序(默认升序)
|
|
||||||
.reverse() // 逆序(变成降序)
|
|
||||||
.limit(limit) // 取前 10 条
|
|
||||||
.toArray()
|
|
||||||
},
|
|
||||||
|
|
||||||
async getTopic(id: string) {
|
async getTopic(id: string) {
|
||||||
return await db.topics.get(id)
|
return await db.topics.get(id)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -75,7 +75,6 @@ const MainTextBlock: React.FC<Props> = ({ block, citationBlockId, role, mentions
|
|||||||
let processedContent = content
|
let processedContent = content
|
||||||
const firstCitation = formattedCitations[0]
|
const firstCitation = formattedCitations[0]
|
||||||
if (firstCitation?.metadata) {
|
if (firstCitation?.metadata) {
|
||||||
console.log('groundingSupport, ', firstCitation.metadata)
|
|
||||||
firstCitation.metadata.forEach((support: GroundingSupport) => {
|
firstCitation.metadata.forEach((support: GroundingSupport) => {
|
||||||
const citationNums = support.groundingChunkIndices!
|
const citationNums = support.groundingChunkIndices!
|
||||||
|
|
||||||
@ -126,12 +125,14 @@ const MainTextBlock: React.FC<Props> = ({ block, citationBlockId, role, mentions
|
|||||||
title: citation.title || citation.hostname || '',
|
title: citation.title || citation.hostname || '',
|
||||||
content: citation.content?.substring(0, 200)
|
content: citation.content?.substring(0, 200)
|
||||||
}
|
}
|
||||||
|
const isLink = citation.url.startsWith('http')
|
||||||
const citationJson = encodeHTML(JSON.stringify(supData))
|
const citationJson = encodeHTML(JSON.stringify(supData))
|
||||||
|
|
||||||
// Handle both plain references [N] and pre-formatted links [<sup>N</sup>](url)
|
// Handle both plain references [N] and pre-formatted links [<sup>N</sup>](url)
|
||||||
const plainRefRegex = new RegExp(`\\[${citationNum}\\]`, 'g')
|
const plainRefRegex = new RegExp(`\\[${citationNum}\\]`, 'g')
|
||||||
|
|
||||||
const citationTag = `[<sup data-citation='${citationJson}'>${citationNum}</sup>](${citation.url})`
|
const supTag = `<sup data-citation='${citationJson}'>${citationNum}</sup>`
|
||||||
|
const citationTag = isLink ? `[${supTag}](${citation.url})` : supTag
|
||||||
|
|
||||||
content = content.replace(plainRefRegex, citationTag)
|
content = content.replace(plainRefRegex, citationTag)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -102,7 +102,7 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message }) => {
|
|||||||
<UserName isBubbleStyle={isBubbleStyle} theme={theme}>
|
<UserName isBubbleStyle={isBubbleStyle} theme={theme}>
|
||||||
{username}
|
{username}
|
||||||
</UserName>
|
</UserName>
|
||||||
<MessageTime>{dayjs(message.createdAt).format('MM/DD HH:mm')}</MessageTime>
|
<MessageTime>{dayjs(message?.updatedAt ?? message.createdAt).format('MM/DD HH:mm')}</MessageTime>
|
||||||
</UserWrap>
|
</UserWrap>
|
||||||
</AvatarWrapper>
|
</AvatarWrapper>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@ -164,7 +164,7 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
if (resendMessage) {
|
if (resendMessage) {
|
||||||
resendUserMessageWithEdit(message, editedText, assistant)
|
resendUserMessageWithEdit(message, editedText, assistant)
|
||||||
} else {
|
} else {
|
||||||
editMessageBlocks([{ ...findMainTextBlocks(message)[0], content: editedText }])
|
editMessageBlocks(message.id, { id: findMainTextBlocks(message)[0].id, content: editedText })
|
||||||
}
|
}
|
||||||
// // 更新消息内容,保留图片信息
|
// // 更新消息内容,保留图片信息
|
||||||
// await editMessage(message.id, {
|
// await editMessage(message.id, {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export function createStreamProcessor(callbacks: StreamProcessorCallbacks = {})
|
|||||||
// The returned function processes a single chunk or a final signal
|
// The returned function processes a single chunk or a final signal
|
||||||
return (chunk: Chunk) => {
|
return (chunk: Chunk) => {
|
||||||
try {
|
try {
|
||||||
// console.log(`[${new Date().toLocaleString()}] createStreamProcessor ${chunk.type}`, chunk)
|
console.log(`[${new Date().toLocaleString()}] createStreamProcessor ${chunk.type}`, chunk)
|
||||||
// 1. Handle the manual final signal first
|
// 1. Handle the manual final signal first
|
||||||
if (chunk?.type === ChunkType.BLOCK_COMPLETE) {
|
if (chunk?.type === ChunkType.BLOCK_COMPLETE) {
|
||||||
callbacks.onComplete?.(AssistantMessageStatus.SUCCESS, chunk?.response)
|
callbacks.onComplete?.(AssistantMessageStatus.SUCCESS, chunk?.response)
|
||||||
|
|||||||
@ -91,6 +91,7 @@ const updateExistingMessageAndBlocksInDB = async (
|
|||||||
const newMessages = [...topic.messages]
|
const newMessages = [...topic.messages]
|
||||||
// Apply the updates passed in updatedMessage
|
// Apply the updates passed in updatedMessage
|
||||||
Object.assign(newMessages[messageIndex], updatedMessage)
|
Object.assign(newMessages[messageIndex], updatedMessage)
|
||||||
|
console.log('updateExistingMessageAndBlocksInDB', updatedMessage)
|
||||||
await db.topics.update(updatedMessage.topicId, { messages: newMessages })
|
await db.topics.update(updatedMessage.topicId, { messages: newMessages })
|
||||||
} else {
|
} else {
|
||||||
console.error(`[updateExistingMsg] Message ${updatedMessage.id} not found in topic ${updatedMessage.topicId}`)
|
console.error(`[updateExistingMsg] Message ${updatedMessage.id} not found in topic ${updatedMessage.topicId}`)
|
||||||
@ -106,44 +107,46 @@ const updateExistingMessageAndBlocksInDB = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新单个块的逻辑,用于更新消息中的单个块
|
// 更新单个块的逻辑,用于更新消息中的单个块
|
||||||
const throttledBlockUpdate = throttle((id, blockUpdate) => {
|
const throttledBlockUpdate = throttle(async (id, blockUpdate) => {
|
||||||
const state = store.getState()
|
// const state = store.getState()
|
||||||
const block = state.messageBlocks.entities[id]
|
// const block = state.messageBlocks.entities[id]
|
||||||
// throttle是异步函数,可能会在complete事件触发后才执行
|
// throttle是异步函数,可能会在complete事件触发后才执行
|
||||||
if (
|
// if (
|
||||||
blockUpdate.status === MessageBlockStatus.STREAMING &&
|
// blockUpdate.status === MessageBlockStatus.STREAMING &&
|
||||||
(block?.status === MessageBlockStatus.SUCCESS || block?.status === MessageBlockStatus.ERROR)
|
// (block?.status === MessageBlockStatus.SUCCESS || block?.status === MessageBlockStatus.ERROR)
|
||||||
)
|
// )
|
||||||
return
|
// return
|
||||||
|
|
||||||
store.dispatch(updateOneBlock({ id, changes: blockUpdate }))
|
store.dispatch(updateOneBlock({ id, changes: blockUpdate }))
|
||||||
|
await db.message_blocks.update(id, blockUpdate)
|
||||||
}, 150)
|
}, 150)
|
||||||
|
|
||||||
// 修改: 节流更新单个块的内容/状态到数据库 (仅用于 Text/Thinking Chunks)
|
const cancelThrottledBlockUpdate = throttledBlockUpdate.cancel
|
||||||
export const throttledBlockDbUpdate = throttle(
|
|
||||||
async (blockId: string, blockChanges: Partial<MessageBlock>) => {
|
// // 修改: 节流更新单个块的内容/状态到数据库 (仅用于 Text/Thinking Chunks)
|
||||||
// Check if blockId is valid before attempting update
|
// export const throttledBlockDbUpdate = throttle(
|
||||||
if (!blockId) {
|
// async (blockId: string, blockChanges: Partial<MessageBlock>) => {
|
||||||
console.warn('[DB Throttle Block Update] Attempted to update with null/undefined blockId. Skipping.')
|
// // Check if blockId is valid before attempting update
|
||||||
return
|
// if (!blockId) {
|
||||||
}
|
// console.warn('[DB Throttle Block Update] Attempted to update with null/undefined blockId. Skipping.')
|
||||||
const state = store.getState()
|
// return
|
||||||
const block = state.messageBlocks.entities[blockId]
|
// }
|
||||||
// throttle是异步函数,可能会在complete事件触发后才执行
|
// const state = store.getState()
|
||||||
if (
|
// const block = state.messageBlocks.entities[blockId]
|
||||||
blockChanges.status === MessageBlockStatus.STREAMING &&
|
// // throttle是异步函数,可能会在complete事件触发后才执行
|
||||||
(block?.status === MessageBlockStatus.SUCCESS || block?.status === MessageBlockStatus.ERROR)
|
// if (
|
||||||
)
|
// blockChanges.status === MessageBlockStatus.STREAMING &&
|
||||||
return
|
// (block?.status === MessageBlockStatus.SUCCESS || block?.status === MessageBlockStatus.ERROR)
|
||||||
try {
|
// )
|
||||||
await db.message_blocks.update(blockId, blockChanges)
|
// return
|
||||||
} catch (error) {
|
// try {
|
||||||
console.error(`[DB Throttle Block Update] Failed for block ${blockId}:`, error)
|
// } catch (error) {
|
||||||
}
|
// console.error(`[DB Throttle Block Update] Failed for block ${blockId}:`, error)
|
||||||
},
|
// }
|
||||||
300, // 可以调整节流间隔
|
// },
|
||||||
{ leading: false, trailing: true }
|
// 300, // 可以调整节流间隔
|
||||||
)
|
// { leading: false, trailing: true }
|
||||||
|
// )
|
||||||
|
|
||||||
// 新增: 通用的、非节流的函数,用于保存消息和块的更新到数据库
|
// 新增: 通用的、非节流的函数,用于保存消息和块的更新到数据库
|
||||||
const saveUpdatesToDB = async (
|
const saveUpdatesToDB = async (
|
||||||
@ -152,6 +155,7 @@ const saveUpdatesToDB = async (
|
|||||||
messageUpdates: Partial<Message>, // 需要更新的消息字段
|
messageUpdates: Partial<Message>, // 需要更新的消息字段
|
||||||
blocksToUpdate: MessageBlock[] // 需要更新/创建的块
|
blocksToUpdate: MessageBlock[] // 需要更新/创建的块
|
||||||
) => {
|
) => {
|
||||||
|
console.log('messageUpdates', messageUpdates)
|
||||||
try {
|
try {
|
||||||
const messageDataToSave: Partial<Message> & Pick<Message, 'id' | 'topicId'> = {
|
const messageDataToSave: Partial<Message> & Pick<Message, 'id' | 'topicId'> = {
|
||||||
id: messageId,
|
id: messageId,
|
||||||
@ -338,7 +342,7 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
status: MessageBlockStatus.STREAMING
|
status: MessageBlockStatus.STREAMING
|
||||||
}
|
}
|
||||||
throttledBlockUpdate(lastBlockId, blockChanges)
|
throttledBlockUpdate(lastBlockId, blockChanges)
|
||||||
throttledBlockDbUpdate(lastBlockId, blockChanges)
|
// throttledBlockDbUpdate(lastBlockId, blockChanges)
|
||||||
} else {
|
} else {
|
||||||
const newBlock = createMainTextBlock(assistantMsgId, accumulatedContent, {
|
const newBlock = createMainTextBlock(assistantMsgId, accumulatedContent, {
|
||||||
status: MessageBlockStatus.STREAMING,
|
status: MessageBlockStatus.STREAMING,
|
||||||
@ -349,7 +353,7 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onTextComplete: (finalText) => {
|
onTextComplete: async (finalText) => {
|
||||||
if (lastBlockType === MessageBlockType.MAIN_TEXT && lastBlockId) {
|
if (lastBlockType === MessageBlockType.MAIN_TEXT && lastBlockId) {
|
||||||
const changes = {
|
const changes = {
|
||||||
content: finalText,
|
content: finalText,
|
||||||
@ -366,8 +370,8 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
{ response: { source: WebSearchSource.OPENROUTER, results: extractedUrls } },
|
{ response: { source: WebSearchSource.OPENROUTER, results: extractedUrls } },
|
||||||
{ status: MessageBlockStatus.SUCCESS }
|
{ status: MessageBlockStatus.SUCCESS }
|
||||||
)
|
)
|
||||||
handleBlockTransition(citationBlock, MessageBlockType.CITATION)
|
await handleBlockTransition(citationBlock, MessageBlockType.CITATION)
|
||||||
saveUpdatedBlockToDB(citationBlock.id, assistantMsgId, topicId, getState)
|
// saveUpdatedBlockToDB(citationBlock.id, assistantMsgId, topicId, getState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -396,7 +400,7 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
thinking_millsec: thinking_millsec
|
thinking_millsec: thinking_millsec
|
||||||
}
|
}
|
||||||
throttledBlockUpdate(lastBlockId, blockChanges)
|
throttledBlockUpdate(lastBlockId, blockChanges)
|
||||||
throttledBlockDbUpdate(lastBlockId, blockChanges)
|
// throttledBlockDbUpdate(lastBlockId, blockChanges)
|
||||||
} else {
|
} else {
|
||||||
const newBlock = createThinkingBlock(assistantMsgId, accumulatedThinking, {
|
const newBlock = createThinkingBlock(assistantMsgId, accumulatedThinking, {
|
||||||
status: MessageBlockStatus.STREAMING,
|
status: MessageBlockStatus.STREAMING,
|
||||||
@ -467,7 +471,7 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
const citationBlock = createCitationBlock(assistantMsgId, {}, { status: MessageBlockStatus.PROCESSING })
|
const citationBlock = createCitationBlock(assistantMsgId, {}, { status: MessageBlockStatus.PROCESSING })
|
||||||
citationBlockId = citationBlock.id
|
citationBlockId = citationBlock.id
|
||||||
handleBlockTransition(citationBlock, MessageBlockType.CITATION)
|
handleBlockTransition(citationBlock, MessageBlockType.CITATION)
|
||||||
saveUpdatedBlockToDB(citationBlock.id, assistantMsgId, topicId, getState)
|
// saveUpdatedBlockToDB(citationBlock.id, assistantMsgId, topicId, getState)
|
||||||
},
|
},
|
||||||
onExternalToolComplete: (externalToolResult: ExternalToolResult) => {
|
onExternalToolComplete: (externalToolResult: ExternalToolResult) => {
|
||||||
if (citationBlockId) {
|
if (citationBlockId) {
|
||||||
@ -486,9 +490,9 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
const citationBlock = createCitationBlock(assistantMsgId, {}, { status: MessageBlockStatus.PROCESSING })
|
const citationBlock = createCitationBlock(assistantMsgId, {}, { status: MessageBlockStatus.PROCESSING })
|
||||||
citationBlockId = citationBlock.id
|
citationBlockId = citationBlock.id
|
||||||
handleBlockTransition(citationBlock, MessageBlockType.CITATION)
|
handleBlockTransition(citationBlock, MessageBlockType.CITATION)
|
||||||
saveUpdatedBlockToDB(citationBlock.id, assistantMsgId, topicId, getState)
|
// saveUpdatedBlockToDB(citationBlock.id, assistantMsgId, topicId, getState)
|
||||||
},
|
},
|
||||||
onLLMWebSearchComplete(llmWebSearchResult) {
|
onLLMWebSearchComplete: async (llmWebSearchResult) => {
|
||||||
if (citationBlockId) {
|
if (citationBlockId) {
|
||||||
const changes: Partial<CitationMessageBlock> = {
|
const changes: Partial<CitationMessageBlock> = {
|
||||||
response: llmWebSearchResult,
|
response: llmWebSearchResult,
|
||||||
@ -544,6 +548,7 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: async (error) => {
|
onError: async (error) => {
|
||||||
|
cancelThrottledBlockUpdate()
|
||||||
console.dir(error, { depth: null })
|
console.dir(error, { depth: null })
|
||||||
const isErrorTypeAbort = isAbortError(error)
|
const isErrorTypeAbort = isAbortError(error)
|
||||||
let pauseErrorLanguagePlaceholder = ''
|
let pauseErrorLanguagePlaceholder = ''
|
||||||
@ -585,6 +590,8 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
onComplete: async (status: AssistantMessageStatus, response?: Response) => {
|
onComplete: async (status: AssistantMessageStatus, response?: Response) => {
|
||||||
|
cancelThrottledBlockUpdate()
|
||||||
|
|
||||||
const finalStateOnComplete = getState()
|
const finalStateOnComplete = getState()
|
||||||
const finalAssistantMsg = finalStateOnComplete.messages.entities[assistantMsgId]
|
const finalAssistantMsg = finalStateOnComplete.messages.entities[assistantMsgId]
|
||||||
|
|
||||||
@ -623,7 +630,7 @@ const fetchAndProcessAssistantResponseImpl = async (
|
|||||||
updates: messageUpdates
|
updates: messageUpdates
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
console.log('onComplete: saveUpdatesToDB', messageUpdates)
|
||||||
saveUpdatesToDB(assistantMsgId, topicId, messageUpdates, [])
|
saveUpdatesToDB(assistantMsgId, topicId, messageUpdates, [])
|
||||||
|
|
||||||
EventEmitter.emit(EVENT_NAMES.MESSAGE_COMPLETE, { id: assistantMsgId, topicId, status })
|
EventEmitter.emit(EVENT_NAMES.MESSAGE_COMPLETE, { id: assistantMsgId, topicId, status })
|
||||||
@ -871,6 +878,7 @@ export const resendMessageThunk =
|
|||||||
const blockIdsToDelete = [...(originalMsg.blocks || [])]
|
const blockIdsToDelete = [...(originalMsg.blocks || [])]
|
||||||
const resetMsg = resetAssistantMessage(originalMsg, {
|
const resetMsg = resetAssistantMessage(originalMsg, {
|
||||||
status: AssistantMessageStatus.PENDING,
|
status: AssistantMessageStatus.PENDING,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
...(assistantMessagesToReset.length === 1 ? { model: assistant.model } : {})
|
...(assistantMessagesToReset.length === 1 ? { model: assistant.model } : {})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -973,7 +981,8 @@ export const regenerateAssistantResponseThunk =
|
|||||||
|
|
||||||
// 5. Reset the message entity in Redux
|
// 5. Reset the message entity in Redux
|
||||||
const resetAssistantMsg = resetAssistantMessage(messageToResetEntity, {
|
const resetAssistantMsg = resetAssistantMessage(messageToResetEntity, {
|
||||||
status: AssistantMessageStatus.PENDING
|
status: AssistantMessageStatus.PENDING,
|
||||||
|
updatedAt: new Date().toISOString()
|
||||||
})
|
})
|
||||||
dispatch(
|
dispatch(
|
||||||
newMessagesActions.updateMessage({
|
newMessagesActions.updateMessage({
|
||||||
|
|||||||
@ -163,7 +163,7 @@ export type Message = {
|
|||||||
assistantId: string
|
assistantId: string
|
||||||
topicId: string
|
topicId: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
// updatedAt?: string
|
updatedAt?: string
|
||||||
status: UserMessageStatus | AssistantMessageStatus
|
status: UserMessageStatus | AssistantMessageStatus
|
||||||
|
|
||||||
// 消息元数据
|
// 消息元数据
|
||||||
|
|||||||
@ -384,7 +384,7 @@ export function resetMessage(
|
|||||||
*/
|
*/
|
||||||
export const resetAssistantMessage = (
|
export const resetAssistantMessage = (
|
||||||
originalMessage: Message,
|
originalMessage: Message,
|
||||||
updates?: Partial<Pick<Message, 'status'>> // Primarily allow updating status
|
updates?: Partial<Pick<Message, 'status' | 'updatedAt'>> // Primarily allow updating status
|
||||||
): Message => {
|
): Message => {
|
||||||
// Ensure we are only resetting assistant messages
|
// Ensure we are only resetting assistant messages
|
||||||
if (originalMessage.role !== 'assistant') {
|
if (originalMessage.role !== 'assistant') {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user