mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
perf: isolate chat render caches by pane
This commit is contained in:
@@ -23,6 +23,7 @@ const SENDER_METADATA_BLOCK =
|
||||
|
||||
function createProps(overrides: Partial<CachedChatItemsProps> = {}): CachedChatItemsProps {
|
||||
return {
|
||||
paneId: "pane-a",
|
||||
sessionKey: "main",
|
||||
runId: null,
|
||||
messages: [],
|
||||
@@ -2454,6 +2455,31 @@ describe("thread item cache", () => {
|
||||
}),
|
||||
).not.toBe(first);
|
||||
});
|
||||
|
||||
it("keeps same-session render caches isolated between panes", () => {
|
||||
resetChatThreadState();
|
||||
const messages = [
|
||||
{ role: "assistant", content: "needle" },
|
||||
{ role: "user", content: "other" },
|
||||
];
|
||||
const paneA = createProps({
|
||||
paneId: "pane-a",
|
||||
messages,
|
||||
searchOpen: true,
|
||||
searchQuery: "needle",
|
||||
});
|
||||
const paneB = createProps({ paneId: "pane-b", messages });
|
||||
|
||||
const paneAItems = buildCachedChatItems(paneA);
|
||||
const paneBItems = buildCachedChatItems(paneB);
|
||||
|
||||
expect(buildCachedChatItems({ ...paneA })).toBe(paneAItems);
|
||||
expect(buildCachedChatItems({ ...paneB })).toBe(paneBItems);
|
||||
|
||||
resetChatThreadState("pane-a");
|
||||
expect(buildCachedChatItems({ ...paneA })).not.toBe(paneAItems);
|
||||
expect(buildCachedChatItems({ ...paneB })).toBe(paneBItems);
|
||||
});
|
||||
});
|
||||
|
||||
function canvasBlocksIn(group: MessageGroup): unknown[] {
|
||||
|
||||
@@ -46,6 +46,7 @@ import { getOrCreateSessionCacheValue } from "./session-cache.ts";
|
||||
import { buildUserChatMessageContentBlocks } from "./user-message-content.ts";
|
||||
|
||||
type BuildChatItemsProps = {
|
||||
paneId: string;
|
||||
sessionKey: string;
|
||||
runId?: string | null;
|
||||
/** Invalidates cached display copy when the active UI language changes. */
|
||||
@@ -77,13 +78,17 @@ type StreamRunRenderItem = {
|
||||
parts: Array<Extract<ChatItem, { kind: "stream" } | { kind: "reading-indicator" }>>;
|
||||
};
|
||||
|
||||
const chatItemsBySession = new Map<string, CachedChatItems>();
|
||||
const chatItemsByPane = new Map<string, Map<string, CachedChatItems>>();
|
||||
const expandedToolCardsBySession = new Map<string, Map<string, boolean>>();
|
||||
const initializedToolCardsBySession = new Map<string, Set<string>>();
|
||||
const lastAutoExpandPrefBySession = new Map<string, boolean>();
|
||||
|
||||
export function resetChatThreadState(): void {
|
||||
chatItemsBySession.clear();
|
||||
export function resetChatThreadState(paneId?: string): void {
|
||||
if (paneId) {
|
||||
chatItemsByPane.delete(paneId);
|
||||
return;
|
||||
}
|
||||
chatItemsByPane.clear();
|
||||
resetWorkingStartedAt();
|
||||
expandedToolCardsBySession.clear();
|
||||
initializedToolCardsBySession.clear();
|
||||
@@ -1546,7 +1551,12 @@ function sameChatItemsInput(previous: BuildChatItemsProps, next: BuildChatItemsP
|
||||
export function buildCachedChatItems(
|
||||
input: BuildChatItemsProps,
|
||||
): ReturnType<typeof buildChatItems> {
|
||||
const cached = getOrCreateSessionCacheValue(chatItemsBySession, input.sessionKey, () => ({
|
||||
let paneCache = chatItemsByPane.get(input.paneId);
|
||||
if (!paneCache) {
|
||||
paneCache = new Map();
|
||||
chatItemsByPane.set(input.paneId, paneCache);
|
||||
}
|
||||
const cached = getOrCreateSessionCacheValue(paneCache, input.sessionKey, () => ({
|
||||
input: null,
|
||||
items: [],
|
||||
}));
|
||||
|
||||
@@ -189,6 +189,7 @@ export function resetChatThreadPresentationState(paneId?: string) {
|
||||
removeChatSelectionPopup();
|
||||
if (paneId) {
|
||||
threadStates.delete(paneId);
|
||||
resetChatThreadState(paneId);
|
||||
} else {
|
||||
threadStates.clear();
|
||||
resetChatThreadState();
|
||||
@@ -598,6 +599,7 @@ export function renderChatThread(props: ChatThreadProps) {
|
||||
const deleted = getDeletedMessages(props.sessionKey);
|
||||
const locale = i18n.getLocale();
|
||||
const chatItems = buildCachedChatItems({
|
||||
paneId: props.paneId,
|
||||
sessionKey: props.sessionKey,
|
||||
runId:
|
||||
props.sessions?.sessions.find((row) => areUiSessionKeysEquivalent(row.key, props.sessionKey))
|
||||
|
||||
Reference in New Issue
Block a user