fix(ai): handle stream failure follow-ups

This commit is contained in:
digua committed 2026-08-26 22:42:13 +08:00
1 parent dc07519bc0
commit e75bb1e556
3 files changed
+63 -17

No files matched your search

+8 -2
View File
@@ -283,9 +283,15 @@ function handleSwitchAssistant(id: string) {
async function handlePresetQuestion(question: string) {
const result = await sendMessage(question)
if (!result.success && result.reason === 'busy') {
showRunningTaskToast()
if (!result.success) {
if (result.reason === 'error') conversationListRef.value?.refresh()
if (result.reason === 'busy') {
showRunningTaskToast()
}
return
}
scrollToBottom(true)
conversationListRef.value?.refresh()
}
function handleEditPresetQuestions() {
+2
View File
@@ -1457,6 +1457,7 @@ export const useAIChatStore = defineStore('aiChatRuntime', () => {
isStreaming: false,
}
} else if (!hasStreamError) {
setAgentPhase(state, 'error')
const blocks = targetBuffer.messages[aiMessageIndex].contentBlocks || []
blocks.push({
type: 'error',
@@ -2006,6 +2007,7 @@ export const useAIChatStore = defineStore('aiChatRuntime', () => {
isStreaming: false,
})
} else if (!hasStreamError) {
setAgentPhase(state, 'error')
const blocks = targetBuffer.messages[aiMessageIndex].contentBlocks || []
blocks.push({ type: 'error', error: normalizeSerializedError(result.error) })
updateAIMessage({ contentBlocks: [...blocks], isStreaming: false })
+53 -15
View File
@@ -61,23 +61,27 @@ test('restores the latest valid AI chat without leaking stale navigation state',
createAIChat: async () => {
throw new Error('create failed')
},
addMessage: async (
addMessagePair: async (
aiChatId: string,
role: 'user' | 'assistant',
content: string,
_dataKeywords?: string[],
_dataMessageCount?: number,
contentBlocks?: unknown,
_tokenUsage?: unknown,
entityRefs?: unknown
userMessage: { content: string; entityRefs?: unknown },
assistantMessage: { content: string; contentBlocks?: unknown }
) => ({
id: `saved-${++savedMessageId}`,
aiChatId,
role,
content,
timestamp: 1,
contentBlocks,
entityRefs,
userMessage: {
id: `saved-${++savedMessageId}`,
aiChatId,
role: 'user' as const,
content: userMessage.content,
timestamp: 1,
entityRefs: userMessage.entityRefs,
},
assistantMessage: {
id: `saved-${++savedMessageId}`,
aiChatId,
role: 'assistant' as const,
content: assistantMessage.content,
timestamp: 1,
contentBlocks: assistantMessage.contentBlocks,
},
}),
}
const assistantStore = {
@@ -255,6 +259,40 @@ test('restores the latest valid AI chat without leaking stale navigation state',
}
)
const networkError = { name: 'FetchError', message: 'connection lost', stack: null }
agentStreamRun = (onChunk) => {
onChunk?.({
type: 'status',
status: {
phase: 'responding',
round: 1,
toolsUsed: 0,
contextTokens: 10,
totalUsage: { promptTokens: 0, completionTokens: 0, totalTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 },
updatedAt: 1,
},
})
return {
requestId: 'network-error',
promise: Promise.resolve({ success: false, error: networkError }),
}
}
const networkFailureResult = await store.sendMessage(first.chatKey, 'Trigger network failure')
const networkFailedAssistant = first.state.messages.findLast((message) => message.role === 'assistant')
assert.deepEqual(
{
result: networkFailureResult,
phase: first.state.agentStatus?.phase,
errorBlocks: networkFailedAssistant?.contentBlocks?.filter((block) => block.type === 'error').length,
},
{
result: { success: false, reason: 'error' },
phase: 'error',
errorBlocks: 1,
}
)
const global = store.ensureGlobalState('zh-CN')
store.activeTask = {
requestId: 'global-request',