




























@@ -4,7 +4,6 @@ import { html, render } from "lit";
44import { afterEach, describe, expect, it, vi } from "vitest";
55import { getSafeLocalStorage } from "../../local-storage.ts";
66import type { MessageGroup } from "../types/chat-types.ts";
7-import { buildChatItems, type BuildChatItemsProps } from "./build-chat-items.ts";
87import {
98renderMessageGroup,
109resetAssistantAttachmentAvailabilityCacheForTest,
@@ -104,6 +103,44 @@ function createMessageGroup(message: unknown, role: string): MessageGroup {
104103};
105104}
106105106+function createAssistantCanvasBlock(params: {
107+suffix: string;
108+title?: string;
109+url?: string;
110+preferredHeight?: number;
111+presentationTarget?: "assistant_message" | "tool_card";
112+}) {
113+const viewId = `cv_inline_${params.suffix}`;
114+const url = params.url ?? `/__openclaw__/canvas/documents/${viewId}/index.html`;
115+const title = params.title ?? "Inline demo";
116+const preferredHeight = params.preferredHeight ?? 360;
117+return {
118+type: "canvas",
119+preview: {
120+kind: "canvas",
121+surface: "assistant_message",
122+render: "url",
123+ viewId,
124+ title,
125+ url,
126+ preferredHeight,
127+},
128+rawText: JSON.stringify({
129+kind: "canvas",
130+view: {
131+backend: "canvas",
132+id: viewId,
133+ url,
134+ title,
135+preferred_height: preferredHeight,
136+},
137+presentation: {
138+target: params.presentationTarget ?? "assistant_message",
139+},
140+}),
141+};
142+}
143+107144function renderMessageGroups(
108145container: HTMLElement,
109146groups: MessageGroup[],
@@ -123,24 +160,6 @@ function renderMessageGroups(
123160);
124161}
125162126-function renderBuiltMessageGroups(
127-container: HTMLElement,
128-props: Partial<BuildChatItemsProps>,
129-opts: Partial<RenderMessageGroupOptions> = {},
130-) {
131-const groups = buildChatItems({
132-sessionKey: "main",
133-messages: [],
134-toolMessages: [],
135-streamSegments: [],
136-stream: null,
137-streamStartedAt: null,
138-showToolCalls: true,
139- ...props,
140-}).filter((item) => item.kind === "group");
141-renderMessageGroups(container, groups, opts);
142-}
143-144163function clearDeleteConfirmSkip() {
145164try {
146165getSafeLocalStorage()?.removeItem("openclaw:skipDeleteConfirm");
@@ -1110,41 +1129,22 @@ describe("grouped chat rendering", () => {
11101129it("renders hidden assistant_message canvas results with the configured sandbox", () => {
11111130const container = document.createElement("div");
11121131const renderCanvas = (params: { embedSandboxMode?: "trusted"; suffix: string }) =>
1113-renderBuiltMessageGroups(
1132+renderMessageGroups(
11141133container,
1115-{
1116-showToolCalls: false,
1117-messages: [
1134+[
1135+createMessageGroup(
11181136{
11191137id: `assistant-canvas-inline-${params.suffix}`,
11201138role: "assistant",
1121-content: [{ type: "text", text: "Inline canvas result." }],
1139+content: [
1140+{ type: "text", text: "Inline canvas result." },
1141+createAssistantCanvasBlock({ suffix: params.suffix }),
1142+],
11221143timestamp: Date.now(),
11231144},
1124-],
1125-toolMessages: [
1126-{
1127-id: `tool-artifact-inline-${params.suffix}`,
1128-role: "tool",
1129-toolCallId: `call-artifact-inline-${params.suffix}`,
1130-toolName: "canvas_render",
1131-content: JSON.stringify({
1132-kind: "canvas",
1133-view: {
1134-backend: "canvas",
1135-id: `cv_inline_${params.suffix}`,
1136-url: `/__openclaw__/canvas/documents/cv_inline_${params.suffix}/index.html`,
1137-title: "Inline demo",
1138-preferred_height: 360,
1139-},
1140-presentation: {
1141-target: "assistant_message",
1142-},
1143-}),
1144-timestamp: Date.now() + 1,
1145-},
1146-],
1147-},
1145+"assistant",
1146+),
1147+],
11481148{
11491149embedSandboxMode: params.embedSandboxMode ?? "scripts",
11501150},
@@ -1169,19 +1169,22 @@ describe("grouped chat rendering", () => {
1169116911701170it("renders assistant_message canvas results in the assistant bubble even when tool rows are visible", () => {
11711171const container = document.createElement("div");
1172-renderBuiltMessageGroups(
1172+renderMessageGroups(
11731173container,
1174-{
1175-showToolCalls: true,
1176-messages: [
1174+[
1175+createMessageGroup(
11771176{
11781177id: "assistant-canvas-inline-visible",
11791178role: "assistant",
1180-content: [{ type: "text", text: "Inline canvas result." }],
1179+content: [
1180+{ type: "text", text: "Inline canvas result." },
1181+createAssistantCanvasBlock({ suffix: "visible" }),
1182+],
11811183timestamp: Date.now(),
11821184},
1183-],
1184-toolMessages: [
1185+"assistant",
1186+),
1187+createMessageGroup(
11851188{
11861189id: "tool-artifact-inline-visible",
11871190role: "tool",
@@ -1202,8 +1205,9 @@ describe("grouped chat rendering", () => {
12021205}),
12031206timestamp: Date.now() + 1,
12041207},
1205-],
1206-},
1208+"tool",
1209+),
1210+],
12071211{
12081212isToolMessageExpanded: () => true,
12091213},
@@ -1222,19 +1226,19 @@ describe("grouped chat rendering", () => {
12221226it("opens generic tool details instead of a canvas preview from tool rows", () => {
12231227const container = document.createElement("div");
12241228const onOpenSidebar = vi.fn();
1225-renderBuiltMessageGroups(
1229+renderMessageGroups(
12261230container,
1227-{
1228-showToolCalls: true,
1229-messages: [
1231+[
1232+createMessageGroup(
12301233{
12311234id: "assistant-canvas-sidebar",
12321235role: "assistant",
12331236content: [{ type: "text", text: "Sidebar canvas result." }],
12341237timestamp: Date.now(),
12351238},
1236-],
1237-toolMessages: [
1239+"assistant",
1240+),
1241+createMessageGroup(
12381242{
12391243id: "tool-artifact-sidebar",
12401244role: "tool",
@@ -1255,8 +1259,9 @@ describe("grouped chat rendering", () => {
12551259}),
12561260timestamp: Date.now() + 1,
12571261},
1258-],
1259-},
1262+"tool",
1263+),
1264+],
12601265{
12611266isToolExpanded: () => true,
12621267isToolMessageExpanded: () => true,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。