






















@@ -4,7 +4,12 @@ import path from "node:path";
44import { beforeEach, describe, expect, it, vi } from "vitest";
55import * as modelThinkingDefault from "../agents/model-thinking-default.js";
66import { runCronIsolatedAgentTurn } from "./isolated-agent.js";
7-import { makeCfg, makeJob, writeSessionStore } from "./isolated-agent.test-harness.js";
7+import {
8+makeCfg,
9+makeJob,
10+writeSessionStore,
11+writeSessionStoreEntries,
12+} from "./isolated-agent.test-harness.js";
813import {
914DEFAULT_AGENT_TURN_PAYLOAD,
1015DEFAULT_MESSAGE,
@@ -18,6 +23,7 @@ import { setupRunCronIsolatedAgentTurnSuite } from "./isolated-agent/run.suite-h
1823import {
1924mockRunCronFallbackPassthrough,
2025runEmbeddedPiAgentMock,
26+updateSessionStoreMock,
2127} from "./isolated-agent/run.test-harness.js";
22282329setupRunCronIsolatedAgentTurnSuite();
@@ -142,6 +148,79 @@ describe("runCronIsolatedAgentTurn session identity", () => {
142148});
143149});
144150151+it("persists rotated transcript identity for session-bound cron runs", async () => {
152+await withTempHome(async (home) => {
153+const deps = makeDeps();
154+const boundSessionKey = "agent:main:telegram:direct:42";
155+const originalSessionFile = path.join(home, "bound-session.jsonl");
156+const rotatedSessionFile = path.join(home, "bound-session-rotated.jsonl");
157+const storePath = await writeSessionStoreEntries(home, {
158+[boundSessionKey]: {
159+sessionId: "bound-session",
160+sessionFile: originalSessionFile,
161+updatedAt: Date.now(),
162+lastInteractionAt: Date.now() - 1_000,
163+systemSent: true,
164+},
165+});
166+runEmbeddedPiAgentMock.mockResolvedValueOnce({
167+payloads: [{ text: "ok" }],
168+meta: {
169+durationMs: 5,
170+agentMeta: {
171+sessionId: "bound-session-rotated",
172+sessionFile: rotatedSessionFile,
173+provider: "anthropic",
174+model: "claude-opus-4-6",
175+compactionCount: 1,
176+compactionTokensAfter: 42,
177+},
178+},
179+});
180+updateSessionStoreMock.mockImplementation(async (_storePath, update) => {
181+const store = {
182+[boundSessionKey]: {
183+sessionId: "bound-session",
184+sessionFile: originalSessionFile,
185+updatedAt: Date.now(),
186+lastInteractionAt: Date.now() - 1_000,
187+systemSent: true,
188+},
189+};
190+update(store);
191+});
192+193+const res = await runCronIsolatedAgentTurn({
194+cfg: makeCfg(home, storePath),
195+ deps,
196+job: {
197+ ...makeJob(DEFAULT_AGENT_TURN_PAYLOAD),
198+sessionTarget: `session:${boundSessionKey}`,
199+delivery: { mode: "none" },
200+},
201+message: DEFAULT_MESSAGE,
202+sessionKey: boundSessionKey,
203+lane: "cron",
204+});
205+206+expect(res.status).toBe("ok");
207+expect(res.sessionId).toBe("bound-session-rotated");
208+209+const finalPersist = updateSessionStoreMock.mock.calls.at(-1);
210+expect(finalPersist?.[0]).toBe(storePath);
211+const persistedStore: Record<string, { [key: string]: unknown }> = {};
212+(finalPersist?.[1] as (store: typeof persistedStore) => void)(persistedStore);
213+expect(persistedStore[boundSessionKey]).toEqual(
214+expect.objectContaining({
215+sessionId: "bound-session-rotated",
216+sessionFile: rotatedSessionFile,
217+usageFamilyKey: boundSessionKey,
218+usageFamilySessionIds: ["bound-session", "bound-session-rotated"],
219+}),
220+);
221+});
222+});
223+145224it("uses lightweight bootstrap context for command-style cron payloads", async () => {
146225await withTempHome(async (home) => {
147226await runCronTurn(home, {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。