ui: reduce per-token render cost when streaming (#26053)
* performance harness - the empirical root Assisted-by: Claude Opus 4.8 * 210.36ms -> 2.67ms per streamed token Assisted-by: Claude Opus 4.8 * 11.58ms -> 0.62ms per streamed token Assisted-by: Claude Opus 4.8 * 22.02ms -> 3.33ms per streamed token Assisted-by: Claude Opus 4.8 * 3.07ms -> 1.36ms per streamed token at 40 messages Assisted-by: Claude Opus 4.8 --------- Co-authored-by: Zach Winter <dmtommy@icloud.com>
This commit is contained in:
co-authored by
Zach Winter
parent
96013c5112
commit
555881ebc8
@@ -89,10 +89,15 @@
|
||||
</Collapsible.Trigger>
|
||||
|
||||
<Collapsible.Content>
|
||||
<div class="pl-1.5 grid min-w-0" style="min-height: var(--min-message-height);">
|
||||
<div class="min-w-0 border-l border-muted-foreground/20 pl-4 pb-2 my-2">
|
||||
{@render children()}
|
||||
<!-- Collapsible.Content renders its children unconditionally and only sets
|
||||
`hidden`, so a closed block would keep re-rendering its whole body on
|
||||
every streamed token. Gate on `open` so collapsed content costs nothing. -->
|
||||
{#if open}
|
||||
<div class="pl-1.5 grid min-w-0" style="min-height: var(--min-message-height);">
|
||||
<div class="min-w-0 border-l border-muted-foreground/20 pl-4 pb-2 my-2">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
|
||||
@@ -90,8 +90,12 @@
|
||||
</Collapsible.Trigger>
|
||||
|
||||
<Collapsible.Content>
|
||||
<div class="p-3 pt-1">
|
||||
{@render children()}
|
||||
</div>
|
||||
<!-- See CollapsibleContentBlock: bits-ui keeps closed content mounted, which
|
||||
makes a collapsed tool result re-render on every streamed token. -->
|
||||
{#if open}
|
||||
<div class="p-3 pt-1">
|
||||
{@render children()}
|
||||
</div>
|
||||
{/if}
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
|
||||
@@ -107,6 +107,15 @@
|
||||
return null;
|
||||
});
|
||||
const liveSvgHtml = $derived(streamingSvgCode !== null ? sanitizeSvg(streamingSvgCode) : '');
|
||||
|
||||
// Derived rather than called inline in the template so it only recomputes when
|
||||
// the block actually changes. Auto-detection is disabled while streaming: it
|
||||
// costs ~38ms a call and re-guesses the language on every chunk.
|
||||
const streamingCodeHtml = $derived(
|
||||
incompleteCodeBlock
|
||||
? highlightCode(incompleteCodeBlock.code, incompleteCodeBlock.language || 'text', false)
|
||||
: ''
|
||||
);
|
||||
let previewDialogOpen = $state(false);
|
||||
let previewCode = $state('');
|
||||
let previewLanguage = $state('text');
|
||||
@@ -903,10 +912,7 @@
|
||||
>
|
||||
<pre class="streaming-code-pre"><code
|
||||
class="hljs language-{incompleteCodeBlock.language || 'text'}"
|
||||
>{@html highlightCode(
|
||||
incompleteCodeBlock.code,
|
||||
incompleteCodeBlock.language || 'text'
|
||||
)}</code
|
||||
>{@html streamingCodeHtml}</code
|
||||
></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user