fix chatHistory reconnect effect

This commit is contained in:
Vikhyath Mondreti
2026-03-25 20:28:15 -07:00
parent 7b96b0e8e8
commit 1a14f4c13d

View File

@@ -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) {