

























@@ -17,6 +17,7 @@ import {
1717resolveModelMock,
1818resolveSandboxContextMock,
1919resolveSessionAgentIdMock,
20+rotateTranscriptAfterCompactionMock,
2021resetCompactHooksHarnessMocks,
2122resetCompactSessionStateMocks,
2223sessionAbortCompactionMock,
@@ -411,6 +412,49 @@ describe("compactEmbeddedPiSessionDirect hooks", () => {
411412}
412413});
413414415+it("emits post-compaction side effects once for a rotated successor transcript", async () => {
416+const listener = vi.fn();
417+const cleanup = onSessionTranscriptUpdate(listener);
418+const sync = vi.fn(async () => {});
419+getMemorySearchManagerMock.mockResolvedValue({ manager: { sync } });
420+rotateTranscriptAfterCompactionMock.mockResolvedValueOnce({
421+rotated: true,
422+sessionId: "rotated-session",
423+sessionFile: "/tmp/rotated-session.jsonl",
424+leafId: "rotated-leaf",
425+});
426+427+try {
428+const result = await compactEmbeddedPiSessionDirect({
429+sessionId: "session-1",
430+sessionKey: TEST_SESSION_KEY,
431+sessionFile: "/tmp/session.jsonl",
432+workspaceDir: "/tmp/workspace",
433+config: {
434+agents: {
435+defaults: {
436+compaction: {
437+truncateAfterCompaction: true,
438+postIndexSync: "await",
439+},
440+},
441+},
442+} as never,
443+});
444+445+expect(result.ok).toBe(true);
446+expect(listener).toHaveBeenCalledTimes(1);
447+expect(listener).toHaveBeenCalledWith({ sessionFile: "/tmp/rotated-session.jsonl" });
448+expect(sync).toHaveBeenCalledTimes(1);
449+expect(sync).toHaveBeenCalledWith({
450+reason: "post-compaction",
451+sessionFiles: ["/tmp/rotated-session.jsonl"],
452+});
453+} finally {
454+cleanup();
455+}
456+});
457+414458it("preserves tokensAfter when full-session context exceeds result.tokensBefore", async () => {
415459estimateTokensMock.mockImplementation((message: unknown) => {
416460const role = (message as { role?: string }).role;
@@ -1008,6 +1052,63 @@ describe("compactEmbeddedPiSession hooks (ownsCompaction engine)", () => {
10081052);
10091053});
101010541055+it("rotates in the wrapper when a delegated result echoes the current transcript", async () => {
1056+const maintain = vi.fn(async (_params?: unknown) => ({
1057+changed: false,
1058+bytesFreed: 0,
1059+rewrittenEntries: 0,
1060+}));
1061+resolveContextEngineMock.mockResolvedValue({
1062+info: { ownsCompaction: false },
1063+compact: contextEngineCompactMock,
1064+ maintain,
1065+} as never);
1066+contextEngineCompactMock.mockResolvedValue({
1067+ok: true,
1068+compacted: true,
1069+reason: undefined,
1070+result: {
1071+summary: "engine-summary",
1072+firstKeptEntryId: "entry-1",
1073+tokensBefore: 120,
1074+tokensAfter: 50,
1075+sessionId: TEST_SESSION_ID,
1076+sessionFile: TEST_SESSION_FILE,
1077+},
1078+} as never);
1079+rotateTranscriptAfterCompactionMock.mockResolvedValueOnce({
1080+rotated: true,
1081+sessionId: "wrapper-rotated-session",
1082+sessionFile: "/tmp/wrapper-rotated-session.jsonl",
1083+leafId: "wrapper-rotated-leaf",
1084+});
1085+1086+const result = await compactEmbeddedPiSession(
1087+wrappedCompactionArgs({
1088+config: {
1089+agents: {
1090+defaults: {
1091+compaction: {
1092+truncateAfterCompaction: true,
1093+},
1094+},
1095+},
1096+},
1097+}),
1098+);
1099+1100+expect(result.ok).toBe(true);
1101+expect(rotateTranscriptAfterCompactionMock).toHaveBeenCalledTimes(1);
1102+expect(result.result?.sessionId).toBe("wrapper-rotated-session");
1103+expect(result.result?.sessionFile).toBe("/tmp/wrapper-rotated-session.jsonl");
1104+expect(maintain).toHaveBeenCalledWith(
1105+expect.objectContaining({
1106+sessionId: "wrapper-rotated-session",
1107+sessionFile: "/tmp/wrapper-rotated-session.jsonl",
1108+}),
1109+);
1110+});
1111+10111112it("catches and logs hook exceptions without aborting compaction", async () => {
10121113hookRunner.hasHooks.mockReturnValue(true);
10131114hookRunner.runBeforeCompaction.mockRejectedValue(new Error("hook boom"));
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。