fix: keep canvas chat messages ordered

This commit is contained in:
134 2026-07-07 14:27:48 +08:00
parent 690d04ec71
commit 57a4840df2
2 changed files with 57 additions and 4 deletions

View File

@ -381,11 +381,15 @@ export function sortCanvasMessagesByCreatedAt(messages: ChatMessage[]): ChatMess
.sort((a, b) => {
const messageA = a.message;
const messageB = b.message;
const timeA = getMessageTimestamp(messageA) ?? 0;
const timeB = getMessageTimestamp(messageB) ?? 0;
if (timeA !== timeB) return timeA - timeB;
const timeA = getMessageTimestamp(messageA);
const timeB = getMessageTimestamp(messageB);
const hasTimeA = timeA !== null;
const hasTimeB = timeB !== null;
if (messageA.role !== messageB.role) {
if (hasTimeA && hasTimeB && timeA !== timeB) return timeA - timeB;
if (hasTimeA !== hasTimeB) return hasTimeA ? -1 : 1;
if (hasTimeA && hasTimeB && messageA.role !== messageB.role) {
if (messageA.role === "user") return -1;
if (messageB.role === "user") return 1;
}

View File

@ -4,6 +4,7 @@ import {
extractAssistantImageUrls,
extractVideoUrls,
normalizeMediaUrl,
sortCanvasMessagesByCreatedAt,
stripMediaMarkup,
} from "@/components/canvas/chat-panel/canvas-chat-media";
import {
@ -211,6 +212,54 @@ import type { CanvasAgentContext } from "@/types/canvas/agent-protocol";
import type { ChatMessage } from "@/lib/types";
test.describe("canvas chat pure helpers", () => {
test("keeps optimistic messages without timestamps after persisted history", () => {
const messages = [
{
id: "optimistic-latest-user",
role: "user",
parts: [{ type: "text", text: "你能为我做什么?列出表给我" }],
},
{
id: "persisted-first-user",
role: "user",
createdAt: "2026-07-07T01:00:00.000Z",
parts: [{ type: "text", text: "你好" }],
},
{
id: "persisted-first-assistant",
role: "assistant",
createdAt: "2026-07-07T01:00:01.000Z",
parts: [{ type: "text", text: "你好,我在。" }],
},
] as ChatMessage[];
expect(sortCanvasMessagesByCreatedAt(messages).map((message) => message.id)).toEqual([
"persisted-first-user",
"persisted-first-assistant",
"optimistic-latest-user",
]);
});
test("preserves relative order among messages without timestamps", () => {
const messages = [
{
id: "pending-user",
role: "user",
parts: [{ type: "text", text: "生成一张图" }],
},
{
id: "pending-assistant",
role: "assistant",
parts: [{ type: "text", text: "分析中" }],
},
] as ChatMessage[];
expect(sortCanvasMessagesByCreatedAt(messages).map((message) => message.id)).toEqual([
"pending-user",
"pending-assistant",
]);
});
test("formats uploaded spreadsheet rows as safe markdown tables for OpenClaw", () => {
const markdown = rowsToOpenClawMarkdownTable([
["名称", "备注"],