File size: 3,441 Bytes
9dc6089
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
 * Test: before_compaction & after_compaction hook wiring
 */
import { beforeEach, describe, expect, it, vi } from "vitest";

const hookMocks = vi.hoisted(() => ({
  runner: {
    hasHooks: vi.fn(() => false),
    runBeforeCompaction: vi.fn(async () => {}),
    runAfterCompaction: vi.fn(async () => {}),
  },
}));

vi.mock("../plugins/hook-runner-global.js", () => ({
  getGlobalHookRunner: () => hookMocks.runner,
}));

vi.mock("../infra/agent-events.js", () => ({
  emitAgentEvent: vi.fn(),
}));

describe("compaction hook wiring", () => {
  beforeEach(() => {
    hookMocks.runner.hasHooks.mockReset();
    hookMocks.runner.hasHooks.mockReturnValue(false);
    hookMocks.runner.runBeforeCompaction.mockReset();
    hookMocks.runner.runBeforeCompaction.mockResolvedValue(undefined);
    hookMocks.runner.runAfterCompaction.mockReset();
    hookMocks.runner.runAfterCompaction.mockResolvedValue(undefined);
  });

  it("calls runBeforeCompaction in handleAutoCompactionStart", async () => {
    hookMocks.runner.hasHooks.mockReturnValue(true);

    const { handleAutoCompactionStart } =
      await import("../agents/pi-embedded-subscribe.handlers.lifecycle.js");

    const ctx = {
      params: { runId: "r1", session: { messages: [1, 2, 3] } },
      state: { compactionInFlight: false },
      log: { debug: vi.fn(), warn: vi.fn() },
      incrementCompactionCount: vi.fn(),
      ensureCompactionPromise: vi.fn(),
    };

    handleAutoCompactionStart(ctx as never);

    await vi.waitFor(() => {
      expect(hookMocks.runner.runBeforeCompaction).toHaveBeenCalledTimes(1);
    });

    const [event] = hookMocks.runner.runBeforeCompaction.mock.calls[0];
    expect(event.messageCount).toBe(3);
  });

  it("calls runAfterCompaction when willRetry is false", async () => {
    hookMocks.runner.hasHooks.mockReturnValue(true);

    const { handleAutoCompactionEnd } =
      await import("../agents/pi-embedded-subscribe.handlers.lifecycle.js");

    const ctx = {
      params: { runId: "r2", session: { messages: [1, 2] } },
      state: { compactionInFlight: true },
      log: { debug: vi.fn(), warn: vi.fn() },
      maybeResolveCompactionWait: vi.fn(),
      getCompactionCount: () => 1,
    };

    handleAutoCompactionEnd(
      ctx as never,
      {
        type: "auto_compaction_end",
        willRetry: false,
      } as never,
    );

    await vi.waitFor(() => {
      expect(hookMocks.runner.runAfterCompaction).toHaveBeenCalledTimes(1);
    });

    const [event] = hookMocks.runner.runAfterCompaction.mock.calls[0];
    expect(event.messageCount).toBe(2);
    expect(event.compactedCount).toBe(1);
  });

  it("does not call runAfterCompaction when willRetry is true", async () => {
    hookMocks.runner.hasHooks.mockReturnValue(true);

    const { handleAutoCompactionEnd } =
      await import("../agents/pi-embedded-subscribe.handlers.lifecycle.js");

    const ctx = {
      params: { runId: "r3", session: { messages: [] } },
      state: { compactionInFlight: true },
      log: { debug: vi.fn(), warn: vi.fn() },
      noteCompactionRetry: vi.fn(),
      resetForCompactionRetry: vi.fn(),
      getCompactionCount: () => 0,
    };

    handleAutoCompactionEnd(
      ctx as never,
      {
        type: "auto_compaction_end",
        willRetry: true,
      } as never,
    );

    await new Promise((r) => setTimeout(r, 50));
    expect(hookMocks.runner.runAfterCompaction).not.toHaveBeenCalled();
  });
});