perf(panel): cached info and history paint first, lazy markdown up the thread, background prefetch
This commit is contained in:
1 parent
20568915db
commit
9080eb7dee
10 files changed
+192
-16
No files matched your search
@@ -8,6 +8,7 @@
|
||||
import { cn } from "$lib/utils";
|
||||
import type { ActivityModel } from "./activity.svelte";
|
||||
import { summarizeInput, toolLabel } from "./activity.svelte";
|
||||
import { cacheableHistory, historyKey } from "./history-cache";
|
||||
import { usePanelHost } from "./host";
|
||||
import Markdown from "./markdown.svelte";
|
||||
import QuestionCard from "./question-card.svelte";
|
||||
@@ -26,7 +27,9 @@
|
||||
} = $props();
|
||||
|
||||
const RESULT_CLIP = 600;
|
||||
const CACHED_MESSAGES = 80;
|
||||
// Markdown for the last few screens renders at once; the rest waits
|
||||
// until scrolled near, so a long thread paints as fast as a short one.
|
||||
const EAGER_MARKDOWN = 40;
|
||||
const host = usePanelHost();
|
||||
const NEAR_BOTTOM_PX = 120;
|
||||
const TICK_MS = 1000;
|
||||
@@ -59,7 +62,7 @@
|
||||
failure = null;
|
||||
if (messages === null) {
|
||||
const cached = host.cache?.get<HistoryMessage[]>(
|
||||
`history:${conversationId}`
|
||||
historyKey(conversationId)
|
||||
);
|
||||
if (cached) {
|
||||
messages = cached;
|
||||
@@ -69,10 +72,7 @@
|
||||
({ messages } = await client.history(conversationId));
|
||||
loadedAt = new Date().toISOString();
|
||||
settle();
|
||||
host.cache?.set(
|
||||
`history:${conversationId}`,
|
||||
messages.slice(-CACHED_MESSAGES)
|
||||
);
|
||||
host.cache?.set(historyKey(conversationId), cacheableHistory(messages));
|
||||
} catch (cause) {
|
||||
failure = cause instanceof Error ? cause.message : String(cause);
|
||||
}
|
||||
@@ -181,6 +181,12 @@
|
||||
openSystem = next;
|
||||
}
|
||||
|
||||
// Keys count from the end: when the network copy grows the head past
|
||||
// what the cache held, the tail keeps its nodes and its rendered markdown.
|
||||
function keyOf(message: HistoryMessage, index: number, total: number) {
|
||||
return `${index - total}:${message.role}:${message.ts ?? ""}`;
|
||||
}
|
||||
|
||||
function blocks(message: HistoryMessage): ContentBlock[] {
|
||||
return typeof message.content === "string"
|
||||
? [{ text: message.content, type: "text" }]
|
||||
@@ -237,7 +243,7 @@
|
||||
title="Empty conversation"
|
||||
/>
|
||||
{:else}
|
||||
{#each messages as message, index (index)}
|
||||
{#each messages as message, index (keyOf(message, index, messages.length))}
|
||||
{@const parts = blocks(message)}
|
||||
{@const isResultOnly = parts.every((b) => b.type === "tool_result")}
|
||||
{@const system = systemText(message)}
|
||||
@@ -303,6 +309,7 @@
|
||||
? "rounded-2xl rounded-br-md bg-primary/10 px-3.5 py-2"
|
||||
: "px-1 py-1"
|
||||
)}
|
||||
eager={index >= messages.length - EAGER_MARKDOWN}
|
||||
text={block.text}
|
||||
/>
|
||||
{:else if block.type === "tool_use"}
|
||||
|
||||
Reference in new issue
Block a user