

























@@ -1,5 +1,6 @@
11import { importFreshModule } from "openclaw/plugin-sdk/test-fixtures";
22import { afterEach, describe, expect, it, vi } from "vitest";
3+import { diagnosticLogger } from "../../logging/diagnostic.js";
34import {
45testing as replyRunTesting,
56createReplyOperation,
@@ -356,6 +357,35 @@ describe("pi-embedded runner run registry", () => {
356357expect(resolveActiveEmbeddedRunHandleSessionId("agent:main:main")).toBeUndefined();
357358});
358359360+it("treats repeated clears for a completed run handle as idempotent", () => {
361+const debugSpy = vi.spyOn(diagnosticLogger, "debug").mockImplementation(() => undefined);
362+const handle = createRunHandle();
363+364+setActiveEmbeddedRun("session-repeat-clear", handle, "agent:main:main");
365+clearActiveEmbeddedRun("session-repeat-clear", handle, "agent:main:main");
366+clearActiveEmbeddedRun("session-repeat-clear", handle, "agent:main:main");
367+368+expect(isEmbeddedPiRunHandleActive("session-repeat-clear")).toBe(false);
369+expect(resolveActiveEmbeddedRunHandleSessionId("agent:main:main")).toBeUndefined();
370+expect(
371+debugSpy.mock.calls.some(([message]) => message.includes("reason=handle_mismatch")),
372+).toBe(false);
373+});
374+375+it("still logs handle mismatches when another run owns the session", () => {
376+const debugSpy = vi.spyOn(diagnosticLogger, "debug").mockImplementation(() => undefined);
377+const staleHandle = createRunHandle();
378+const activeHandle = createRunHandle();
379+380+setActiveEmbeddedRun("session-handle-replaced", activeHandle);
381+clearActiveEmbeddedRun("session-handle-replaced", staleHandle);
382+383+expect(isEmbeddedPiRunHandleActive("session-handle-replaced")).toBe(true);
384+expect(
385+debugSpy.mock.calls.some(([message]) => message.includes("reason=handle_mismatch")),
386+).toBe(true);
387+});
388+359389it("tracks and clears per-session transcript snapshots for active runs", () => {
360390const handle = createRunHandle();
361391此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。