mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
fix(ai): handle stream failure follow-ups
This commit is contained in:
1 parent
dc07519bc0
commit
e75bb1e556
3 files changed
+63
-17
No files matched your search
@@ -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() {
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in new issue
Block a user