import { useLayoutEffect, useMemo, useState } from 'react' import { flushSync } from 'react-dom' import { createRoot } from 'react-dom/client' import { ChatTimeline, type Message } from '../../src/renderer/src/ChatTimeline' import { UiLocaleProvider } from '../../src/renderer/src/i18n/UiLocaleProvider' import '../../src/renderer/src/fonts' import '../../src/renderer/src/styles.css' const epoch = () => performance.timeOrigin + performance.now() const inputs: { at: number; frame: number; value: string; trusted: boolean }[] = [] const tasks: number[] = [] let collecting = false let committed = '' let committedDraft = '' let updates = 0 let received = 0 let firstCommit = 0 let lastCommit = 0 let setContent: (update: string | ((previous: string) => string)) => void let setDraft: (value: string) => void const observer = new PerformanceObserver(list => { if (collecting) tasks.push(...list.getEntries().map(entry => entry.duration)) }) observer.observe({ type: 'longtask' }) const callbacks = { onArticleRef: () => {}, onCopyMessage: async () => true, onDownloadImage: () => {}, onOpenCitationContext: async () => {}, onOpenCitationSource: async () => {}, onOpenImage: () => {}, onRespondApproval: async () => {}, onRespondQuestion: async () => {}, onRetry: () => {}, onRevealEarlier: () => {} } const artifacts = new Map() const initial: Message = { id: 'answer', role: 'assistant', content: '', createdAt: 1, state: 'streaming' } function Bench() { const [content, updateContent] = useState('') const [draft, updateDraft] = useState('') // Preserve ChatTimeline's production memo boundary when only the composer changes. const messages = useMemo(() => [{ ...initial, content }], [content]) setContent = updateContent setDraft = updateDraft useLayoutEffect(() => { committed = content if (collecting && content) { updates++ lastCommit = epoch() if (!firstCommit) firstCommit = lastCommit } }, [content]) useLayoutEffect(() => { committedDraft = draft }, [draft]) return