mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
fix chatHistory reconnect effect
This commit is contained in:
@@ -845,44 +845,62 @@ export function useChat(
|
||||
const assistantId = crypto.randomUUID()
|
||||
|
||||
const reconnect = async () => {
|
||||
try {
|
||||
const result = await attachToExistingStream({
|
||||
streamId: activeStreamId,
|
||||
assistantId,
|
||||
expectedGen: gen,
|
||||
snapshot,
|
||||
initialLastEventId: lastEventIdRef.current,
|
||||
})
|
||||
if (streamGenRef.current === gen && !result.aborted) {
|
||||
finalizeRef.current(result.error ? { error: true } : undefined)
|
||||
let lastAttemptError: string | undefined
|
||||
|
||||
for (let attempt = 0; attempt <= MAX_RECONNECT_ATTEMPTS; attempt++) {
|
||||
if (streamGenRef.current !== gen) return
|
||||
if (abortControllerRef.current?.signal.aborted) return
|
||||
|
||||
if (attempt > 0) {
|
||||
const delayMs = Math.min(
|
||||
RECONNECT_BASE_DELAY_MS * 2 ** (attempt - 1),
|
||||
RECONNECT_MAX_DELAY_MS
|
||||
)
|
||||
logger.error('Reconnect attempt (chatHistory)', {
|
||||
streamId: activeStreamId,
|
||||
attempt,
|
||||
maxAttempts: MAX_RECONNECT_ATTEMPTS,
|
||||
delayMs,
|
||||
error: lastAttemptError,
|
||||
})
|
||||
setIsReconnecting(true)
|
||||
await new Promise((resolve) => setTimeout(resolve, delayMs))
|
||||
if (streamGenRef.current !== gen) return
|
||||
if (abortControllerRef.current?.signal.aborted) return
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name === 'AbortError') return
|
||||
logger.warn('Unexpected error during reconnect', {
|
||||
streamId: activeStreamId,
|
||||
chatId: chatHistory.id,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
})
|
||||
if (streamGenRef.current === gen) {
|
||||
try {
|
||||
finalizeRef.current({ error: true })
|
||||
} catch (finalizeError) {
|
||||
logger.error('Reconnect fallback finalize failed', {
|
||||
streamId: activeStreamId,
|
||||
chatId: chatHistory.id,
|
||||
error:
|
||||
finalizeError instanceof Error ? finalizeError.message : String(finalizeError),
|
||||
})
|
||||
sendingRef.current = false
|
||||
setIsSending(false)
|
||||
setIsReconnecting(false)
|
||||
abortControllerRef.current = null
|
||||
setError('Failed to reconnect to the active stream')
|
||||
|
||||
try {
|
||||
const result = await attachToExistingStream({
|
||||
streamId: activeStreamId,
|
||||
assistantId,
|
||||
expectedGen: gen,
|
||||
snapshot: attempt === 0 ? snapshot : undefined,
|
||||
initialLastEventId: lastEventIdRef.current,
|
||||
})
|
||||
if (streamGenRef.current === gen && !result.aborted) {
|
||||
finalizeRef.current(result.error ? { error: true } : undefined)
|
||||
}
|
||||
return
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name === 'AbortError') return
|
||||
lastAttemptError = err instanceof Error ? err.message : String(err)
|
||||
}
|
||||
} finally {
|
||||
if (abortControllerRef.current === abortController) {
|
||||
}
|
||||
|
||||
logger.error('All reconnect attempts exhausted (chatHistory)', {
|
||||
streamId: activeStreamId,
|
||||
maxAttempts: MAX_RECONNECT_ATTEMPTS,
|
||||
})
|
||||
setIsReconnecting(false)
|
||||
if (streamGenRef.current === gen) {
|
||||
try {
|
||||
finalizeRef.current({ error: true })
|
||||
} catch {
|
||||
sendingRef.current = false
|
||||
setIsSending(false)
|
||||
setIsReconnecting(false)
|
||||
abortControllerRef.current = null
|
||||
setError('Failed to reconnect to the active stream')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1799,19 +1817,8 @@ export function useChat(
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name === 'AbortError') {
|
||||
logger.error('Send aborted (AbortError)', { streamId: userMessageId })
|
||||
return
|
||||
}
|
||||
if (err instanceof Error && err.name === 'AbortError') return
|
||||
const errorMessage = err instanceof Error ? err.message : 'Failed to send message'
|
||||
logger.error('Send catch block entered', {
|
||||
streamId: userMessageId,
|
||||
errorMessage,
|
||||
errorName: err instanceof Error ? err.name : 'unknown',
|
||||
gen,
|
||||
currentGen: streamGenRef.current,
|
||||
hasActiveStreamId: Boolean(streamIdRef.current),
|
||||
})
|
||||
if (requestChatId && isActiveStreamConflictError(errorMessage)) {
|
||||
logger.info('Active stream conflict detected while sending message; reattaching', {
|
||||
chatId: requestChatId,
|
||||
@@ -1870,12 +1877,9 @@ export function useChat(
|
||||
|
||||
const activeStreamId = streamIdRef.current
|
||||
if (activeStreamId && streamGenRef.current === gen) {
|
||||
const reconnectController = new AbortController()
|
||||
abortControllerRef.current = reconnectController
|
||||
|
||||
for (let attempt = 0; attempt < MAX_RECONNECT_ATTEMPTS; attempt++) {
|
||||
if (streamGenRef.current !== gen) return
|
||||
if (reconnectController.signal.aborted) return
|
||||
if (abortControllerRef.current?.signal.aborted) return
|
||||
|
||||
const delayMs = Math.min(RECONNECT_BASE_DELAY_MS * 2 ** attempt, RECONNECT_MAX_DELAY_MS)
|
||||
logger.info('Reconnect attempt after network error', {
|
||||
@@ -1890,7 +1894,7 @@ export function useChat(
|
||||
await new Promise((resolve) => setTimeout(resolve, delayMs))
|
||||
|
||||
if (streamGenRef.current !== gen) return
|
||||
if (reconnectController.signal.aborted) return
|
||||
if (abortControllerRef.current?.signal.aborted) return
|
||||
|
||||
try {
|
||||
await resumeOrFinalize({
|
||||
@@ -1898,7 +1902,7 @@ export function useChat(
|
||||
assistantId,
|
||||
gen,
|
||||
fromEventId: lastEventIdRef.current,
|
||||
signal: reconnectController.signal,
|
||||
signal: abortControllerRef.current?.signal,
|
||||
})
|
||||
return
|
||||
} catch (reconnectErr) {
|
||||
|
||||
Reference in New Issue
Block a user