@monotykamary/pi-vcc 0.3.16 → 0.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monotykamary/pi-vcc",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.17",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@monotykamary/pi-vcc",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.17",
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"knip": "6.14.1",
|
|
12
12
|
"typescript": "6.0.3"
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { writeFileSync } from "fs";
|
|
3
3
|
import { compile, type CompileInput } from "../core/summarize";
|
|
4
|
-
import { loadSettings,
|
|
5
|
-
import { isProactiveTriggerActive } from "./proactive-threshold";
|
|
4
|
+
import { loadSettings, type PiVccSettings } from "../core/settings";
|
|
6
5
|
import { triggerInvisibleContinue } from "../core/invisible-continue";
|
|
7
6
|
import type { PiVccCompactionDetails } from "../details";
|
|
8
7
|
|
|
@@ -279,34 +278,23 @@ export const registerBeforeCompactHook = (pi: ExtensionAPI) => {
|
|
|
279
278
|
const { preparation, branchEntries, customInstructions } = event;
|
|
280
279
|
const settings = loadSettings();
|
|
281
280
|
|
|
282
|
-
// Per-model threshold
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
//
|
|
281
|
+
// Per-model threshold guard was previously applied here, cancelling
|
|
282
|
+
// compaction when context was below the per-model threshold. This
|
|
283
|
+
// blocked manual /compact from working because session_before_compact
|
|
284
|
+
// carries no "reason" field — manual and auto compactions are
|
|
285
|
+
// indistinguishable (both have customInstructions: undefined).
|
|
286
286
|
//
|
|
287
|
-
//
|
|
288
|
-
//
|
|
287
|
+
// The per-model threshold is now served entirely by the proactive
|
|
288
|
+
// trigger (in proactive-threshold.ts), which fires on agent_end /
|
|
289
|
+
// model_select when the per-model threshold is crossed. This correctly
|
|
290
|
+
// compacts earlier than pi-core's global threshold without needing to
|
|
291
|
+
// cancel any compaction here.
|
|
292
|
+
//
|
|
293
|
+
// If pi-core's global threshold fires before the per-model threshold
|
|
294
|
+
// is crossed, the compaction proceeds — slightly premature from the
|
|
295
|
+
// per-model threshold's perspective, but this is preferable to blocking
|
|
296
|
+
// an explicit user action (/compact).
|
|
289
297
|
const isPiVcc = customInstructions === PI_VCC_COMPACT_INSTRUCTION;
|
|
290
|
-
if (!isPiVcc && !isProactiveTriggerActive()) {
|
|
291
|
-
const threshold = getModelThreshold(settings, ctx.model);
|
|
292
|
-
if (threshold) {
|
|
293
|
-
const contextWindow = ctx.model?.contextWindow ?? 0;
|
|
294
|
-
const reserve = resolveReserveTokens(threshold, contextWindow);
|
|
295
|
-
if (reserve != null && contextWindow > 0) {
|
|
296
|
-
const effectiveThreshold = contextWindow - reserve;
|
|
297
|
-
if (preparation.tokensBefore <= effectiveThreshold) {
|
|
298
|
-
try {
|
|
299
|
-
const pct = Math.round((preparation.tokensBefore / contextWindow) * 100);
|
|
300
|
-
ctx?.ui?.notify?.(
|
|
301
|
-
`pi-vcc: Skipped compaction — ${pct}% of context window used (threshold: ${formatTokens(effectiveThreshold)} tok)`,
|
|
302
|
-
"info",
|
|
303
|
-
);
|
|
304
|
-
} catch {}
|
|
305
|
-
return { cancel: true };
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
298
|
|
|
311
299
|
// Always handle explicit /pi-vcc marker.
|
|
312
300
|
// Otherwise, only handle when user opted in via settings.
|
|
@@ -19,7 +19,7 @@ afterAll(() => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
function createMockPi(model?: { id: string; provider?: string; contextWindow?: number }) {
|
|
22
|
-
|
|
22
|
+
const handlers: Record<string, ((e: any, c: any) => any)[]> = {};
|
|
23
23
|
const notifyCalls: Array<{ msg: string; level: string }> = [];
|
|
24
24
|
const ctx = {
|
|
25
25
|
hasUI: true,
|
|
@@ -30,15 +30,19 @@ function createMockPi(model?: { id: string; provider?: string; contextWindow?: n
|
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
32
|
} as any;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
const pi = {
|
|
34
|
+
on: (eventName: string, h: (e: any, c: any) => any) => {
|
|
35
|
+
if (!handlers[eventName]) handlers[eventName] = [];
|
|
36
|
+
handlers[eventName].push(h);
|
|
37
|
+
},
|
|
38
|
+
} as any;
|
|
39
|
+
const emit = (eventName: string, event: any = {}) => {
|
|
40
|
+
const hs = handlers[eventName] ?? [];
|
|
41
|
+
let result: any;
|
|
42
|
+
for (const h of hs) result = h(event, ctx);
|
|
43
|
+
return result;
|
|
41
44
|
};
|
|
45
|
+
return { pi, ctx, emit, notifyCalls };
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
function setConfig(cfg: Record<string, unknown>) {
|
|
@@ -70,7 +74,12 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
70
74
|
if (existsSync(CONFIG_PATH)) unlinkSync(CONFIG_PATH);
|
|
71
75
|
});
|
|
72
76
|
|
|
73
|
-
test("
|
|
77
|
+
test("compaction proceeds when context is below per-model threshold", () => {
|
|
78
|
+
// The threshold guard was removed because session_before_compact carries no
|
|
79
|
+
// reason field — manual /compact and auto-compaction are indistinguishable.
|
|
80
|
+
// The proactive trigger handles compacting earlier than pi-core's global
|
|
81
|
+
// threshold; this hook no longer blocks compaction that arrives before the
|
|
82
|
+
// per-model threshold.
|
|
74
83
|
setConfig({
|
|
75
84
|
debug: false,
|
|
76
85
|
overrideDefaultCompaction: true,
|
|
@@ -78,27 +87,27 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
78
87
|
"neuralwatt/GLM-5.1": { reserveTokens: 32768 },
|
|
79
88
|
},
|
|
80
89
|
});
|
|
81
|
-
const { pi,
|
|
90
|
+
const { pi, ctx, emit } = createMockPi({
|
|
82
91
|
id: "GLM-5.1",
|
|
83
92
|
provider: "neuralwatt",
|
|
84
93
|
contextWindow: 200000,
|
|
85
94
|
});
|
|
86
95
|
registerBeforeCompactHook(pi);
|
|
87
96
|
|
|
88
|
-
// 100k tokens < 200k - 32768 = 167232 → below threshold
|
|
97
|
+
// 100k tokens < 200k - 32768 = 167232 → below threshold, but proceeds
|
|
89
98
|
const entries = [
|
|
90
99
|
msg("m1", "user", "hello"),
|
|
91
100
|
msg("m2", "assistant", "hi"),
|
|
92
101
|
msg("m3", "user", "do work"),
|
|
93
102
|
msg("m4", "assistant", "done"),
|
|
94
103
|
];
|
|
95
|
-
const result =
|
|
96
|
-
|
|
97
|
-
expect(
|
|
98
|
-
expect(
|
|
104
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 100000));
|
|
105
|
+
// No longer cancelled — threshold guard removed
|
|
106
|
+
expect(result.cancel).toBeUndefined();
|
|
107
|
+
expect(result.compaction).toBeDefined();
|
|
99
108
|
});
|
|
100
109
|
|
|
101
|
-
test("
|
|
110
|
+
test("compaction proceeds when context exceeds per-model threshold", () => {
|
|
102
111
|
setConfig({
|
|
103
112
|
debug: false,
|
|
104
113
|
overrideDefaultCompaction: true,
|
|
@@ -106,7 +115,7 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
106
115
|
"neuralwatt/GLM-5.1": { reserveTokens: 32768 },
|
|
107
116
|
},
|
|
108
117
|
});
|
|
109
|
-
const { pi,
|
|
118
|
+
const { pi, ctx, emit } = createMockPi({
|
|
110
119
|
id: "GLM-5.1",
|
|
111
120
|
provider: "neuralwatt",
|
|
112
121
|
contextWindow: 200000,
|
|
@@ -120,64 +129,38 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
120
129
|
msg("m3", "user", "do work"),
|
|
121
130
|
msg("m4", "assistant", "done"),
|
|
122
131
|
];
|
|
123
|
-
const result =
|
|
124
|
-
// Not cancelled — pi-vcc proceeds with its own summary
|
|
132
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 180000));
|
|
125
133
|
expect(result.cancel).toBeUndefined();
|
|
126
134
|
expect(result.compaction).toBeDefined();
|
|
127
135
|
});
|
|
128
136
|
|
|
129
|
-
test("
|
|
130
|
-
// compactPercent: 65 → reserve = 128000 * 0.35 = 44800 → threshold = 83200
|
|
131
|
-
setConfig({
|
|
132
|
-
debug: false,
|
|
133
|
-
overrideDefaultCompaction: true,
|
|
134
|
-
globalThreshold: { compactPercent: 65 },
|
|
135
|
-
});
|
|
136
|
-
const { pi, invoke } = createMockPi({
|
|
137
|
-
id: "some-model",
|
|
138
|
-
provider: "some-provider",
|
|
139
|
-
contextWindow: 128000,
|
|
140
|
-
});
|
|
141
|
-
registerBeforeCompactHook(pi);
|
|
142
|
-
|
|
143
|
-
// 50k tokens < 83200 → below threshold
|
|
144
|
-
const entries = [
|
|
145
|
-
msg("m1", "user", "hello"),
|
|
146
|
-
msg("m2", "assistant", "hi"),
|
|
147
|
-
msg("m3", "user", "do work"),
|
|
148
|
-
msg("m4", "assistant", "done"),
|
|
149
|
-
];
|
|
150
|
-
const result = invoke(makeEvent(entries, undefined, 50000));
|
|
151
|
-
expect(result).toEqual({ cancel: true });
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test("allows compaction when context exceeds globalThreshold with compactPercent", () => {
|
|
137
|
+
test("compaction proceeds with globalThreshold compactPercent", () => {
|
|
155
138
|
// compactPercent: 65 → reserve = 128000 * 0.35 = 44800 → threshold = 83200
|
|
156
139
|
setConfig({
|
|
157
140
|
debug: false,
|
|
158
141
|
overrideDefaultCompaction: true,
|
|
159
142
|
globalThreshold: { compactPercent: 65 },
|
|
160
143
|
});
|
|
161
|
-
const { pi,
|
|
144
|
+
const { pi, ctx, emit } = createMockPi({
|
|
162
145
|
id: "some-model",
|
|
163
146
|
provider: "some-provider",
|
|
164
147
|
contextWindow: 128000,
|
|
165
148
|
});
|
|
166
149
|
registerBeforeCompactHook(pi);
|
|
167
150
|
|
|
168
|
-
//
|
|
151
|
+
// 50k tokens < 83200 → below threshold, but proceeds
|
|
169
152
|
const entries = [
|
|
170
153
|
msg("m1", "user", "hello"),
|
|
171
154
|
msg("m2", "assistant", "hi"),
|
|
172
155
|
msg("m3", "user", "do work"),
|
|
173
156
|
msg("m4", "assistant", "done"),
|
|
174
157
|
];
|
|
175
|
-
const result =
|
|
158
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 50000));
|
|
176
159
|
expect(result.cancel).toBeUndefined();
|
|
177
160
|
expect(result.compaction).toBeDefined();
|
|
178
161
|
});
|
|
179
162
|
|
|
180
|
-
test("
|
|
163
|
+
test("compaction proceeds with modelThreshold compactPercent", () => {
|
|
181
164
|
// compactPercent: 80 → reserve = 200000 * 0.20 = 40000 → threshold = 160000
|
|
182
165
|
setConfig({
|
|
183
166
|
debug: false,
|
|
@@ -186,68 +169,48 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
186
169
|
"neuralwatt/GLM-5.1": { compactPercent: 80 },
|
|
187
170
|
},
|
|
188
171
|
});
|
|
189
|
-
const { pi,
|
|
172
|
+
const { pi, ctx, emit } = createMockPi({
|
|
190
173
|
id: "GLM-5.1",
|
|
191
174
|
provider: "neuralwatt",
|
|
192
175
|
contextWindow: 200000,
|
|
193
176
|
});
|
|
194
177
|
registerBeforeCompactHook(pi);
|
|
195
178
|
|
|
196
|
-
// 100k tokens < 160000 → below threshold
|
|
179
|
+
// 100k tokens < 160000 → below threshold, but proceeds
|
|
197
180
|
const entries = [
|
|
198
181
|
msg("m1", "user", "hello"),
|
|
199
182
|
msg("m2", "assistant", "hi"),
|
|
200
183
|
msg("m3", "user", "do work"),
|
|
201
184
|
msg("m4", "assistant", "done"),
|
|
202
185
|
];
|
|
203
|
-
const result =
|
|
204
|
-
expect(result).
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
test("globalThreshold with compactPercent falls back from defaultThreshold", () => {
|
|
208
|
-
setConfig({
|
|
209
|
-
debug: false,
|
|
210
|
-
overrideDefaultCompaction: true,
|
|
211
|
-
defaultThreshold: { reserveTokens: 16384 },
|
|
212
|
-
});
|
|
213
|
-
const { pi, invoke } = createMockPi({
|
|
214
|
-
id: "some-model",
|
|
215
|
-
provider: "some-provider",
|
|
216
|
-
contextWindow: 128000,
|
|
217
|
-
});
|
|
218
|
-
registerBeforeCompactHook(pi);
|
|
219
|
-
|
|
220
|
-
// 50k tokens < 128k - 16384 = 111616 → below threshold
|
|
221
|
-
const entries = [
|
|
222
|
-
msg("m1", "user", "hello"),
|
|
223
|
-
msg("m2", "assistant", "hi"),
|
|
224
|
-
];
|
|
225
|
-
const result = invoke(makeEvent(entries, undefined, 50000));
|
|
226
|
-
expect(result).toEqual({ cancel: true });
|
|
186
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 100000));
|
|
187
|
+
expect(result.cancel).toBeUndefined();
|
|
188
|
+
expect(result.compaction).toBeDefined();
|
|
227
189
|
});
|
|
228
190
|
|
|
229
|
-
test("
|
|
191
|
+
test("compaction proceeds with defaultThreshold", () => {
|
|
230
192
|
setConfig({
|
|
231
193
|
debug: false,
|
|
232
194
|
overrideDefaultCompaction: true,
|
|
233
195
|
defaultThreshold: { reserveTokens: 16384 },
|
|
234
196
|
});
|
|
235
|
-
const { pi,
|
|
197
|
+
const { pi, ctx, emit } = createMockPi({
|
|
236
198
|
id: "some-model",
|
|
237
199
|
provider: "some-provider",
|
|
238
200
|
contextWindow: 128000,
|
|
239
201
|
});
|
|
240
202
|
registerBeforeCompactHook(pi);
|
|
241
203
|
|
|
242
|
-
// 50k tokens < 128k - 16384 = 111616 → below threshold
|
|
204
|
+
// 50k tokens < 128k - 16384 = 111616 → below threshold, but proceeds
|
|
243
205
|
const entries = [
|
|
244
206
|
msg("m1", "user", "hello"),
|
|
245
207
|
msg("m2", "assistant", "hi"),
|
|
246
208
|
msg("m3", "user", "do work"),
|
|
247
209
|
msg("m4", "assistant", "done"),
|
|
248
210
|
];
|
|
249
|
-
const result =
|
|
250
|
-
expect(result).
|
|
211
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 50000));
|
|
212
|
+
expect(result.cancel).toBeUndefined();
|
|
213
|
+
expect(result.compaction).toBeDefined();
|
|
251
214
|
});
|
|
252
215
|
|
|
253
216
|
test("does NOT cancel on /pi-vcc even when below threshold", () => {
|
|
@@ -258,51 +221,48 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
258
221
|
"neuralwatt/GLM-5.1": { reserveTokens: 32768 },
|
|
259
222
|
},
|
|
260
223
|
});
|
|
261
|
-
const { pi,
|
|
224
|
+
const { pi, ctx, emit } = createMockPi({
|
|
262
225
|
id: "GLM-5.1",
|
|
263
226
|
provider: "neuralwatt",
|
|
264
227
|
contextWindow: 200000,
|
|
265
228
|
});
|
|
266
229
|
registerBeforeCompactHook(pi);
|
|
267
230
|
|
|
268
|
-
// Below threshold, but explicit /pi-vcc command
|
|
231
|
+
// Below threshold, but explicit /pi-vcc command
|
|
269
232
|
const entries = [
|
|
270
233
|
msg("m1", "user", "hello"),
|
|
271
234
|
msg("m2", "assistant", "hi"),
|
|
272
235
|
msg("m3", "user", "do work"),
|
|
273
236
|
msg("m4", "assistant", "done"),
|
|
274
237
|
];
|
|
275
|
-
const result =
|
|
276
|
-
// Not cancelled — explicit /pi-vcc bypasses threshold check
|
|
238
|
+
const result = emit("session_before_compact", makeEvent(entries, PI_VCC_COMPACT_INSTRUCTION, 100000));
|
|
277
239
|
expect(result.cancel).toBeUndefined();
|
|
278
240
|
expect(result.compaction).toBeDefined();
|
|
279
241
|
});
|
|
280
242
|
|
|
281
|
-
test("
|
|
243
|
+
test("compaction proceeds when no modelThresholds configured", () => {
|
|
282
244
|
setConfig({
|
|
283
245
|
debug: false,
|
|
284
246
|
overrideDefaultCompaction: true,
|
|
285
247
|
});
|
|
286
|
-
const { pi,
|
|
248
|
+
const { pi, ctx, emit } = createMockPi({
|
|
287
249
|
id: "GLM-5.1",
|
|
288
250
|
provider: "neuralwatt",
|
|
289
251
|
contextWindow: 200000,
|
|
290
252
|
});
|
|
291
253
|
registerBeforeCompactHook(pi);
|
|
292
254
|
|
|
293
|
-
// No modelThresholds → no threshold override → fall through to normal flow
|
|
294
255
|
const entries = [
|
|
295
256
|
msg("m1", "user", "hello"),
|
|
296
257
|
msg("m2", "assistant", "hi"),
|
|
297
258
|
msg("m3", "user", "do work"),
|
|
298
259
|
msg("m4", "assistant", "done"),
|
|
299
260
|
];
|
|
300
|
-
const result =
|
|
301
|
-
// Not cancelled by threshold check (may be cancelled by other logic)
|
|
261
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 100000));
|
|
302
262
|
expect(result.cancel === true).toBe(false);
|
|
303
263
|
});
|
|
304
264
|
|
|
305
|
-
test("
|
|
265
|
+
test("compaction proceeds when model is undefined", () => {
|
|
306
266
|
setConfig({
|
|
307
267
|
debug: false,
|
|
308
268
|
overrideDefaultCompaction: true,
|
|
@@ -310,8 +270,7 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
310
270
|
"GLM-5.1": { reserveTokens: 32768 },
|
|
311
271
|
},
|
|
312
272
|
});
|
|
313
|
-
|
|
314
|
-
const { pi, invoke } = createMockPi(undefined);
|
|
273
|
+
const { pi, ctx, emit } = createMockPi(undefined);
|
|
315
274
|
registerBeforeCompactHook(pi);
|
|
316
275
|
|
|
317
276
|
const entries = [
|
|
@@ -320,12 +279,11 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
320
279
|
msg("m3", "user", "do work"),
|
|
321
280
|
msg("m4", "assistant", "done"),
|
|
322
281
|
];
|
|
323
|
-
const result =
|
|
324
|
-
// No model → can't check threshold → fall through to normal flow
|
|
282
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 100000));
|
|
325
283
|
expect(result.cancel === true).toBe(false);
|
|
326
284
|
});
|
|
327
285
|
|
|
328
|
-
test("
|
|
286
|
+
test("compaction proceeds with overrideDefaultCompaction false", () => {
|
|
329
287
|
setConfig({
|
|
330
288
|
debug: false,
|
|
331
289
|
overrideDefaultCompaction: false,
|
|
@@ -333,45 +291,21 @@ describe("session_before_compact: per-model threshold", () => {
|
|
|
333
291
|
"neuralwatt/GLM-5.1": { reserveTokens: 32768 },
|
|
334
292
|
},
|
|
335
293
|
});
|
|
336
|
-
const { pi,
|
|
337
|
-
id: "GLM-5.1",
|
|
338
|
-
provider: "neuralwatt",
|
|
339
|
-
contextWindow: 200000,
|
|
340
|
-
});
|
|
341
|
-
registerBeforeCompactHook(pi);
|
|
342
|
-
|
|
343
|
-
// Below threshold → cancel, even though pi-vcc wouldn't handle the summary
|
|
344
|
-
const entries = [
|
|
345
|
-
msg("m1", "user", "hello"),
|
|
346
|
-
msg("m2", "assistant", "hi"),
|
|
347
|
-
];
|
|
348
|
-
const result = invoke(makeEvent(entries, undefined, 100000));
|
|
349
|
-
expect(result).toEqual({ cancel: true });
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
test("modelId-only key matches when provider/modelId does not", () => {
|
|
353
|
-
setConfig({
|
|
354
|
-
debug: false,
|
|
355
|
-
overrideDefaultCompaction: true,
|
|
356
|
-
modelThresholds: {
|
|
357
|
-
"GLM-5.1": { reserveTokens: 32768 },
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
const { pi, invoke } = createMockPi({
|
|
294
|
+
const { pi, ctx, emit } = createMockPi({
|
|
361
295
|
id: "GLM-5.1",
|
|
362
296
|
provider: "neuralwatt",
|
|
363
297
|
contextWindow: 200000,
|
|
364
298
|
});
|
|
365
299
|
registerBeforeCompactHook(pi);
|
|
366
300
|
|
|
367
|
-
//
|
|
301
|
+
// Below threshold, overrideDefaultCompaction: false → pi-vcc doesn't
|
|
302
|
+
// handle the summary, but also doesn't cancel (threshold guard removed)
|
|
368
303
|
const entries = [
|
|
369
304
|
msg("m1", "user", "hello"),
|
|
370
305
|
msg("m2", "assistant", "hi"),
|
|
371
|
-
msg("m3", "user", "do work"),
|
|
372
|
-
msg("m4", "assistant", "done"),
|
|
373
306
|
];
|
|
374
|
-
const result =
|
|
375
|
-
|
|
307
|
+
const result = emit("session_before_compact", makeEvent(entries, undefined, 100000));
|
|
308
|
+
// Not cancelled — returns undefined (pi-vcc doesn't handle it)
|
|
309
|
+
expect(result).toBeUndefined();
|
|
376
310
|
});
|
|
377
311
|
});
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* - When proactive trigger calls ctx.compact(), session_before_compact
|
|
6
6
|
* must NOT cancel the compaction even if tokensBefore differs from
|
|
7
7
|
* getContextUsage().
|
|
8
|
-
* -
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* - The per-model threshold guard was removed from session_before_compact
|
|
9
|
+
* because the event carries no "reason" field — manual /compact and
|
|
10
|
+
* auto-compaction are indistinguishable. The proactive trigger handles
|
|
11
|
+
* the "compact earlier than pi-core" direction.
|
|
11
12
|
*/
|
|
12
13
|
import { describe, test, expect, afterEach, beforeAll, afterAll } from "bun:test";
|
|
13
14
|
import { existsSync, unlinkSync, writeFileSync, mkdtempSync, rmSync } from "fs";
|
|
@@ -100,11 +101,6 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
100
101
|
});
|
|
101
102
|
|
|
102
103
|
test("proactive trigger then before-compact: does NOT cancel when proactiveTriggerActive", () => {
|
|
103
|
-
// Scenario: agent_end fires, getContextUsage says 110k tokens,
|
|
104
|
-
// per-model threshold is 95232 (128k - 32768). Proactive triggers compact.
|
|
105
|
-
// Then session_before_compact fires with tokensBefore = 94000
|
|
106
|
-
// (slightly different due to estimation).
|
|
107
|
-
// Without the proactiveTriggerActive guard, this would be cancelled.
|
|
108
104
|
setConfig({
|
|
109
105
|
debug: false,
|
|
110
106
|
overrideDefaultCompaction: true,
|
|
@@ -119,13 +115,9 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
119
115
|
registerProactiveThresholdHook(pi);
|
|
120
116
|
registerBeforeCompactHook(pi);
|
|
121
117
|
|
|
122
|
-
// Step 1: agent_end fires → proactive trigger calls ctx.compact()
|
|
123
118
|
emit("agent_end", { type: "agent_end", messages: [] });
|
|
124
119
|
expect(compactCalls).toHaveLength(1);
|
|
125
120
|
|
|
126
|
-
// Step 2: session_before_compact fires with tokensBefore = 94000
|
|
127
|
-
// (below the 95232 threshold — but we should NOT cancel because
|
|
128
|
-
// we ourselves triggered this compaction)
|
|
129
121
|
const entries = [
|
|
130
122
|
msg("m1", "user", "hello"),
|
|
131
123
|
msg("m2", "assistant", "hi"),
|
|
@@ -136,14 +128,14 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
136
128
|
|
|
137
129
|
// Should NOT cancel — proactiveTriggerActive is true
|
|
138
130
|
expect(result?.cancel).toBeUndefined();
|
|
139
|
-
// Should proceed with compaction (pi-vcc's own summary)
|
|
140
131
|
expect(result?.compaction).toBeDefined();
|
|
141
132
|
});
|
|
142
133
|
|
|
143
|
-
test("global trigger + before-compact:
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
134
|
+
test("global trigger + before-compact: compaction proceeds (threshold guard removed)", () => {
|
|
135
|
+
// Previously: pi-core's global threshold triggers compaction below the
|
|
136
|
+
// per-model threshold → cancelled. Now: the threshold guard is removed
|
|
137
|
+
// because manual /compact can't be distinguished from auto-compaction,
|
|
138
|
+
// so compaction proceeds.
|
|
147
139
|
setConfig({
|
|
148
140
|
debug: false,
|
|
149
141
|
overrideDefaultCompaction: true,
|
|
@@ -151,24 +143,23 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
151
143
|
"neuralwatt/GLM-5.1": { reserveTokens: 32768 },
|
|
152
144
|
},
|
|
153
145
|
});
|
|
154
|
-
const { pi, ctx, emit
|
|
146
|
+
const { pi, ctx, emit } = createMockPi(
|
|
155
147
|
{ id: "GLM-5.1", provider: "neuralwatt", contextWindow: 128000 },
|
|
156
|
-
// getContextUsage says 80k — well below per-model threshold
|
|
157
148
|
{ tokens: 80000, contextWindow: 128000, percent: 63 },
|
|
158
149
|
);
|
|
159
150
|
registerProactiveThresholdHook(pi);
|
|
160
151
|
registerBeforeCompactHook(pi);
|
|
161
152
|
|
|
162
|
-
// No agent_end fired (global threshold triggered this)
|
|
163
153
|
const entries = [
|
|
164
154
|
msg("m1", "user", "hello"),
|
|
165
155
|
msg("m2", "assistant", "hi"),
|
|
166
156
|
msg("m3", "user", "do work"),
|
|
167
157
|
msg("m4", "assistant", "done"),
|
|
168
158
|
];
|
|
169
|
-
// tokensBefore = 90k < 95232 — should cancel
|
|
170
159
|
const result = emit("session_before_compact", makeBeforeCompactEvent(entries, undefined, 90000));
|
|
171
|
-
|
|
160
|
+
// No longer cancelled — threshold guard removed
|
|
161
|
+
expect(result?.cancel).toBeUndefined();
|
|
162
|
+
expect(result?.compaction).toBeDefined();
|
|
172
163
|
});
|
|
173
164
|
|
|
174
165
|
test("proactiveTriggerActive is cleared after session_compact", () => {
|
|
@@ -186,16 +177,13 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
186
177
|
registerProactiveThresholdHook(pi);
|
|
187
178
|
registerBeforeCompactHook(pi);
|
|
188
179
|
|
|
189
|
-
// Step 1: proactive trigger
|
|
190
180
|
emit("agent_end", { type: "agent_end", messages: [] });
|
|
191
181
|
expect(compactCalls).toHaveLength(1);
|
|
192
182
|
|
|
193
|
-
// Step 2: compaction completes
|
|
194
183
|
emit("session_compact", { type: "session_compact", compactionEntry: {} });
|
|
195
184
|
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
// because proactiveTriggerActive was cleared by session_compact
|
|
185
|
+
// After session_compact, proactiveTriggerActive is cleared.
|
|
186
|
+
// But the threshold guard is also removed, so compaction proceeds.
|
|
199
187
|
const entries = [
|
|
200
188
|
msg("m1", "user", "hello"),
|
|
201
189
|
msg("m2", "assistant", "hi"),
|
|
@@ -203,10 +191,11 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
203
191
|
msg("m4", "assistant", "done"),
|
|
204
192
|
];
|
|
205
193
|
const result = emit("session_before_compact", makeBeforeCompactEvent(entries, undefined, 90000));
|
|
206
|
-
expect(result).
|
|
194
|
+
expect(result?.cancel).toBeUndefined();
|
|
195
|
+
expect(result?.compaction).toBeDefined();
|
|
207
196
|
});
|
|
208
197
|
|
|
209
|
-
test("explicit /pi-vcc
|
|
198
|
+
test("explicit /pi-vcc proceeds regardless of context level", () => {
|
|
210
199
|
setConfig({
|
|
211
200
|
debug: false,
|
|
212
201
|
overrideDefaultCompaction: true,
|
|
@@ -216,19 +205,18 @@ describe("integration: proactive trigger + before-compact", () => {
|
|
|
216
205
|
});
|
|
217
206
|
const { pi, ctx, emit } = createMockPi(
|
|
218
207
|
{ id: "GLM-5.1", provider: "neuralwatt", contextWindow: 128000 },
|
|
219
|
-
{ tokens:
|
|
208
|
+
{ tokens: 5000, contextWindow: 128000, percent: 4 },
|
|
220
209
|
);
|
|
221
210
|
registerProactiveThresholdHook(pi);
|
|
222
211
|
registerBeforeCompactHook(pi);
|
|
223
212
|
|
|
224
|
-
// Direct /pi-vcc with tokens well below threshold — should still proceed
|
|
225
213
|
const entries = [
|
|
226
214
|
msg("m1", "user", "hello"),
|
|
227
215
|
msg("m2", "assistant", "hi"),
|
|
228
216
|
msg("m3", "user", "do work"),
|
|
229
217
|
msg("m4", "assistant", "done"),
|
|
230
218
|
];
|
|
231
|
-
const result = emit("session_before_compact", makeBeforeCompactEvent(entries, "__pi_vcc__",
|
|
219
|
+
const result = emit("session_before_compact", makeBeforeCompactEvent(entries, "__pi_vcc__", 5000));
|
|
232
220
|
expect(result?.cancel).toBeUndefined();
|
|
233
221
|
expect(result?.compaction).toBeDefined();
|
|
234
222
|
});
|
|
@@ -241,10 +229,6 @@ describe("integration: proactive trigger + before-compact with overrideDefaultCo
|
|
|
241
229
|
});
|
|
242
230
|
|
|
243
231
|
test("proactive trigger fires, before-compact doesn't cancel, then pi-core handles summary", () => {
|
|
244
|
-
// When overrideDefaultCompaction: false, pi-vcc doesn't handle the summary
|
|
245
|
-
// for non-/pi-vcc compactions. But the threshold guard and proactive trigger
|
|
246
|
-
// should still work — the threshold guard controls WHEN compaction triggers,
|
|
247
|
-
// and pi-core handles the actual summary.
|
|
248
232
|
setConfig({
|
|
249
233
|
debug: false,
|
|
250
234
|
overrideDefaultCompaction: false,
|
|
@@ -259,14 +243,9 @@ describe("integration: proactive trigger + before-compact with overrideDefaultCo
|
|
|
259
243
|
registerProactiveThresholdHook(pi);
|
|
260
244
|
registerBeforeCompactHook(pi);
|
|
261
245
|
|
|
262
|
-
// agent_end fires → proactive trigger
|
|
263
246
|
emit("agent_end", { type: "agent_end", messages: [] });
|
|
264
247
|
expect(compactCalls).toHaveLength(1);
|
|
265
248
|
|
|
266
|
-
// session_before_compact fires: threshold is crossed (tokensBefore = 110k
|
|
267
|
-
// > 95232), and our guard allows it because proactiveTriggerActive.
|
|
268
|
-
// Then overrideDefaultCompaction: false means pi-vcc returns undefined,
|
|
269
|
-
// letting pi-core handle the summary.
|
|
270
249
|
const entries = [
|
|
271
250
|
msg("m1", "user", "hello"),
|
|
272
251
|
msg("m2", "assistant", "hi"),
|
|
@@ -275,11 +254,10 @@ describe("integration: proactive trigger + before-compact with overrideDefaultCo
|
|
|
275
254
|
];
|
|
276
255
|
const result = emit("session_before_compact", makeBeforeCompactEvent(entries, undefined, 110000));
|
|
277
256
|
// pi-vcc doesn't handle it (overrideDefaultCompaction: false) → returns undefined
|
|
278
|
-
// pi-core will handle the summary
|
|
279
257
|
expect(result).toBeUndefined();
|
|
280
258
|
});
|
|
281
259
|
|
|
282
|
-
test("
|
|
260
|
+
test("compaction proceeds even with overrideDefaultCompaction: false (threshold guard removed)", () => {
|
|
283
261
|
setConfig({
|
|
284
262
|
debug: false,
|
|
285
263
|
overrideDefaultCompaction: false,
|
|
@@ -294,15 +272,16 @@ describe("integration: proactive trigger + before-compact with overrideDefaultCo
|
|
|
294
272
|
registerProactiveThresholdHook(pi);
|
|
295
273
|
registerBeforeCompactHook(pi);
|
|
296
274
|
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
// says the model can handle more → cancel
|
|
275
|
+
// Previously this would cancel (threshold guard). Now: compaction
|
|
276
|
+
// proceeds (threshold guard removed).
|
|
300
277
|
const entries = [
|
|
301
278
|
msg("m1", "user", "hello"),
|
|
302
279
|
msg("m2", "assistant", "hi"),
|
|
303
280
|
];
|
|
304
281
|
const result = emit("session_before_compact", makeBeforeCompactEvent(entries, undefined, 80000));
|
|
305
|
-
|
|
282
|
+
// No longer cancelled — returns undefined (pi-vcc doesn't handle it,
|
|
283
|
+
// but doesn't block it either)
|
|
284
|
+
expect(result).toBeUndefined();
|
|
306
285
|
});
|
|
307
286
|
});
|
|
308
287
|
|
|
@@ -326,11 +305,9 @@ describe("integration: cooldown prevents double compaction", () => {
|
|
|
326
305
|
);
|
|
327
306
|
registerProactiveThresholdHook(pi);
|
|
328
307
|
|
|
329
|
-
// agent_end triggers compact and sets cooldown
|
|
330
308
|
emit("agent_end", { type: "agent_end", messages: [] });
|
|
331
309
|
expect(compactCalls).toHaveLength(1);
|
|
332
310
|
|
|
333
|
-
// model_select fires on same turn — blocked by cooldown
|
|
334
311
|
emit("model_select", { type: "model_select" });
|
|
335
312
|
expect(compactCalls).toHaveLength(1);
|
|
336
313
|
});
|
|
@@ -352,7 +329,6 @@ describe("integration: cooldown prevents double compaction", () => {
|
|
|
352
329
|
emit("agent_end", { type: "agent_end", messages: [] });
|
|
353
330
|
expect(compactCalls).toHaveLength(1);
|
|
354
331
|
|
|
355
|
-
// No session_compact between — cooldown still active
|
|
356
332
|
emit("agent_end", { type: "agent_end", messages: [] });
|
|
357
333
|
expect(compactCalls).toHaveLength(1);
|
|
358
334
|
});
|