fix(ai): persist conversation turns atomically

中文:将用户与助手消息合并为单事务写入,失败时不再留下孤儿消息或误报成功。

English: Persist user and assistant messages in one transaction so failures leave no orphaned turn or false success.
This commit is contained in:
Sanssssssssssssssss authored and digua committed 2026-08-26 21:11:35 +08:00
1 parent 0126b56648
commit 893f1c05ec
10 files changed
+279 -78

No files matched your search

+14 -14
View File
@@ -34,23 +34,23 @@ function createAIChatManager(
chats.set(id, chat)
return chat
},
addMessage: (
aiChatId: string,
role: string,
content: string,
_dataKeywords?: string[],
_dataMessageCount?: number,
contentBlocks?: ContentBlock[],
tokenUsage?: TokenUsageData
) => {
addMessagePair: (aiChatId, userMessage, assistantMessage) => {
const savedUserMessage = { id: `msg_${messages.length + 1}`, aiChatId, role: 'user' as const, timestamp: 1 }
messages.push({ aiChatId, role: 'user', content: userMessage.content })
const savedAssistantMessage = {
id: `msg_${messages.length + 1}`,
aiChatId,
role: 'assistant' as const,
timestamp: 1,
}
messages.push({
aiChatId,
role,
content,
...(contentBlocks ? { contentBlocks } : {}),
...(tokenUsage ? { tokenUsage } : {}),
role: 'assistant',
content: assistantMessage.content,
...(assistantMessage.contentBlocks ? { contentBlocks: assistantMessage.contentBlocks } : {}),
...(assistantMessage.tokenUsage ? { tokenUsage: assistantMessage.tokenUsage } : {}),
})
return { id: `msg_${messages.length}`, aiChatId, role, content, timestamp: 1 }
return { userMessage: savedUserMessage, assistantMessage: savedAssistantMessage }
},
__messages: messages,
} as unknown as AIChatManager
+7 -8
View File
@@ -317,15 +317,14 @@ export async function runChatTurn(
write(stdout, '\n')
}
deps.aiChatManager.addMessage(target.aiChatId, 'user', options.question)
deps.aiChatManager.addMessage(
deps.aiChatManager.addMessagePair(
target.aiChatId,
'assistant',
answer,
undefined,
undefined,
hasReplayContentBlocks ? contentBlocks : undefined,
tokenUsage ?? undefined
{ content: options.question },
{
content: answer,
contentBlocks: hasReplayContentBlocks ? contentBlocks : undefined,
tokenUsage: tokenUsage ?? undefined,
}
)
return {