


























@@ -699,6 +699,115 @@ describe("runMemoryFlushIfNeeded", () => {
699699expect(compactCall.sandboxSessionKey).toBe("agent:main:telegram:default:direct:12345");
700700});
701701702+it.each([
703+["stale_thread_binding", "thread not found: <codex-thread-id>"],
704+["missing_thread_binding", "no thread binding for session"],
705+])(
706+"continues after recoverable native harness %s failure during preflight compaction",
707+async (failureReason, reason) => {
708+const sessionFile = path.join(rootDir, "session.jsonl");
709+await fs.writeFile(
710+sessionFile,
711+`${JSON.stringify({ message: { role: "user", content: "x".repeat(5_000) } })}\n`,
712+"utf8",
713+);
714+registerMemoryFlushPlanResolverForTest(() => ({
715+softThresholdTokens: 1,
716+forceFlushTranscriptBytes: 1_000_000_000,
717+reserveTokensFloor: 0,
718+prompt: "Pre-compaction memory flush.\nNO_REPLY",
719+systemPrompt: "Write memory to memory/YYYY-MM-DD.md.",
720+relativePath: "memory/2023-11-14.md",
721+}));
722+compactEmbeddedPiSessionMock.mockResolvedValueOnce({
723+ok: false,
724+compacted: false,
725+ reason,
726+failure: { reason: failureReason },
727+});
728+const sessionEntry: SessionEntry = {
729+sessionId: "session",
730+ sessionFile,
731+updatedAt: Date.now(),
732+totalTokensFresh: false,
733+};
734+const sessionStore = { "agent:main:telegram:group:redacted": sessionEntry };
735+736+const entry = await runPreflightCompactionIfNeeded({
737+cfg: { agents: { defaults: { compaction: { memoryFlush: {} } } } },
738+followupRun: createTestFollowupRun({
739+sessionId: "session",
740+ sessionFile,
741+sessionKey: "agent:main:telegram:group:redacted",
742+}),
743+defaultModel: "anthropic/claude-opus-4-6",
744+agentCfgContextTokens: 100,
745+ sessionEntry,
746+ sessionStore,
747+sessionKey: "agent:main:telegram:group:redacted",
748+storePath: path.join(rootDir, "sessions.json"),
749+isHeartbeat: false,
750+replyOperation: createReplyOperation(),
751+});
752+753+expect(entry).toBe(sessionEntry);
754+expect(compactEmbeddedPiSessionMock).toHaveBeenCalledTimes(1);
755+expect(incrementCompactionCountMock).not.toHaveBeenCalled();
756+},
757+);
758+759+it("still fails preflight compaction for non-binding native harness failures", async () => {
760+const sessionFile = path.join(rootDir, "session.jsonl");
761+await fs.writeFile(
762+sessionFile,
763+`${JSON.stringify({ message: { role: "user", content: "x".repeat(5_000) } })}\n`,
764+"utf8",
765+);
766+registerMemoryFlushPlanResolverForTest(() => ({
767+softThresholdTokens: 1,
768+forceFlushTranscriptBytes: 1_000_000_000,
769+reserveTokensFloor: 0,
770+prompt: "Pre-compaction memory flush.\nNO_REPLY",
771+systemPrompt: "Write memory to memory/YYYY-MM-DD.md.",
772+relativePath: "memory/2023-11-14.md",
773+}));
774+compactEmbeddedPiSessionMock.mockResolvedValueOnce({
775+ok: false,
776+compacted: false,
777+reason: "auth profile mismatch",
778+failure: { reason: "auth_profile_mismatch" },
779+});
780+const sessionEntry: SessionEntry = {
781+sessionId: "session",
782+ sessionFile,
783+updatedAt: Date.now(),
784+totalTokensFresh: false,
785+};
786+const sessionStore = { "agent:main:telegram:group:redacted": sessionEntry };
787+788+await expect(
789+runPreflightCompactionIfNeeded({
790+cfg: { agents: { defaults: { compaction: { memoryFlush: {} } } } },
791+followupRun: createTestFollowupRun({
792+sessionId: "session",
793+ sessionFile,
794+sessionKey: "agent:main:telegram:group:redacted",
795+}),
796+defaultModel: "anthropic/claude-opus-4-6",
797+agentCfgContextTokens: 100,
798+ sessionEntry,
799+ sessionStore,
800+sessionKey: "agent:main:telegram:group:redacted",
801+storePath: path.join(rootDir, "sessions.json"),
802+isHeartbeat: false,
803+replyOperation: createReplyOperation(),
804+}),
805+).rejects.toThrow("Preflight compaction required but failed: auth profile mismatch");
806+807+expect(compactEmbeddedPiSessionMock).toHaveBeenCalledTimes(1);
808+expect(incrementCompactionCountMock).not.toHaveBeenCalled();
809+});
810+702811it("updates the active preflight run after transcript rotation", async () => {
703812const sessionFile = path.join(rootDir, "session.jsonl");
704813const successorFile = path.join(rootDir, "session-rotated.jsonl");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。