






















@@ -100,6 +100,26 @@ const buildChatItemsMock = vi.hoisted(() =>
100100return [];
101101}),
102102);
103+const renderMessageGroupMock = vi.hoisted(() =>
104+vi.fn((group: { messages: Array<{ message: unknown }> }) => {
105+const element = document.createElement("div");
106+element.className = "chat-group";
107+element.textContent = group.messages
108+.map(({ message }) => {
109+if (typeof message === "object" && message !== null && "content" in message) {
110+const content = (message as { content?: unknown }).content;
111+if (typeof content === "string") {
112+return content;
113+}
114+return content == null ? "" : JSON.stringify(content);
115+}
116+return String(message);
117+})
118+.join("\n");
119+return element;
120+}),
121+);
122+const assistantAttachmentRenderVersionMock = vi.hoisted(() => ({ value: 0 }));
103123104124function requireFirstAttachmentsChange(
105125onAttachmentsChange: ReturnType<typeof vi.fn>,
@@ -124,23 +144,8 @@ vi.mock("../chat/build-chat-items.ts", () => ({
124144}));
125145126146vi.mock("../chat/grouped-render.ts", () => ({
127-renderMessageGroup: (group: { messages: Array<{ message: unknown }> }) => {
128-const element = document.createElement("div");
129-element.className = "chat-group";
130-element.textContent = group.messages
131-.map(({ message }) => {
132-if (typeof message === "object" && message !== null && "content" in message) {
133-const content = (message as { content?: unknown }).content;
134-if (typeof content === "string") {
135-return content;
136-}
137-return content == null ? "" : JSON.stringify(content);
138-}
139-return String(message);
140-})
141-.join("\n");
142-return element;
143-},
147+getAssistantAttachmentAvailabilityRenderVersion: () => assistantAttachmentRenderVersionMock.value,
148+renderMessageGroup: renderMessageGroupMock,
144149renderReadingIndicatorGroup: () => {
145150const element = document.createElement("div");
146151element.className = "chat-reading-indicator";
@@ -490,84 +495,87 @@ function clickTalkSelectOption(container: Element, name: string, value: string):
490495option.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
491496}
492497498+function createChatProps(
499+overrides: Partial<Parameters<typeof renderChat>[0]> = {},
500+): Parameters<typeof renderChat>[0] {
501+return {
502+sessionKey: "main",
503+onSessionKeyChange: () => undefined,
504+thinkingLevel: null,
505+showThinking: false,
506+showToolCalls: true,
507+loading: false,
508+sending: false,
509+compactionStatus: null,
510+fallbackStatus: null,
511+messages: [],
512+sideResult: null,
513+toolMessages: [],
514+streamSegments: [],
515+stream: null,
516+streamStartedAt: null,
517+assistantAvatarUrl: null,
518+draft: "",
519+queue: [],
520+realtimeTalkActive: false,
521+realtimeTalkStatus: "idle",
522+realtimeTalkDetail: null,
523+realtimeTalkTranscript: null,
524+connected: true,
525+canSend: true,
526+disabledReason: null,
527+error: null,
528+sessions: null,
529+sidebarOpen: false,
530+sidebarContent: null,
531+sidebarError: null,
532+splitRatio: 0.6,
533+canvasPluginSurfaceUrl: null,
534+embedSandboxMode: "scripts",
535+allowExternalEmbedUrls: false,
536+assistantName: "Val",
537+assistantAvatar: null,
538+userName: null,
539+userAvatar: null,
540+localMediaPreviewRoots: [],
541+assistantAttachmentAuthToken: null,
542+autoExpandToolCalls: false,
543+attachments: [],
544+onAttachmentsChange: () => undefined,
545+showNewMessages: false,
546+onScrollToBottom: () => undefined,
547+onRefresh: () => undefined,
548+getDraft: () => "",
549+onDraftChange: () => undefined,
550+onRequestUpdate: () => undefined,
551+onSend: () => undefined,
552+onCompact: () => undefined,
553+onToggleRealtimeTalk: () => undefined,
554+onDismissError: () => undefined,
555+onAbort: () => undefined,
556+onQueueRemove: () => undefined,
557+onQueueSteer: () => undefined,
558+onDismissSideResult: () => undefined,
559+onNewSession: () => undefined,
560+onClearHistory: () => undefined,
561+onOpenSessionCheckpoints: () => undefined,
562+agentsList: null,
563+currentAgentId: "main",
564+onAgentChange: () => undefined,
565+onNavigateToAgent: () => undefined,
566+onSessionSelect: () => undefined,
567+onOpenSidebar: () => undefined,
568+onCloseSidebar: () => undefined,
569+onSplitRatioChange: () => undefined,
570+onChatScroll: () => undefined,
571+basePath: "",
572+ ...overrides,
573+};
574+}
575+493576function renderChatView(overrides: Partial<Parameters<typeof renderChat>[0]> = {}) {
494577const container = document.createElement("div");
495-render(
496-renderChat({
497-sessionKey: "main",
498-onSessionKeyChange: () => undefined,
499-thinkingLevel: null,
500-showThinking: false,
501-showToolCalls: true,
502-loading: false,
503-sending: false,
504-compactionStatus: null,
505-fallbackStatus: null,
506-messages: [],
507-sideResult: null,
508-toolMessages: [],
509-streamSegments: [],
510-stream: null,
511-streamStartedAt: null,
512-assistantAvatarUrl: null,
513-draft: "",
514-queue: [],
515-realtimeTalkActive: false,
516-realtimeTalkStatus: "idle",
517-realtimeTalkDetail: null,
518-realtimeTalkTranscript: null,
519-connected: true,
520-canSend: true,
521-disabledReason: null,
522-error: null,
523-sessions: null,
524-sidebarOpen: false,
525-sidebarContent: null,
526-sidebarError: null,
527-splitRatio: 0.6,
528-canvasPluginSurfaceUrl: null,
529-embedSandboxMode: "scripts",
530-allowExternalEmbedUrls: false,
531-assistantName: "Val",
532-assistantAvatar: null,
533-userName: null,
534-userAvatar: null,
535-localMediaPreviewRoots: [],
536-assistantAttachmentAuthToken: null,
537-autoExpandToolCalls: false,
538-attachments: [],
539-onAttachmentsChange: () => undefined,
540-showNewMessages: false,
541-onScrollToBottom: () => undefined,
542-onRefresh: () => undefined,
543-getDraft: () => "",
544-onDraftChange: () => undefined,
545-onRequestUpdate: () => undefined,
546-onSend: () => undefined,
547-onCompact: () => undefined,
548-onToggleRealtimeTalk: () => undefined,
549-onDismissError: () => undefined,
550-onAbort: () => undefined,
551-onQueueRemove: () => undefined,
552-onQueueSteer: () => undefined,
553-onDismissSideResult: () => undefined,
554-onNewSession: () => undefined,
555-onClearHistory: () => undefined,
556-onOpenSessionCheckpoints: () => undefined,
557-agentsList: null,
558-currentAgentId: "main",
559-onAgentChange: () => undefined,
560-onNavigateToAgent: () => undefined,
561-onSessionSelect: () => undefined,
562-onOpenSidebar: () => undefined,
563-onCloseSidebar: () => undefined,
564-onSplitRatioChange: () => undefined,
565-onChatScroll: () => undefined,
566-basePath: "",
567- ...overrides,
568-}),
569-container,
570-);
578+render(renderChat(createChatProps(overrides)), container);
571579return container;
572580}
573581@@ -673,6 +681,8 @@ describe("chat composer workbench", () => {
673681afterEach(() => {
674682vi.useRealTimers();
675683buildChatItemsMock.mockClear();
684+renderMessageGroupMock.mockClear();
685+assistantAttachmentRenderVersionMock.value = 0;
676686loadSessionsMock.mockClear();
677687refreshVisibleToolsEffectiveForCurrentSessionMock.mockClear();
678688resetChatViewState();
@@ -694,6 +704,51 @@ describe("chat transcript rendering cache", () => {
694704expect(buildChatItemsMock).toHaveBeenCalledTimes(1);
695705});
696706707+it("does not rerender transcript groups for draft-only rerenders", () => {
708+const messages = [{ role: "assistant", content: "ready" }];
709+const toolMessages: unknown[] = [];
710+const streamSegments: Array<{ text: string; ts: number }> = [];
711+const queue: ChatQueueItem[] = [];
712+const container = document.createElement("div");
713+714+render(
715+renderChat(createChatProps({ messages, toolMessages, streamSegments, queue })),
716+container,
717+);
718+render(
719+renderChat(createChatProps({ messages, toolMessages, streamSegments, queue, draft: "h" })),
720+container,
721+);
722+render(
723+renderChat(
724+createChatProps({ messages, toolMessages, streamSegments, queue, draft: "hello" }),
725+),
726+container,
727+);
728+729+expect(renderMessageGroupMock).toHaveBeenCalledTimes(1);
730+});
731+732+it("rerenders transcript groups when assistant attachment availability changes", () => {
733+const messages = [{ role: "assistant", content: "ready" }];
734+const toolMessages: unknown[] = [];
735+const streamSegments: Array<{ text: string; ts: number }> = [];
736+const queue: ChatQueueItem[] = [];
737+const container = document.createElement("div");
738+739+render(
740+renderChat(createChatProps({ messages, toolMessages, streamSegments, queue })),
741+container,
742+);
743+assistantAttachmentRenderVersionMock.value += 1;
744+render(
745+renderChat(createChatProps({ messages, toolMessages, streamSegments, queue, draft: "h" })),
746+container,
747+);
748+749+expect(renderMessageGroupMock).toHaveBeenCalledTimes(2);
750+});
751+697752it("rebuilds transcript items when the transcript reference changes", () => {
698753const toolMessages: unknown[] = [];
699754const streamSegments: Array<{ text: string; ts: number }> = [];
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。