





















@@ -596,6 +596,189 @@ describe("runMemoryFlushIfNeeded", () => {
596596expect(compactCall.currentTokenCount).toBeGreaterThan(100_000);
597597});
598598599+it("combines latest usage with post-usage tail pressure for preflight compaction", async () => {
600+const sessionFile = path.join(rootDir, "combined-tail-pressure-session.jsonl");
601+await fs.writeFile(
602+sessionFile,
603+[
604+JSON.stringify({
605+message: {
606+role: "assistant",
607+content: "small answer",
608+usage: { input: 86_000, output: 2_000 },
609+},
610+}),
611+JSON.stringify({
612+message: {
613+role: "tool",
614+content: `moderate interrupted tool output ${"x".repeat(36_000)}`,
615+},
616+}),
617+].join("\n"),
618+"utf8",
619+);
620+registerMemoryFlushPlanResolverForTest(() => ({
621+softThresholdTokens: 4_000,
622+forceFlushTranscriptBytes: 1_000_000_000,
623+reserveTokensFloor: 0,
624+prompt: "Pre-compaction memory flush.\nNO_REPLY",
625+systemPrompt: "Write memory to memory/YYYY-MM-DD.md.",
626+relativePath: "memory/2023-11-14.md",
627+}));
628+const sessionEntry: SessionEntry = {
629+sessionId: "session",
630+ sessionFile,
631+updatedAt: Date.now(),
632+totalTokensFresh: false,
633+};
634+635+await runPreflightCompactionIfNeeded({
636+cfg: { agents: { defaults: { compaction: { memoryFlush: {} } } } },
637+followupRun: createTestFollowupRun({
638+sessionId: "session",
639+ sessionFile,
640+sessionKey: "main",
641+}),
642+defaultModel: "anthropic/claude-opus-4-6",
643+agentCfgContextTokens: 100_000,
644+ sessionEntry,
645+sessionStore: { main: sessionEntry },
646+sessionKey: "main",
647+storePath: path.join(rootDir, "sessions.json"),
648+isHeartbeat: false,
649+replyOperation: createReplyOperation(),
650+});
651+652+const compactCall = compactEmbeddedPiSessionMock.mock.calls[0]?.[0] as {
653+currentTokenCount?: number;
654+};
655+expect(compactCall.currentTokenCount).toBeGreaterThanOrEqual(96_000);
656+});
657+658+it("does not count bytes from a large latest usage record as post-usage tail pressure", async () => {
659+const sessionFile = path.join(rootDir, "large-usage-record-session.jsonl");
660+await fs.writeFile(
661+sessionFile,
662+[
663+JSON.stringify({
664+type: "session",
665+id: "session",
666+}),
667+JSON.stringify({
668+message: {
669+role: "assistant",
670+content: `large answer ${"x".repeat(300_000)}`,
671+usage: { input: 40_000, output: 2_000 },
672+},
673+}),
674+].join("\n"),
675+"utf8",
676+);
677+registerMemoryFlushPlanResolverForTest(() => ({
678+softThresholdTokens: 4_000,
679+forceFlushTranscriptBytes: 1_000_000_000,
680+reserveTokensFloor: 0,
681+prompt: "Pre-compaction memory flush.\nNO_REPLY",
682+systemPrompt: "Write memory to memory/YYYY-MM-DD.md.",
683+relativePath: "memory/2023-11-14.md",
684+}));
685+const sessionEntry: SessionEntry = {
686+sessionId: "session",
687+ sessionFile,
688+updatedAt: Date.now(),
689+totalTokensFresh: false,
690+};
691+692+const entry = await runPreflightCompactionIfNeeded({
693+cfg: { agents: { defaults: { compaction: { memoryFlush: {} } } } },
694+followupRun: createTestFollowupRun({
695+sessionId: "session",
696+ sessionFile,
697+sessionKey: "main",
698+}),
699+defaultModel: "anthropic/claude-opus-4-6",
700+agentCfgContextTokens: 100_000,
701+ sessionEntry,
702+sessionStore: { main: sessionEntry },
703+sessionKey: "main",
704+storePath: path.join(rootDir, "sessions.json"),
705+isHeartbeat: false,
706+replyOperation: createReplyOperation(),
707+});
708+709+expect(entry).toBe(sessionEntry);
710+expect(compactEmbeddedPiSessionMock).not.toHaveBeenCalled();
711+});
712+713+it("does not treat raw transcript metadata bytes as token pressure", async () => {
714+const sessionFile = path.join(rootDir, "metadata-heavy-session.jsonl");
715+await fs.writeFile(
716+sessionFile,
717+[
718+JSON.stringify({
719+type: "session",
720+id: "session",
721+}),
722+JSON.stringify({
723+type: "custom",
724+payload: "x".repeat(450_000),
725+}),
726+JSON.stringify({
727+message: {
728+role: "assistant",
729+content: "small answer",
730+usage: { input: 40_000, output: 2_000 },
731+},
732+}),
733+].join("\n"),
734+"utf8",
735+);
736+registerMemoryFlushPlanResolverForTest(() => ({
737+softThresholdTokens: 4_000,
738+forceFlushTranscriptBytes: 1_000_000_000,
739+reserveTokensFloor: 0,
740+prompt: "Pre-compaction memory flush.\nNO_REPLY",
741+systemPrompt: "Write memory to memory/YYYY-MM-DD.md.",
742+relativePath: "memory/2023-11-14.md",
743+}));
744+const sessionEntry: SessionEntry = {
745+sessionId: "session",
746+ sessionFile,
747+updatedAt: Date.now(),
748+totalTokensFresh: false,
749+};
750+751+const entry = await runPreflightCompactionIfNeeded({
752+cfg: {
753+agents: {
754+defaults: {
755+compaction: {
756+memoryFlush: {},
757+truncateAfterCompaction: true,
758+maxActiveTranscriptBytes: "10mb",
759+},
760+},
761+},
762+},
763+followupRun: createTestFollowupRun({
764+sessionId: "session",
765+ sessionFile,
766+sessionKey: "main",
767+}),
768+defaultModel: "anthropic/claude-opus-4-6",
769+agentCfgContextTokens: 100_000,
770+ sessionEntry,
771+sessionStore: { main: sessionEntry },
772+sessionKey: "main",
773+storePath: path.join(rootDir, "sessions.json"),
774+isHeartbeat: false,
775+replyOperation: createReplyOperation(),
776+});
777+778+expect(entry).toBe(sessionEntry);
779+expect(compactEmbeddedPiSessionMock).not.toHaveBeenCalled();
780+});
781+599782it("triggers preflight compaction when the active transcript exceeds the configured byte threshold", async () => {
600783const sessionFile = path.join(rootDir, "large-session.jsonl");
601784await fs.writeFile(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。