Web UI: show Compaction divider in chat history (#11341)

This commit is contained in:
Tak Hoffman
2026-02-07 12:37:22 -06:00
committed by GitHub
parent f0722498a4
commit 82419eaad6
5 changed files with 117 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ import { afterEach, beforeEach, describe, expect, test } from "vitest";
import {
readFirstUserMessageFromTranscript,
readLastMessagePreviewFromTranscript,
readSessionMessages,
readSessionPreviewItemsFromTranscript,
} from "./session-utils.fs.js";
@@ -343,6 +344,53 @@ describe("readLastMessagePreviewFromTranscript", () => {
});
});
describe("readSessionMessages", () => {
let tmpDir: string;
let storePath: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-fs-test-"));
storePath = path.join(tmpDir, "sessions.json");
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
test("includes synthetic compaction markers for compaction entries", () => {
const sessionId = "test-session-compaction";
const transcriptPath = path.join(tmpDir, `${sessionId}.jsonl`);
const lines = [
JSON.stringify({ type: "session", version: 1, id: sessionId }),
JSON.stringify({ message: { role: "user", content: "Hello" } }),
JSON.stringify({
type: "compaction",
id: "comp-1",
timestamp: "2026-02-07T00:00:00.000Z",
summary: "Compacted history",
firstKeptEntryId: "x",
tokensBefore: 123,
}),
JSON.stringify({ message: { role: "assistant", content: "World" } }),
];
fs.writeFileSync(transcriptPath, lines.join("\n"), "utf-8");
const out = readSessionMessages(sessionId, storePath);
expect(out).toHaveLength(3);
const marker = out[1] as {
role: string;
content?: Array<{ text?: string }>;
__openclaw?: { kind?: string; id?: string };
timestamp?: number;
};
expect(marker.role).toBe("system");
expect(marker.content?.[0]?.text).toBe("Compaction");
expect(marker.__openclaw?.kind).toBe("compaction");
expect(marker.__openclaw?.id).toBe("comp-1");
expect(typeof marker.timestamp).toBe("number");
});
});
describe("readSessionPreviewItemsFromTranscript", () => {
let tmpDir: string;
let storePath: string;

View File

@@ -28,6 +28,23 @@ export function readSessionMessages(
const parsed = JSON.parse(line);
if (parsed?.message) {
messages.push(parsed.message);
continue;
}
// Compaction entries are not "message" records, but they're useful context for debugging.
// Emit a lightweight synthetic message that the Web UI can render as a divider.
if (parsed?.type === "compaction") {
const ts = typeof parsed.timestamp === "string" ? Date.parse(parsed.timestamp) : Number.NaN;
const timestamp = Number.isFinite(ts) ? ts : Date.now();
messages.push({
role: "system",
content: [{ type: "text", text: "Compaction" }],
timestamp,
__openclaw: {
kind: "compaction",
id: typeof parsed.id === "string" ? parsed.id : undefined,
},
});
}
} catch {
// ignore bad lines