File size: 1,590 Bytes
28ad89a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | import type { ChatMessage } from '@/lib/chat-messages'
export type ThreadLoadingState = 'response' | 'session'
export function lastVisibleMessageIsUser(messages: ChatMessage[]): boolean {
// Allocation-free reverse scan — runs in a hot $messages computed.
for (let i = messages.length - 1; i >= 0; i -= 1) {
if (!messages[i].hidden) {
return messages[i].role === 'user'
}
}
return false
}
export function threadLoadingState(
loadingSession: boolean,
busy: boolean,
awaitingResponse: boolean,
lastVisibleIsUser: boolean
): ThreadLoadingState | undefined {
if (loadingSession) {
return 'session'
}
if (busy && awaitingResponse && lastVisibleIsUser) {
return 'response'
}
return undefined
}
export function routedSessionIsLoading({
activeSessionId,
knownHistory,
messagesEmpty,
resumeExhausted,
routeSessionMismatch,
routedSessionView
}: {
activeSessionId: string | null
knownHistory: boolean
messagesEmpty: boolean
resumeExhausted: boolean
routeSessionMismatch: boolean
routedSessionView: boolean
}): boolean {
if (resumeExhausted || !routedSessionView) {
return false
}
if (routeSessionMismatch) {
return true
}
if (!messagesEmpty) {
return false
}
// Brand-new routed drafts are empty on purpose. A session the list already
// knows has history must keep the loader up until a display-authoritative
// transcript arrives — including the unproven warm-cache hold, where the
// runtime is bound but messages are still suppressed.
return !activeSessionId || knownHistory
}
|