perf(frontend): split chat streaming, load Inter, isolate admin CSS
Settled messages no longer rebuild on every token, Inter is actually requested, and admin routes drop the 33 KB chat stylesheet. Root force-dynamic is gone so public shells can prerender without changing the no-store Cache-Control contract. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
export type ChartLibrarySessionBranch = "clear" | "hydrate-then-persist" | "persist-self";
|
||||
|
||||
export function chartLibrarySessionBranch(
|
||||
accountId: string | null | undefined,
|
||||
loadedAccount: string,
|
||||
): ChartLibrarySessionBranch {
|
||||
if (!accountId) return "clear";
|
||||
if (loadedAccount !== accountId) return "hydrate-then-persist";
|
||||
return "persist-self";
|
||||
}
|
||||
|
||||
export function chartLibraryFromCloudOthers<T extends { role: "self" | "other" }>(
|
||||
cloudLibrary: readonly T[],
|
||||
profile: unknown,
|
||||
upsertSelfChart: (library: T[], profile: unknown) => T[],
|
||||
): T[] {
|
||||
return upsertSelfChart(cloudLibrary.filter((record) => record.role !== "self"), profile);
|
||||
}
|
||||
|
||||
export function keepLocalChartLibraryOnCloudFailure<T>(localLibrary: T): T {
|
||||
return localLibrary;
|
||||
}
|
||||
@@ -71,6 +71,41 @@ export type ChatMessageView = ChatMessage & {
|
||||
readonly timeline?: readonly ConsultationTimelineRow[];
|
||||
};
|
||||
|
||||
export function settledChatMessageViews(
|
||||
messages: readonly ChatMessage[],
|
||||
): readonly ChatMessageView[] {
|
||||
return messages.map((message, index) => ({
|
||||
...message,
|
||||
renderKey: `message-${index}`,
|
||||
state: "settled" as const,
|
||||
...(message.role === "assistant"
|
||||
? { timeline: consultationTimelineFromSettled(message) }
|
||||
: {}),
|
||||
}));
|
||||
}
|
||||
|
||||
export function streamingChatMessageView(
|
||||
messages: readonly ChatMessage[],
|
||||
loading: boolean,
|
||||
streamingText: string,
|
||||
activity?: AgentActivityView,
|
||||
thinkingText?: string,
|
||||
thinkingSections?: readonly PublicThinkingSection[],
|
||||
timeline?: readonly ConsultationTimelineRow[],
|
||||
): ChatMessageView | undefined {
|
||||
if (!loading || messages.at(-1)?.role === "assistant") return undefined;
|
||||
return {
|
||||
role: "assistant",
|
||||
text: streamingText,
|
||||
thinkingText,
|
||||
thinkingSections,
|
||||
timeline: timeline ?? [],
|
||||
renderKey: `message-${messages.length}`,
|
||||
state: streamingText ? "streaming" : "thinking",
|
||||
activity,
|
||||
};
|
||||
}
|
||||
|
||||
export function chatMessageViews(
|
||||
messages: readonly ChatMessage[],
|
||||
loading: boolean,
|
||||
@@ -80,27 +115,15 @@ export function chatMessageViews(
|
||||
thinkingSections?: readonly PublicThinkingSection[],
|
||||
timeline?: readonly ConsultationTimelineRow[],
|
||||
): readonly ChatMessageView[] {
|
||||
const settled = messages.map((message, index) => ({
|
||||
...message,
|
||||
renderKey: `message-${index}`,
|
||||
state: "settled" as const,
|
||||
...(message.role === "assistant"
|
||||
? { timeline: consultationTimelineFromSettled(message) }
|
||||
: {}),
|
||||
}));
|
||||
if (!loading || messages.at(-1)?.role === "assistant") return settled;
|
||||
|
||||
return [
|
||||
...settled,
|
||||
{
|
||||
role: "assistant",
|
||||
text: streamingText,
|
||||
thinkingText,
|
||||
thinkingSections,
|
||||
timeline: timeline ?? [],
|
||||
renderKey: `message-${messages.length}`,
|
||||
state: streamingText ? "streaming" : "thinking",
|
||||
activity,
|
||||
},
|
||||
];
|
||||
const settled = settledChatMessageViews(messages);
|
||||
const streaming = streamingChatMessageView(
|
||||
messages,
|
||||
loading,
|
||||
streamingText,
|
||||
activity,
|
||||
thinkingText,
|
||||
thinkingSections,
|
||||
timeline,
|
||||
);
|
||||
return streaming ? [...settled, streaming] : settled;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
export type HomeStreamingRenderProbeSnapshot = Readonly<{
|
||||
settledListRenders: number;
|
||||
settledRowRenders: number;
|
||||
streamingRowRenders: number;
|
||||
unsplitListRenders: number;
|
||||
}>;
|
||||
|
||||
const emptySnapshot = (): HomeStreamingRenderProbeSnapshot => ({
|
||||
settledListRenders: 0,
|
||||
settledRowRenders: 0,
|
||||
streamingRowRenders: 0,
|
||||
unsplitListRenders: 0,
|
||||
});
|
||||
|
||||
let enabled = false;
|
||||
let snapshot = emptySnapshot();
|
||||
|
||||
export function enableHomeStreamingRenderProbe() {
|
||||
enabled = true;
|
||||
snapshot = emptySnapshot();
|
||||
}
|
||||
|
||||
export function disableHomeStreamingRenderProbe() {
|
||||
enabled = false;
|
||||
snapshot = emptySnapshot();
|
||||
}
|
||||
|
||||
export function resetHomeStreamingRenderProbe() {
|
||||
snapshot = emptySnapshot();
|
||||
}
|
||||
|
||||
export function homeStreamingRenderProbeSnapshot(): HomeStreamingRenderProbeSnapshot {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
export function noteSettledListRender() {
|
||||
if (enabled) snapshot = { ...snapshot, settledListRenders: snapshot.settledListRenders + 1 };
|
||||
}
|
||||
|
||||
export function noteSettledRowRender() {
|
||||
if (enabled) snapshot = { ...snapshot, settledRowRenders: snapshot.settledRowRenders + 1 };
|
||||
}
|
||||
|
||||
export function noteStreamingRowRender() {
|
||||
if (enabled) snapshot = { ...snapshot, streamingRowRenders: snapshot.streamingRowRenders + 1 };
|
||||
}
|
||||
|
||||
export function noteUnsplitListRender() {
|
||||
if (enabled) snapshot = { ...snapshot, unsplitListRenders: snapshot.unsplitListRenders + 1 };
|
||||
}
|
||||
Reference in New Issue
Block a user