





















1+import fs from "node:fs/promises";
2+import os from "node:os";
3+import path from "node:path";
4+import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
5+import { afterEach, describe, expect, it } from "vitest";
6+import { makeAgentAssistantMessage } from "../test-helpers/agent-message-fixtures.js";
7+import { rotateTranscriptAfterCompaction } from "./compaction-successor-transcript.js";
8+import { readTranscriptFileState } from "./transcript-file-state.js";
9+10+let tmpDir: string | undefined;
11+afterEach(async () => {
12+if (tmpDir) {
13+await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => undefined);
14+tmpDir = undefined;
15+}
16+});
17+18+function makeAssistant(text: string, timestamp: number) {
19+return makeAgentAssistantMessage({ content: [{ type: "text", text }], timestamp });
20+}
21+22+function readUserTexts(entries: { type: string; message?: unknown }[]): string[] {
23+return entries
24+.filter(
25+(entry) =>
26+entry.type === "message" &&
27+(entry.message as { role?: unknown } | undefined)?.role === "user",
28+)
29+.map((entry) => {
30+const content = (entry.message as { content?: unknown } | undefined)?.content;
31+if (typeof content === "string") {
32+return content;
33+}
34+if (Array.isArray(content)) {
35+return content.map((block) => (block as { text?: string })?.text ?? "").join("");
36+}
37+return "";
38+});
39+}
40+41+const PROMPT = "Please refactor the authentication module right now";
42+43+describe("rotateTranscriptAfterCompaction duplicate-prompt preservation", () => {
44+it("keeps a kept-tail prompt whose earlier copy was summarized away", async () => {
45+tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "successor-dup-loss-"));
46+const manager = SessionManager.create(tmpDir, tmpDir);
47+48+manager.appendMessage({ role: "user", content: PROMPT, timestamp: 1000 });
49+manager.appendMessage(makeAssistant("Working on it.", 1001));
50+const firstKeptId = manager.appendMessage({
51+role: "user",
52+content: "go on",
53+timestamp: 1002,
54+});
55+manager.appendMessage(makeAssistant("Continuing.", 1003));
56+manager.appendCompaction("Summary of earlier turns.", firstKeptId, 5000);
57+manager.appendMessage({ role: "user", content: PROMPT, timestamp: 40000 });
58+manager.appendMessage(makeAssistant("On it again.", 40001));
59+60+const sessionFile = manager.getSessionFile();
61+if (!sessionFile) {
62+throw new Error("no session file");
63+}
64+65+const result = await rotateTranscriptAfterCompaction({ sessionManager: manager, sessionFile });
66+expect(result.rotated).toBe(true);
67+const successorFile = result.sessionFile;
68+if (!successorFile) {
69+throw new Error("no successor file");
70+}
71+72+const successor = await readTranscriptFileState(successorFile);
73+const userPromptTexts = readUserTexts(
74+successor.getEntries() as { type: string; message?: unknown }[],
75+);
76+77+expect(userPromptTexts.some((text) => text.includes(PROMPT))).toBe(true);
78+});
79+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。