fix: reduce redundant work during chat and note startup

Avoid hidden activity renders, no-op message saves and attachment scans when pinning conversations. Reuse note body inspection and skip unchanged attachment reference writes while preserving recovery and cleanup behavior.

Skip unnecessary Markdown normalization and memoize subagent lookups without delaying live rich text. Add storage operation counts and real Electron rendering equivalence benchmarks; full-render speedup remains unproven.

Validation: 5397 tests passed, 84 skipped; typecheck passed. Lint passed excluding two existing untracked sidebar probe files.

Release note: Reduce repeated rendering and disk work during chat, conversation pinning and note startup while preserving existing content and interactions.
This commit is contained in:
mesalogo
2026-09-28 20:53:43 +08:00
parent 594222a2b5
commit 13ff182858
23 changed files with 1047 additions and 54 deletions
+65
View File
@@ -0,0 +1,65 @@
// @vitest-environment node
import { spawn } from 'node:child_process'
import { copyFile, mkdtemp, readFile, rm } from 'node:fs/promises'
import { createRequire } from 'node:module'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import react from '@vitejs/plugin-react'
import { createServer } from 'vite'
import { expect, it } from 'vitest'
it('measures real streaming Markdown and preserves every prefix against the original normalizer', async () => {
const directory = await mkdtemp(join(tmpdir(), 'goodbuddy-streaming-markdown-'))
const server = await createServer({
configFile: false, root: resolve('.'), cacheDir: join(directory, 'vite'),
plugins: [{
name: 'streaming-markdown-instrumentation', enforce: 'pre',
async load(id) {
if (!id.endsWith('MarkdownRenderer.tsx?streaming-original')) return
const source = await readFile(id.split('?')[0]!, 'utf8')
return source.replace(/(?:export )?function replaceLatexDelimiters[\s\S]*?(?=function unwrapMarkdownFence)/u,
'import { originalNormalize as normalizeLatexDelimiters } from "/tests/support/streaming-markdown-corpus.ts"\n\n')
},
transform(source, id) {
if (id.split('?')[0]!.endsWith('/MarkdownRenderer.tsx')) {
return source + '\nexport { normalizeLatexDelimiters as benchmarkNormalize }\n'
}
},
configureServer(server) {
server.middlewares.use('/streaming-markdown.html', async (_request, response) => {
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.end(await server.transformIndexHtml('/streaming-markdown.html',
'<!doctype html><html><head><meta charset="utf-8"></head><body><div id="root"></div><script type="module" src="/tests/support/streaming-markdown-perf.tsx"></script></body></html>'))
})
}
}, react()],
server: { host: '127.0.0.1', port: 0, watch: null }
})
try {
await server.listen()
const env: NodeJS.ProcessEnv = { ...process.env, GOODBUDDY_MARKDOWN_URL: server.resolvedUrls!.local[0] + 'streaming-markdown.html',
GOODBUDDY_MARKDOWN_DIRECTORY: directory }
delete env.ELECTRON_RUN_AS_NODE
const driver = join(directory, 'driver.mjs')
await copyFile(resolve('tests/support/streaming-markdown-driver.mjs'), driver)
const child = spawn(createRequire(import.meta.url)('electron'), [driver], { env, stdio: ['ignore', 'pipe', 'pipe'] })
let output = ''
child.stdout.on('data', data => { output += data })
child.stderr.on('data', data => { output += data })
const timeout = setTimeout(() => child.kill(), 150_000)
try {
const code = await new Promise((resolve, reject) => {
child.once('exit', resolve)
child.once('error', reject)
})
expect(code, output).toBe(0)
process.stdout.write(output.split(/\r?\n/u).filter(line => line.startsWith('Markdown ')).join('\n') + '\n')
} finally {
clearTimeout(timeout)
if (child.exitCode === null) child.kill()
}
} finally {
await server.close()
await rm(directory, { recursive: true, force: true })
}
}, 180_000)
+101
View File
@@ -0,0 +1,101 @@
// Frozen pre-optimization implementation: an independent streaming equivalence oracle.
function originalReplace(line: string): string {
let output = ''
let index = 0
let codeDelimiterLength = 0
while (index < line.length) {
if (line[index] === '`') {
let runLength = 1
while (line[index + runLength] === '`') runLength += 1
if (codeDelimiterLength === 0 || codeDelimiterLength === runLength) {
codeDelimiterLength = codeDelimiterLength === 0 ? runLength : 0
}
output += line.slice(index, index + runLength)
index += runLength
continue
}
if (codeDelimiterLength === 0 && line[index] === '\\' &&
line[index - 1] !== '\\' && (line[index + 1] === '(' || line[index + 1] === ')')) {
output += '$'
index += 2
continue
}
output += line[index]
index += 1
}
return output
}
export function originalNormalize(content: string): string {
let fence: { character: '`' | '~'; length: number } | undefined
return content.split(/\r?\n/u).map(line => {
if (fence) {
const closingFence = new RegExp(`^ {0,3}${fence.character}{${fence.length},}\\s*$`, 'u')
if (closingFence.test(line)) fence = undefined
return line
}
const openingFence = /^ {0,3}(`{3,}|~{3,})/u.exec(line)
if (openingFence) {
const marker = openingFence[1]!
fence = { character: marker[0] as '`' | '~', length: marker.length }
return line
}
const standaloneDollar = /^ {0,3}\$(?!\$)(.+?)(?<!\\)\$\s*$/u.exec(line)
if (standaloneDollar) return `$$\n${standaloneDollar[1]}\n$$`
const standaloneParentheses = /^ {0,3}\\\(\s*(.*?)\s*\\\)\s*$/u.exec(line)
if (standaloneParentheses) return `$$\n${standaloneParentheses[1]}\n$$`
const singleLineDisplay = /^ {0,3}\\\[\s*(.*?)\s*\\\]\s*$/u.exec(line)
if (singleLineDisplay) return `$$\n${singleLineDisplay[1]}\n$$`
if (/^ {0,3}\\\[\s*$/u.test(line)) return '$$'
if (/^ {0,3}\\\]\s*$/u.test(line)) return '$$'
return originalReplace(line)
}).join('\n')
}
export const equivalenceCorpus = [
'# Heading\n\n**bold** and [link](https://example.com)\n- [x] ready\n',
'Inline \\(a+b\\), $x$ and \\\\(escaped\\).\n$x^2$\n\\(y\\)\n\\[z\\]\n\\[\na+b\n\\]\n',
'`\\(code\\)` ``a ` \\(b\\)`` and \\(x\\)\n```tex\n\\(x\\)\n```\n~~~\n$y$\n~~~\n',
'````tex\n```\n\\[x\\]\n````\n ~~~txt\n\\(y\\)\n ~~~~\n\\(z\\)\n',
'a\r\nb\r\n$x$\r\n```txt\r\n\\(code\\)\r\n```\r\nend\r',
'```markdown\r\n# Title\r\n\r\n\\(x\\)\r\n```',
'<html>\r\n<body><p>\\(x\\)</p></body>\r\n</html>',
'```html\r\n<section><strong>bold</strong></section>\r\n```',
'<section>**raw**\r\ntext</section>',
'partial \\(x + \\) then `code \\( and `` and \\[\n\\',
'\n\nplain\rtext\r\n\n $indented$\n \\(indented\\)\n'
]
const prose = '# Streaming answer\n\n' + (
'A growing paragraph with **emphasis**, `inline code`, and [a link](https://example.com).\n\n' +
'- First item\n- Second item\n\n> A quoted explanation.\n\n'
).repeat(48)
export const performanceCorpus = [
{ name: 'prose', content: prose },
{ name: 'mixed', content: (prose.slice(0, 1200) + '\n\\(x^2 + y^2\\)\n\n' +
'```ts\nconst value = "\\(literal\\)"\n```\n\n| A | B |\n| - | - |\n| 1 | 2 |\n\n').repeat(5) },
{ name: 'crlf', content: prose.replaceAll('\n', '\r\n') }
]
const longSection = [
'## Deployment review\n',
'The service processes incoming records in order and stores the last completed sequence. ' +
'A restart resumes from that sequence so operators can inspect partial progress without repeating successful work. ' +
'Keep **validation results** next to the source record and link the [runbook](https://example.com/runbook) in the report.\n',
'Before deployment, compare the proposed configuration with the active settings. ' +
'Check the database connection, confirm the worker count, and run a small representative batch. ' +
'Record the elapsed time and any rejected records before increasing concurrency.\n',
'- Validate required fields before writing.\n- Commit each completed batch.\n- Review rejected records separately.\n',
'```ts\nasync function processBatch(records: Record<string, string>[]) {\n' +
' for (const record of records) {\n const label = record.name ?? "unnamed"\n' +
' await store.save({ ...record, label })\n }\n}\n```\n',
'| Check | Expected result | Follow-up |\n| --- | --- | --- |\n' +
'| Validation | Required fields present | Review rejected rows |\n' +
'| Persistence | Completed batches stored | Resume from checkpoint |\n' +
'| Throughput | Stable processing time | Inspect slow operations |\n',
'> Keep the original input available until the final reconciliation has completed.\n\n'
].join('\n')
const longBody = longSection.repeat(Math.floor(102_400 / longSection.length))
// ASCII makes character and UTF-8 byte lengths identical: exactly 100 KiB.
export const longAnswerCorpus = longBody + 'Final review notes. '.repeat(100)
.slice(0, 102_400 - longBody.length)
@@ -0,0 +1,34 @@
import { app, BrowserWindow } from 'electron'
import assert from 'node:assert/strict'
import { join } from 'node:path'
import process from 'node:process'
import console from 'node:console'
import { setTimeout } from 'node:timers/promises'
app.setPath('userData', join(process.env.GOODBUDDY_MARKDOWN_DIRECTORY, 'profile'))
app.commandLine.appendSwitch('force-device-scale-factor', '1')
app.whenReady().then(async () => {
const win = new BrowserWindow({ show: true, width: 1100, height: 800,
webPreferences: { sandbox: true, contextIsolation: true, nodeIntegration: false, backgroundThrottling: false } })
const errors = []
win.webContents.on('console-message', event => {
if (event.level === 'error') errors.push(event.message)
})
await win.loadURL(process.env.GOODBUDDY_MARKDOWN_URL)
for (let i = 0; i < 600; i++) {
if (await win.webContents.executeJavaScript('typeof window.streamingMarkdown === "function"')) break
await setTimeout(25)
}
const result = await win.webContents.executeJavaScript('window.streamingMarkdown()')
assert(result.prefixesChecked > 500)
assert.equal(result.domChecks, result.prefixesChecked * 2)
assert.equal(result.longAnswer.bytes, 102_400)
assert.equal(result.longAnswer.prefixLengths.length, 6)
assert.equal(result.longAnswer.samplesPerVariant, 18)
assert.equal(result.longAnswer.domChecks, 24)
assert.equal(result.longAnswer.finalDomEquivalent, true)
assert.deepEqual(errors, [])
console.log('Markdown ' + JSON.stringify({ electron: process.versions.electron,
chromium: process.versions.chrome, ...result }))
app.exit(0)
}).catch(error => { console.error(error); app.exit(1) })
+149
View File
@@ -0,0 +1,149 @@
import { flushSync } from 'react-dom'
import { createRoot } from 'react-dom/client'
import * as current from '../../src/renderer/src/MarkdownRenderer'
import { UiLocaleProvider } from '../../src/renderer/src/i18n/UiLocaleProvider'
import { equivalenceCorpus, longAnswerCorpus, originalNormalize, performanceCorpus } from './streaming-markdown-corpus'
import '../../src/renderer/src/fonts'
import '../../src/renderer/src/styles.css'
type Instrumented = typeof current & { benchmarkNormalize: (content: string) => string }
const normalize = (current as Instrumented).benchmarkNormalize
const host = document.getElementById('root')!
host.className = 'markdown-content'
host.style.cssText = 'width: 800px; padding: 16px'
const root = createRoot(host)
function snapshot(container = host): string {
const clone = container.cloneNode(true) as HTMLElement
const ids = new Map<string, string>()
// Separate component instances receive different React useId values.
// Canonicalize only those IDs/references; retain all content and iframe srcdoc.
for (const element of clone.querySelectorAll('*')) {
for (const name of ['id', 'aria-controls', 'aria-labelledby', 'aria-describedby']) {
const value = element.getAttribute(name)
if (value && /^_r_[a-z0-9]+_$/u.test(value)) {
if (!ids.has(value)) ids.set(value, `react-id-${ids.size}`)
element.setAttribute(name, ids.get(value)!)
}
}
}
return clone.innerHTML
}
const stats = (values: number[]) => {
const sorted = [...values].sort((a, b) => a - b)
return { median: (sorted[Math.floor((sorted.length - 1) / 2)]! + sorted[Math.floor(sorted.length / 2)]!) / 2,
p95: sorted[Math.ceil(sorted.length * 0.95) - 1] }
}
async function run() {
const originalPath = '/src/renderer/src/MarkdownRenderer.tsx?streaming-original'
const original = await import(/* @vite-ignore */ originalPath) as Instrumented
const render = (Component: typeof current.MarkdownRenderer, content: string, renderHtml = false) => {
flushSync(() => root.render(<UiLocaleProvider initialPreference="en-US">
<Component renderHtml={renderHtml}>{content}</Component>
</UiLocaleProvider>))
}
// Warm fonts, styles, React, Markdown, and KaTeX before recording samples.
render(current.MarkdownRenderer, performanceCorpus[1]!.content)
await document.fonts.ready
const results = []
for (const corpus of performanceCorpus) {
const prefixes = Array.from({ length: 24 }, (_, i) => corpus.content.slice(0, Math.ceil(corpus.content.length * (i + 1) / 24)))
const renderTimes: number[] = []
const normalizeTimes: number[] = []
let checksum = 0
for (let round = 0; round < 4; round++) {
render(current.MarkdownRenderer, '')
for (const prefix of prefixes) {
await new Promise<void>(resolve => requestAnimationFrame(() => resolve()))
const start = performance.now()
render(current.MarkdownRenderer, prefix)
// Include the synchronous DOM commit and Chromium style/layout, not frame waiting.
void host.offsetHeight
if (round > 0) renderTimes.push(performance.now() - start)
}
}
// Batch sub-millisecond calls to exceed Chromium timer resolution.
for (let round = 0; round < 4; round++) {
for (const prefix of prefixes) {
const start = performance.now()
for (let i = 0; i < 100; i++) checksum += normalize(prefix).length
if (round > 0) normalizeTimes.push((performance.now() - start) / 100)
}
}
results.push({ corpus: corpus.name, characters: corpus.content.length, samples: renderTimes.length,
renderMs: stats(renderTimes), normalizeMs: stats(normalizeTimes), checksum })
}
const originalHost = document.createElement('div')
originalHost.className = host.className
originalHost.style.cssText = host.style.cssText
document.body.append(originalHost)
const originalRoot = createRoot(originalHost)
const longSamples = { original: [] as number[], current: [] as number[] }
const prefixLengths = Array.from({ length: 6 }, (_, i) => Math.ceil(longAnswerCorpus.length * (i + 1) / 6))
let longDomChecks = 0
try {
// One warm-up sweep, three measured sweeps: 48 renders total, on persistent roots.
for (let round = 0; round < 4; round++) {
render(current.MarkdownRenderer, '')
flushSync(() => originalRoot.render(<UiLocaleProvider initialPreference="en-US">
<original.MarkdownRenderer>{''}</original.MarkdownRenderer>
</UiLocaleProvider>))
for (const [index, length] of prefixLengths.entries()) {
const prefix = longAnswerCorpus.slice(0, length)
if (normalize(prefix) !== originalNormalize(prefix)) throw new Error(`Long normalizer mismatch: ${length}`)
const order = (round + index) % 2 === 0
? ['original', 'current'] as const : ['current', 'original'] as const
for (const variant of order) {
await new Promise<void>(resolve => requestAnimationFrame(() => resolve()))
const start = performance.now()
if (variant === 'original') {
flushSync(() => originalRoot.render(<UiLocaleProvider initialPreference="en-US">
<original.MarkdownRenderer>{prefix}</original.MarkdownRenderer>
</UiLocaleProvider>))
void originalHost.offsetHeight
} else {
render(current.MarkdownRenderer, prefix)
void host.offsetHeight
}
if (round > 0) longSamples[variant].push(performance.now() - start)
}
// Compare outside timing, including the complete 100 KiB answer on every sweep.
if (snapshot() !== snapshot(originalHost)) throw new Error(`Long DOM mismatch: ${length}`)
longDomChecks++
}
}
if (!host.querySelector('h2') || !host.querySelector('pre code') || !host.querySelector('table')) {
throw new Error('Long-answer prose/code/table formatting missing')
}
} finally {
flushSync(() => originalRoot.unmount())
originalHost.remove()
}
const longAnswer = { characters: longAnswerCorpus.length, bytes: new TextEncoder().encode(longAnswerCorpus).length,
prefixLengths, warmupSweeps: 1, measuredSweeps: 3, samplesPerVariant: longSamples.current.length,
originalRenderMs: stats(longSamples.original), currentRenderMs: stats(longSamples.current),
rawRenderMs: longSamples, domChecks: longDomChecks, finalDomEquivalent: true }
let prefixesChecked = 0
let domChecks = 0
for (const content of equivalenceCorpus) {
for (let end = 0; end <= content.length; end++) {
const prefix = content.slice(0, end)
if (normalize(prefix) !== originalNormalize(prefix)) throw new Error(`Normalizer mismatch: ${JSON.stringify(prefix)}`)
prefixesChecked++
for (const renderHtml of [false, true]) {
render(original.MarkdownRenderer, prefix, renderHtml)
const expected = snapshot()
render(current.MarkdownRenderer, prefix, renderHtml)
if (snapshot() !== expected) throw new Error(`DOM mismatch (${renderHtml}): ${JSON.stringify(prefix)}`)
domChecks++
}
}
}
render(current.MarkdownRenderer, '# Live\n\n**formatted** and \\(x\\)')
if (!host.querySelector('h1') || !host.querySelector('strong') || !host.querySelector('.katex')) {
throw new Error('Real Markdown formatting missing')
}
return { results, longAnswer, prefixesChecked, domChecks }
}
Object.assign(window, { streamingMarkdown: run })