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
}