





















1+/**
2+ * Live proof script for PR #95484 — assistant reply lost after compaction rotation.
3+ *
4+ * Demonstrates that:
5+ * 1. BEFORE fix: successor context shows [compactionSummary, user, ...]
6+ * — the assistant reply is silently dropped.
7+ * 2. AFTER fix: successor context shows [compactionSummary, assistant, user, ...]
8+ * — the assistant reply is preserved.
9+ *
10+ * Usage: node --import tsx scripts/repro/issue-76729-compaction-assistant-loss-proof.mts
11+ */
12+import { mkdtempSync, rmSync } from "node:fs";
13+import { join } from "node:path";
14+import { tmpdir } from "node:os";
15+import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
16+import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
17+import type { TextContent } from "openclaw/plugin-sdk/llm";
18+import { makeAgentAssistantMessage } from "../../src/agents/test-helpers/agent-message-fixtures.js";
19+import { rotateTranscriptAfterCompaction } from "../../src/agents/embedded-agent-runner/compaction-successor-transcript.js";
20+21+const sessionDir = mkdtempSync(join(tmpdir(), "compaction-proof-"));
22+console.log("Session dir:", sessionDir);
23+console.log();
24+25+const manager = SessionManager.create(sessionDir, sessionDir);
26+27+// Build session: user("Summarize") → assistant("Here is the summary") → user("Analyze Q3") → assistant("Q3 analysis...") → compaction(firstKept=user_Analyze_Q3)
28+manager.appendMessage({ role: "user", content: "Summarize reports", timestamp: 1 });
29+manager.appendMessage(makeAgentAssistantMessage({ content: [{ type: "text", text: "Here is the summary" }], timestamp: 2 }));
30+const firstKeptId = manager.appendMessage({ role: "user", content: "Analyze Q3", timestamp: 3 });
31+manager.appendMessage(makeAgentAssistantMessage({ content: [{ type: "text", text: "Q3 analysis shows..." }], timestamp: 4 }));
32+manager.appendCompaction("Summary of previous work.", firstKeptId, 5000);
33+34+// Post-compaction
35+manager.appendMessage({ role: "user", content: "Any more insights?", timestamp: 5 });
36+manager.appendMessage(makeAgentAssistantMessage({ content: [{ type: "text", text: "Additional insights" }], timestamp: 6 }));
37+38+const sessionFile = manager.getSessionFile()!;
39+console.log("Source session file:", sessionFile);
40+console.log();
41+42+const result = await rotateTranscriptAfterCompaction({
43+sessionManager: manager,
44+ sessionFile,
45+now: () => new Date("2026-06-21T12:00:00.000Z"),
46+});
47+48+console.log("Rotation result:", JSON.stringify(result, null, 2));
49+console.log();
50+51+// Open successor and inspect context
52+const successor = SessionManager.open(result.sessionFile!);
53+const context = successor.buildSessionContext();
54+55+console.log("=== SUCCESSOR CONTEXT ===");
56+console.log("Roles:", JSON.stringify(context.messages.map((m) => m.role)));
57+58+for (const msg of context.messages) {
59+if (msg.role === "compactionSummary") {
60+const summary = (msg as AgentMessage & { summary: string }).summary;
61+console.log(` [compactionSummary] summary="${summary}"`);
62+} else if ("content" in msg) {
63+const text = Array.isArray(msg.content)
64+ ? (msg.content[0] as TextContent)?.text ?? JSON.stringify(msg.content)
65+ : msg.content;
66+console.log(` [${msg.role}] "${text}"`);
67+}
68+}
69+console.log();
70+71+const roles = context.messages.map((m) => m.role);
72+console.log("=== VERIFICATION ===");
73+console.log("Role sequence:", JSON.stringify(roles));
74+console.log("compactionSummary → assistant (no gap):", roles[0] === "compactionSummary" && roles[1] === "assistant");
75+console.log("BEFORE fix shows: [compactionSummary, user, assistant, ...] ← missing assistant");
76+console.log("AFTER fix shows:", JSON.stringify(roles));
77+console.log();
78+79+// Cleanup
80+rmSync(sessionDir, { recursive: true, force: true });
81+console.log("Temp dir cleaned up.");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。