Files
hermes-agent/apps/desktop/src/app/chat/thread-loading.ts
Brooklyn Nicholson 7c226cc57f perf(desktop): isolate streaming re-renders & cut layout thrash
During a token stream $messages is replaced ~30x/s. Subscribing the whole
chat view to it re-rendered the composer, runtime boundary, and every
message on every delta.

- Derive coarse facts (empty thread? tail is user?) via nanostores
  `computed` atoms so per-token flushes don't re-render their consumers.
- Move the $messages subscription + runtime wiring into a dedicated
  ChatRuntimeBoundary; the composer reads $messages imperatively.
- Drive message rows off stable useAuiState selectors and a lazy
  getMessageText getter instead of eagerly materialized text.
- Feed ResizeObserver entry sizes into measureClamp / FadeText and dedupe
  the style writes, killing the read-write-read reflow cascade.
2026-06-12 21:07:33 -05:00

32 lines
744 B
TypeScript

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
}