






















@@ -17,6 +17,8 @@ import {
1717loadSessionEntry,
1818loadTranscriptEvents,
1919patchSessionEntry,
20+persistSessionResetLifecycle,
21+persistSessionRolloverLifecycle,
2022persistSessionTranscriptTurn,
2123purgeDeletedAgentSessionEntries,
2224publishTranscriptUpdate,
@@ -597,6 +599,118 @@ describe("session accessor file-backed seam", () => {
597599expect(fs.readdirSync(siblingDir)).toEqual(["sibling-lifecycle.jsonl"]);
598600});
599601602+it("persists reset lifecycle entry changes with transcript replay and cleanup", async () => {
603+const now = Date.now();
604+const sessionKey = "agent:main:main";
605+const previousTranscript = path.join(tempDir, "previous-session.jsonl");
606+const nextTranscript = path.join(tempDir, "next-session.jsonl");
607+const previousEntry: SessionEntry = {
608+sessionFile: previousTranscript,
609+sessionId: "previous-session",
610+updatedAt: now,
611+};
612+const nextEntry: SessionEntry = {
613+sessionFile: nextTranscript,
614+sessionId: "next-session",
615+updatedAt: now + 1,
616+};
617+fs.writeFileSync(
618+previousTranscript,
619+[
620+JSON.stringify({ type: "session", id: "previous-session" }),
621+JSON.stringify({
622+id: "msg-user",
623+message: { role: "user", content: "hello" },
624+parentId: null,
625+timestamp: "2026-06-16T00:00:00.000Z",
626+type: "message",
627+}),
628+JSON.stringify({
629+id: "msg-assistant",
630+message: { role: "assistant", content: "hi" },
631+parentId: "msg-user",
632+timestamp: "2026-06-16T00:00:01.000Z",
633+type: "message",
634+}),
635+].join("\n") + "\n",
636+"utf-8",
637+);
638+await upsertSessionEntry({ sessionKey, storePath }, previousEntry);
639+640+const result = await persistSessionResetLifecycle({
641+agentId: "main",
642+cleanupPreviousTranscript: true,
643+ nextEntry,
644+nextSessionFile: nextTranscript,
645+ previousEntry,
646+previousSessionId: previousEntry.sessionId,
647+ sessionKey,
648+ storePath,
649+});
650+651+expect(result.replayedMessages).toBe(2);
652+expect(loadSessionEntry({ sessionKey, storePath })).toMatchObject(nextEntry);
653+expect(fs.existsSync(previousTranscript)).toBe(false);
654+expect(fs.readFileSync(nextTranscript, "utf-8")).toContain('"content":"hello"');
655+});
656+657+it("persists rollover entries and returns archived previous transcript info", async () => {
658+const now = Date.now();
659+const sessionKey = "agent:main:telegram:dm:user";
660+const retiredKey = "agent:main:main";
661+const previousTranscript = path.join(tempDir, "previous-rollover.jsonl");
662+const previousEntry: SessionEntry = {
663+sessionFile: previousTranscript,
664+sessionId: "previous-rollover",
665+updatedAt: now,
666+};
667+const nextEntry: SessionEntry = {
668+sessionFile: path.join(tempDir, "next-rollover.jsonl"),
669+sessionId: "next-rollover",
670+updatedAt: now + 1,
671+};
672+fs.writeFileSync(previousTranscript, '{"type":"session","id":"previous-rollover"}\n', "utf-8");
673+await upsertSessionEntry({ sessionKey, storePath }, previousEntry);
674+await upsertSessionEntry(
675+{ sessionKey: retiredKey, storePath },
676+{
677+lastChannel: "telegram",
678+lastTo: "user",
679+sessionId: "legacy-main",
680+updatedAt: now,
681+},
682+);
683+684+const result = await persistSessionRolloverLifecycle({
685+activeSessionKey: sessionKey,
686+agentId: "main",
687+ previousEntry,
688+retiredEntry: {
689+key: retiredKey,
690+entry: {
691+sessionId: "legacy-main",
692+updatedAt: now,
693+},
694+},
695+sessionEntry: nextEntry,
696+ sessionKey,
697+ storePath,
698+});
699+700+expect(result.sessionEntry).toMatchObject(nextEntry);
701+expect(result.previousSessionTranscript.transcriptArchived).toBe(true);
702+expect(result.previousSessionTranscript.sessionFile).toContain(
703+"previous-rollover.jsonl.reset.",
704+);
705+expect(loadSessionEntry({ sessionKey, storePath })).toMatchObject(nextEntry);
706+expect(loadSessionEntry({ sessionKey: retiredKey, storePath })).toEqual({
707+sessionId: "legacy-main",
708+updatedAt: expect.any(Number),
709+});
710+expect(fs.existsSync(previousTranscript)).toBe(false);
711+expect(fs.existsSync(result.previousSessionTranscript.sessionFile ?? "")).toBe(true);
712+});
713+600714it("loads and appends transcript events through a session scope", async () => {
601715const scope = {
602716sessionFile: transcriptPath,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。