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 { const actionsRef = createRef() 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); });