

























@@ -89,6 +89,13 @@ function resetMocks() {
8989mocks.diag.warn.mockReset();
9090}
919192+function warnLogMessages(): string[] {
93+return mocks.diag.warn.mock.calls.map(([message]) => {
94+expect(typeof message).toBe("string");
95+return message as string;
96+});
97+}
98+9299describe("stuck session recovery", () => {
93100beforeEach(() => {
94101resetMocks();
@@ -108,10 +115,10 @@ describe("stuck session recovery", () => {
108115expect(mocks.waitForEmbeddedPiRunEnd).not.toHaveBeenCalled();
109116expect(mocks.forceClearEmbeddedPiRun).not.toHaveBeenCalled();
110117expect(mocks.resetCommandLane).not.toHaveBeenCalled();
111-expect(mocks.diag.warn).toHaveBeenCalledWith(
112-expect.stringContaining("reason=active_embedded_run"),
113-);
114-expect(mocks.diag.warn).toHaveBeenCalledWith(expect.stringContaining("action=observe_only"));
118+expect(warnLogMessages()).toEqual([
119+"stuck session recovery skipped: sessionId=session-1 sessionKey=agent:main:main age=180s queueDepth=1 activeSessionId=session-1",
120+ "stuck session recovery outcome: status=skipped action=observe_only sessionId=session-1 sessionKey=agent:main:main activeSessionId=session-1 activeWorkKind=embedded_run reason=active_embedded_run",
121+]);
115122});
116123117124it("aborts an active embedded run when active abort recovery is enabled", async () => {
@@ -172,15 +179,10 @@ describe("stuck session recovery", () => {
172179fs.rmSync(tempDir, { recursive: true, force: true });
173180}
174181175-expect(mocks.diag.warn).toHaveBeenCalledWith(
176-expect.stringContaining("action=abort_embedded_run"),
177-);
178-expect(mocks.diag.warn).toHaveBeenCalledWith(
179-expect.stringContaining('stopped="Twitter Mention Moderation Agent"'),
180-);
181-expect(mocks.diag.warn).toHaveBeenCalledWith(
182-expect.stringContaining('lastAssistant="There are 40 cached mentions."'),
183-);
182+expect(warnLogMessages()).toEqual([
183+'stuck session recovery: sessionId=run-456 sessionKey=agent:clawblocker:cron:job-123:run:run-456 age=629s action=abort_embedded_run aborted=true drained=true released=0 stopped="Twitter Mention Moderation Agent" cronJobId=job-123 cronRunId=run-456 lastAssistant="There are 40 cached mentions."',
184+"stuck session recovery outcome: status=aborted action=abort_embedded_run sessionId=run-456 sessionKey=agent:clawblocker:cron:job-123:run:run-456 activeSessionId=run-456 activeWorkKind=embedded_run lane=session:agent:clawblocker:cron:job-123:run:run-456 aborted=true drained=true forceCleared=false released=0",
185+]);
184186});
185187186188it("force-clears and releases the session lane when abort cleanup does not drain", async () => {
@@ -255,12 +257,9 @@ describe("stuck session recovery", () => {
255257expect(mocks.abortEmbeddedPiRun).not.toHaveBeenCalled();
256258expect(mocks.forceClearEmbeddedPiRun).not.toHaveBeenCalled();
257259expect(mocks.resetCommandLane).not.toHaveBeenCalled();
258-expect(mocks.diag.warn).toHaveBeenCalledWith(
259-expect.stringContaining("reason=active_reply_work"),
260-);
261-expect(mocks.diag.warn).toHaveBeenCalledWith(
262-expect.stringContaining("activeSessionId=queued-reply-session"),
263-);
260+expect(warnLogMessages()).toEqual([
261+"stuck session recovery outcome: status=skipped action=keep_lane sessionId=queued-reply-session sessionKey=agent:main:main activeSessionId=queued-reply-session activeWorkKind=embedded_run reason=active_reply_work",
262+]);
264263});
265264266265it("does not release the session lane while unregistered lane work is active", async () => {
@@ -287,10 +286,9 @@ describe("stuck session recovery", () => {
287286expect(mocks.abortEmbeddedPiRun).not.toHaveBeenCalled();
288287expect(mocks.forceClearEmbeddedPiRun).not.toHaveBeenCalled();
289288expect(mocks.resetCommandLane).not.toHaveBeenCalled();
290-expect(mocks.diag.warn).toHaveBeenCalledWith(
291-expect.stringContaining("reason=active_lane_task"),
292-);
293-expect(mocks.diag.warn).toHaveBeenCalledWith(expect.stringContaining("laneActive=1"));
289+expect(warnLogMessages()).toEqual([
290+"stuck session recovery outcome: status=skipped action=keep_lane sessionId=unregistered-work-session sessionKey=agent:main:main lane=session:agent:main:main reason=active_lane_task laneActive=1 laneQueued=1",
291+]);
294292});
295293296294it("reports when recovery finds no active work to release", async () => {
@@ -306,7 +304,9 @@ describe("stuck session recovery", () => {
306304});
307305308306expect(mocks.resetCommandLane).toHaveBeenCalledWith("session:agent:main:main");
309-expect(mocks.diag.warn).toHaveBeenCalledWith(expect.stringContaining("reason=no_active_work"));
307+expect(warnLogMessages()).toEqual([
308+"stuck session recovery outcome: status=noop action=none sessionId=stale-session sessionKey=agent:main:main lane=session:agent:main:main reason=no_active_work",
309+]);
310310});
311311312312it("releases a stale session-id lane when no session key is available", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。