3198fb6b2b
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>
78 lines
2.8 KiB
TypeScript
78 lines
2.8 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { createElement, createRef } from "react";
|
|
import { renderToString } from "react-dom/server";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
SettledMessageList,
|
|
StreamingMessageEntry,
|
|
UnsplitChatTranscript,
|
|
type ChatTranscriptActions,
|
|
type ChatTranscriptProps,
|
|
} from "../src/components/chat-transcript.tsx";
|
|
import type { ChatMessage } from "../src/lib/chat-message-view.ts";
|
|
import { streamingChatMessageView } from "../src/lib/chat-message-view.ts";
|
|
import {
|
|
disableHomeStreamingRenderProbe,
|
|
enableHomeStreamingRenderProbe,
|
|
homeStreamingRenderProbeSnapshot,
|
|
resetHomeStreamingRenderProbe,
|
|
} from "../src/lib/home-streaming-render-probe.ts";
|
|
|
|
function propsFor(messages: readonly ChatMessage[]): Omit<ChatTranscriptProps, "loading" | "streamingText"> {
|
|
const actionsRef = createRef<ChatTranscriptActions>() as ChatTranscriptProps["actionsRef"];
|
|
actionsRef.current = {
|
|
onFeedback() {},
|
|
onCopy() {},
|
|
onRegenerate() {},
|
|
onFollowUp() {},
|
|
};
|
|
return {
|
|
messages,
|
|
sessionId: "session-test",
|
|
sessionType: "consultation",
|
|
theme: "career",
|
|
messageFeedback: {},
|
|
copiedMessageKey: null,
|
|
cancellationPending: false,
|
|
productEntrypointsDisabled: true,
|
|
actionsRef,
|
|
};
|
|
}
|
|
|
|
test("the split architecture renders settled history once while streaming tokens", () => {
|
|
const messages: ChatMessage[] = [
|
|
{ role: "user", text: "问题一" },
|
|
{ role: "assistant", text: "回答一,需要足够长才能生成追问卡片。" },
|
|
{ role: "user", text: "问题二" },
|
|
{ role: "assistant", text: "回答二,需要足够长才能生成追问卡片。" },
|
|
{ role: "user", text: "请继续说明这个月的安排。" },
|
|
];
|
|
const tokens = ["甲", "甲乙", "甲乙丙", "甲乙丙丁", "甲乙丙丁戊"];
|
|
const base = propsFor(messages);
|
|
|
|
resetHomeStreamingRenderProbe();
|
|
enableHomeStreamingRenderProbe();
|
|
renderToString(createElement(SettledMessageList, { ...base, loading: true }));
|
|
for (const streamingText of tokens) {
|
|
const streamingMessage = streamingChatMessageView(messages, true, streamingText);
|
|
assert.ok(streamingMessage);
|
|
renderToString(createElement(StreamingMessageEntry, { message: streamingMessage }));
|
|
}
|
|
const split = homeStreamingRenderProbeSnapshot();
|
|
disableHomeStreamingRenderProbe();
|
|
|
|
resetHomeStreamingRenderProbe();
|
|
enableHomeStreamingRenderProbe();
|
|
for (const streamingText of tokens) {
|
|
renderToString(createElement(UnsplitChatTranscript, { ...base, loading: true, streamingText }));
|
|
}
|
|
const unsplit = homeStreamingRenderProbeSnapshot();
|
|
disableHomeStreamingRenderProbe();
|
|
|
|
assert.equal(split.settledListRenders, 1);
|
|
assert.equal(split.streamingRowRenders, tokens.length);
|
|
assert.equal(unsplit.unsplitListRenders, tokens.length);
|
|
assert.ok(unsplit.settledRowRenders > split.settledRowRenders);
|
|
});
|