mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 02:53:19 +08:00
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.
32 lines
744 B
TypeScript
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
|
|
}
|