pi-mega-compact 0.4.12 β 0.4.13
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.
|
@@ -255,25 +255,43 @@ export default function (pi) {
|
|
|
255
255
|
const usedStr = `${C.cyan}${fmt(st.totalTokenEstimate)} sess${C.reset} / ${C.blue}${fmt(repo.totalTokenEstimate)} repo${C.reset}`;
|
|
256
256
|
const agentStr = activeAgents > 0 ? ` β π€ ${activeAgents} agent${activeAgents === 1 ? "" : "s"}` : "";
|
|
257
257
|
const turnStr = currentTurn > 0 ? ` β turn ${currentTurn}` : "";
|
|
258
|
+
// Phase 3 β pulsing status glyph while a compaction is in flight.
|
|
259
|
+
const pulse = pulsing ? `${C.cyan}${PULSE[Math.floor(Date.now() / 250) % PULSE.length]}${C.reset} ` : "";
|
|
258
260
|
const lines = [
|
|
259
|
-
` ${C.amber}β‘ ${config.tier}${C.reset} β ${tokStr}/${maxStr} tokens (${C.bold}${pctStr}${C.reset}) β ${st.checkpointCount} chkpt${
|
|
261
|
+
` ${C.amber}β‘ ${config.tier}${C.reset} β ${tokStr}/${maxStr} tokens (${C.bold}${pctStr}${C.reset}) β ${st.checkpointCount} chkpt${agentStr}${turnStr}`,
|
|
260
262
|
` ${triggerLabel} β ${C.magenta}dedup: ${dedupStr}${C.reset} β ${C.gray}used:${C.reset} ${usedStr} β ${C.gray}saved:${C.reset} ${savedStr}`,
|
|
261
263
|
];
|
|
264
|
+
// Phase 3 β compact progress bar: session tokens saved toward the rolling goal.
|
|
265
|
+
if (rt.tokensSaved > 0) {
|
|
266
|
+
const goal = Math.max(savedGoal, 1);
|
|
267
|
+
const pct = Math.min(100, Math.round((rt.tokensSaved / goal) * 100));
|
|
268
|
+
const filled = Math.round((pct / 100) * 10);
|
|
269
|
+
const bar = "β".repeat(filled) + "β".repeat(10 - filled);
|
|
270
|
+
lines.push(` ${C.green}saved ${fmt(rt.tokensSaved)} ${bar}${C.reset} ${pct}% of ${fmt(goal)}`);
|
|
271
|
+
}
|
|
262
272
|
// Live "now processing" line β teal while fresh (β€4s), then the last-seen
|
|
263
273
|
// action keeps the widget lively. Cleared on session reset.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const fresh = Date.now() - lastActivityAt < 4000;
|
|
268
|
-
if (fresh)
|
|
269
|
-
lines.push(` ${tierTrace}`);
|
|
270
|
-
else if (currentActivity)
|
|
271
|
-
lines.push(` ${C.dim}${currentActivity}${C.reset}`);
|
|
274
|
+
const fresh = Date.now() - lastActivityAt < 4000;
|
|
275
|
+
if (tierTrace && fresh) {
|
|
276
|
+
lines.push(` ${pulse}${tierTrace}`);
|
|
272
277
|
}
|
|
273
278
|
else if (currentActivity) {
|
|
274
|
-
const fresh = Date.now() - lastActivityAt < 4000;
|
|
275
279
|
lines.push(` ${fresh ? C.teal : C.dim}${currentActivity}${C.reset}`);
|
|
276
280
|
}
|
|
281
|
+
else if (pulsing) {
|
|
282
|
+
lines.push(` ${pulse}${C.teal}compactingβ¦${C.reset}`);
|
|
283
|
+
}
|
|
284
|
+
// Phase 3 β explain-why line (fresh only).
|
|
285
|
+
if (lastWhy && fresh)
|
|
286
|
+
lines.push(` ${C.gray}${lastWhy}${C.reset}`);
|
|
287
|
+
// Phase 3 β recall/activity ticker (most-recent first), fresh only.
|
|
288
|
+
if (fresh) {
|
|
289
|
+
for (let i = ticker.length - 1; i >= 0; i--) {
|
|
290
|
+
if (lines.length >= 10)
|
|
291
|
+
break; // MAX_WIDGET_LINES guard
|
|
292
|
+
lines.push(` ${i === ticker.length - 1 ? "" : C.dim}${ticker[i].text}${C.reset}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
277
295
|
ctx.ui.setWidget(WIDGET_KEY, lines, { placement: "aboveEditor" });
|
|
278
296
|
}
|
|
279
297
|
}
|
|
@@ -305,6 +323,24 @@ export default function (pi) {
|
|
|
305
323
|
// Built from the store's sync onTier callback during a compaction so the user
|
|
306
324
|
// watches each tier evaluate in real time. Cleared once the outcome settles.
|
|
307
325
|
let tierTrace;
|
|
326
|
+
const ticker = [];
|
|
327
|
+
const TICKER_MAX = 5;
|
|
328
|
+
function pushTicker(text) {
|
|
329
|
+
ticker.push({ text, at: Date.now() });
|
|
330
|
+
while (ticker.length > TICKER_MAX)
|
|
331
|
+
ticker.shift();
|
|
332
|
+
lastActivityAt = Date.now();
|
|
333
|
+
}
|
|
334
|
+
// Pulsing status: set true while a compaction is in flight, cleared on result.
|
|
335
|
+
let pulsing = false;
|
|
336
|
+
// Rolling "saved" goal for the progress bar β grows as we save more, so the
|
|
337
|
+
// bar always has a meaningful denominator (never sits at 100% forever).
|
|
338
|
+
let savedGoal = 50_000;
|
|
339
|
+
// Last explain-why line (dedup reason / anchor-kept / superseded), surfaced
|
|
340
|
+
// while fresh.
|
|
341
|
+
let lastWhy = undefined;
|
|
342
|
+
// Cycling glyph phases for the pulsing status.
|
|
343
|
+
const PULSE = ["β", "β", "β", "β"];
|
|
308
344
|
// ANSI palette for the toolbar. The pi TUI's Text component preserves ANSI
|
|
309
345
|
// escape codes (see wrapTextWithAnsi), so raw escapes render as colors. No
|
|
310
346
|
// chalk dependency needed β these are just strings.
|
|
@@ -344,6 +380,10 @@ export default function (pi) {
|
|
|
344
380
|
currentActivity = undefined;
|
|
345
381
|
lastActivityAt = 0;
|
|
346
382
|
tierTrace = undefined;
|
|
383
|
+
ticker.length = 0;
|
|
384
|
+
pulsing = false;
|
|
385
|
+
savedGoal = 50_000;
|
|
386
|
+
lastWhy = undefined;
|
|
347
387
|
}
|
|
348
388
|
/** Build the sync onTier callback that paints the live per-tier trace. */
|
|
349
389
|
function makeTierCallback(ctx) {
|
|
@@ -382,6 +422,7 @@ export default function (pi) {
|
|
|
382
422
|
const keepFrom = opts.keepFrom ?? Math.max(0, view.length - config.preserveRecent);
|
|
383
423
|
if (keepFrom <= 0)
|
|
384
424
|
return { skipped: true };
|
|
425
|
+
pulsing = true; // animate the status line while the (sync) pipeline runs
|
|
385
426
|
const result = compactSession({
|
|
386
427
|
sessionId: sid,
|
|
387
428
|
messages: view,
|
|
@@ -390,6 +431,7 @@ export default function (pi) {
|
|
|
390
431
|
timestamp: Date.now(),
|
|
391
432
|
onTier: makeTierCallback(ctx),
|
|
392
433
|
}, store);
|
|
434
|
+
pulsing = false;
|
|
393
435
|
if (result.skipped)
|
|
394
436
|
return { skipped: true };
|
|
395
437
|
if (!result.deduped) {
|
|
@@ -410,6 +452,10 @@ export default function (pi) {
|
|
|
410
452
|
rt.tokensSaved += saved;
|
|
411
453
|
if (result.deduped)
|
|
412
454
|
rt.dedupSkips++;
|
|
455
|
+
// Grow the rolling "saved" goal so the progress bar always has a fresh
|
|
456
|
+
// denominator (we don't want it pinned at 100% once we pass an old target).
|
|
457
|
+
if (rt.tokensSaved > savedGoal)
|
|
458
|
+
savedGoal = Math.ceil((rt.tokensSaved * 1.25) / 10_000) * 10_000;
|
|
413
459
|
// Live toolbar "now processing" line: what file/region just got compacted or
|
|
414
460
|
// deduped. Reset to the last-seen action after a few seconds (see snapshot).
|
|
415
461
|
const files = result.filesModified ?? [];
|
|
@@ -420,6 +466,16 @@ export default function (pi) {
|
|
|
420
466
|
? `β» deduped ${fileLabel}`
|
|
421
467
|
: `π compacted ${result.checkpointId} Β· ${fileLabel}`;
|
|
422
468
|
lastActivityAt = Date.now();
|
|
469
|
+
// Explain-why line: surfaced while fresh. Pulls the dedup reason (which for
|
|
470
|
+
// L2 includes the cosine sim) so the user sees WHY a region was kept/dropped.
|
|
471
|
+
lastWhy = result.deduped
|
|
472
|
+
? `why: deduped@${result.dedupReason ?? "tier"}`
|
|
473
|
+
: `why: compacted β ${result.checkpointId}`;
|
|
474
|
+
// Recall/activity ticker: record this event in the ring buffer.
|
|
475
|
+
const savedK = (saved / 1000).toFixed(1);
|
|
476
|
+
pushTicker(result.deduped
|
|
477
|
+
? `${C.green}β»${C.reset} deduped ${fileLabel} Β· ${savedK}k saved`
|
|
478
|
+
: `${C.cyan}π${C.reset} ${result.checkpointId} Β· +${savedK}k Β· ${fileLabel}`);
|
|
423
479
|
// The per-tier trace has settled into the final outcome β fold it back into
|
|
424
480
|
// the activity line and stop showing the live trace.
|
|
425
481
|
tierTrace = undefined;
|
|
@@ -472,6 +528,14 @@ export default function (pi) {
|
|
|
472
528
|
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
473
529
|
const result = recallAndInline({ sessionId: sid, query, limit: config.autoInlineK, source, skipInjected: true }, store);
|
|
474
530
|
dashboard.event("recall", { source, query: query.slice(0, 120), injected: result.toInject.length, empty: result.empty });
|
|
531
|
+
if (!result.empty && result.toInject.length > 0) {
|
|
532
|
+
const top = result.toInject[0];
|
|
533
|
+
const scorePct = Math.round((top.score ?? 0) * 100);
|
|
534
|
+
const files = top.checkpoint.filesModified ?? [];
|
|
535
|
+
const label = files.length ? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ") : top.checkpoint.checkpointId;
|
|
536
|
+
pushTicker(`${C.amber}β©${C.reset} recalled ${top.checkpoint.checkpointId} Β· ${scorePct}% Β· ${label}`);
|
|
537
|
+
lastWhy = `why: recalled@${scorePct}% (${result.toInject.length} chkpt)`;
|
|
538
|
+
}
|
|
475
539
|
return result;
|
|
476
540
|
}
|
|
477
541
|
// ---- Session lifecycle (state reset points) -------------------------------
|
|
@@ -358,21 +358,38 @@ export default function (pi: ExtensionAPI) {
|
|
|
358
358
|
const usedStr = `${C.cyan}${fmt(st.totalTokenEstimate)} sess${C.reset} / ${C.blue}${fmt(repo.totalTokenEstimate)} repo${C.reset}`;
|
|
359
359
|
const agentStr = activeAgents > 0 ? ` β π€ ${activeAgents} agent${activeAgents === 1 ? "" : "s"}` : "";
|
|
360
360
|
const turnStr = currentTurn > 0 ? ` β turn ${currentTurn}` : "";
|
|
361
|
+
// Phase 3 β pulsing status glyph while a compaction is in flight.
|
|
362
|
+
const pulse = pulsing ? `${C.cyan}${PULSE[Math.floor(Date.now() / 250) % PULSE.length]}${C.reset} ` : "";
|
|
361
363
|
const lines = [
|
|
362
|
-
` ${C.amber}β‘ ${config.tier}${C.reset} β ${tokStr}/${maxStr} tokens (${C.bold}${pctStr}${C.reset}) β ${st.checkpointCount} chkpt${
|
|
364
|
+
` ${C.amber}β‘ ${config.tier}${C.reset} β ${tokStr}/${maxStr} tokens (${C.bold}${pctStr}${C.reset}) β ${st.checkpointCount} chkpt${agentStr}${turnStr}`,
|
|
363
365
|
` ${triggerLabel} β ${C.magenta}dedup: ${dedupStr}${C.reset} β ${C.gray}used:${C.reset} ${usedStr} β ${C.gray}saved:${C.reset} ${savedStr}`,
|
|
364
366
|
];
|
|
367
|
+
// Phase 3 β compact progress bar: session tokens saved toward the rolling goal.
|
|
368
|
+
if (rt.tokensSaved > 0) {
|
|
369
|
+
const goal = Math.max(savedGoal, 1);
|
|
370
|
+
const pct = Math.min(100, Math.round((rt.tokensSaved / goal) * 100));
|
|
371
|
+
const filled = Math.round((pct / 100) * 10);
|
|
372
|
+
const bar = "β".repeat(filled) + "β".repeat(10 - filled);
|
|
373
|
+
lines.push(` ${C.green}saved ${fmt(rt.tokensSaved)} ${bar}${C.reset} ${pct}% of ${fmt(goal)}`);
|
|
374
|
+
}
|
|
365
375
|
// Live "now processing" line β teal while fresh (β€4s), then the last-seen
|
|
366
376
|
// action keeps the widget lively. Cleared on session reset.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const fresh = Date.now() - lastActivityAt < 4000;
|
|
371
|
-
if (fresh) lines.push(` ${tierTrace}`);
|
|
372
|
-
else if (currentActivity) lines.push(` ${C.dim}${currentActivity}${C.reset}`);
|
|
377
|
+
const fresh = Date.now() - lastActivityAt < 4000;
|
|
378
|
+
if (tierTrace && fresh) {
|
|
379
|
+
lines.push(` ${pulse}${tierTrace}`);
|
|
373
380
|
} else if (currentActivity) {
|
|
374
|
-
const fresh = Date.now() - lastActivityAt < 4000;
|
|
375
381
|
lines.push(` ${fresh ? C.teal : C.dim}${currentActivity}${C.reset}`);
|
|
382
|
+
} else if (pulsing) {
|
|
383
|
+
lines.push(` ${pulse}${C.teal}compactingβ¦${C.reset}`);
|
|
384
|
+
}
|
|
385
|
+
// Phase 3 β explain-why line (fresh only).
|
|
386
|
+
if (lastWhy && fresh) lines.push(` ${C.gray}${lastWhy}${C.reset}`);
|
|
387
|
+
// Phase 3 β recall/activity ticker (most-recent first), fresh only.
|
|
388
|
+
if (fresh) {
|
|
389
|
+
for (let i = ticker.length - 1; i >= 0; i--) {
|
|
390
|
+
if (lines.length >= 10) break; // MAX_WIDGET_LINES guard
|
|
391
|
+
lines.push(` ${i === ticker.length - 1 ? "" : C.dim}${ticker[i].text}${C.reset}`);
|
|
392
|
+
}
|
|
376
393
|
}
|
|
377
394
|
ctx.ui.setWidget(WIDGET_KEY, lines, { placement: "aboveEditor" });
|
|
378
395
|
}
|
|
@@ -406,6 +423,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
406
423
|
// Built from the store's sync onTier callback during a compaction so the user
|
|
407
424
|
// watches each tier evaluate in real time. Cleared once the outcome settles.
|
|
408
425
|
let tierTrace: string | undefined;
|
|
426
|
+
// Phase 3 β standout toolbar state.
|
|
427
|
+
// Recall/activity ticker: a small ring buffer (β€5) of recent compact/recall
|
|
428
|
+
// events so the widget shows a live history instead of a single last action.
|
|
429
|
+
interface TickerEntry { text: string; at: number; }
|
|
430
|
+
const ticker: TickerEntry[] = [];
|
|
431
|
+
const TICKER_MAX = 5;
|
|
432
|
+
function pushTicker(text: string): void {
|
|
433
|
+
ticker.push({ text, at: Date.now() });
|
|
434
|
+
while (ticker.length > TICKER_MAX) ticker.shift();
|
|
435
|
+
lastActivityAt = Date.now();
|
|
436
|
+
}
|
|
437
|
+
// Pulsing status: set true while a compaction is in flight, cleared on result.
|
|
438
|
+
let pulsing = false;
|
|
439
|
+
// Rolling "saved" goal for the progress bar β grows as we save more, so the
|
|
440
|
+
// bar always has a meaningful denominator (never sits at 100% forever).
|
|
441
|
+
let savedGoal = 50_000;
|
|
442
|
+
// Last explain-why line (dedup reason / anchor-kept / superseded), surfaced
|
|
443
|
+
// while fresh.
|
|
444
|
+
let lastWhy: string | undefined = undefined;
|
|
445
|
+
// Cycling glyph phases for the pulsing status.
|
|
446
|
+
const PULSE = ["β", "β", "β", "β"];
|
|
409
447
|
// ANSI palette for the toolbar. The pi TUI's Text component preserves ANSI
|
|
410
448
|
// escape codes (see wrapTextWithAnsi), so raw escapes render as colors. No
|
|
411
449
|
// chalk dependency needed β these are just strings.
|
|
@@ -446,6 +484,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
446
484
|
currentActivity = undefined;
|
|
447
485
|
lastActivityAt = 0;
|
|
448
486
|
tierTrace = undefined;
|
|
487
|
+
ticker.length = 0;
|
|
488
|
+
pulsing = false;
|
|
489
|
+
savedGoal = 50_000;
|
|
490
|
+
lastWhy = undefined;
|
|
449
491
|
}
|
|
450
492
|
|
|
451
493
|
/** Build the sync onTier callback that paints the live per-tier trace. */
|
|
@@ -488,6 +530,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
488
530
|
const keepFrom = opts.keepFrom ?? Math.max(0, view.length - config.preserveRecent);
|
|
489
531
|
if (keepFrom <= 0) return { skipped: true as const };
|
|
490
532
|
|
|
533
|
+
pulsing = true; // animate the status line while the (sync) pipeline runs
|
|
491
534
|
const result = compactSession(
|
|
492
535
|
{
|
|
493
536
|
sessionId: sid,
|
|
@@ -499,6 +542,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
499
542
|
},
|
|
500
543
|
store,
|
|
501
544
|
);
|
|
545
|
+
pulsing = false;
|
|
502
546
|
|
|
503
547
|
if (result.skipped) return { skipped: true as const };
|
|
504
548
|
if (!result.deduped) {
|
|
@@ -518,6 +562,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
518
562
|
: Math.max(0, result.originalTokenEstimate - result.tokenEstimate);
|
|
519
563
|
rt.tokensSaved += saved;
|
|
520
564
|
if (result.deduped) rt.dedupSkips++;
|
|
565
|
+
// Grow the rolling "saved" goal so the progress bar always has a fresh
|
|
566
|
+
// denominator (we don't want it pinned at 100% once we pass an old target).
|
|
567
|
+
if (rt.tokensSaved > savedGoal) savedGoal = Math.ceil((rt.tokensSaved * 1.25) / 10_000) * 10_000;
|
|
521
568
|
|
|
522
569
|
// Live toolbar "now processing" line: what file/region just got compacted or
|
|
523
570
|
// deduped. Reset to the last-seen action after a few seconds (see snapshot).
|
|
@@ -529,6 +576,18 @@ export default function (pi: ExtensionAPI) {
|
|
|
529
576
|
? `β» deduped ${fileLabel}`
|
|
530
577
|
: `π compacted ${result.checkpointId} Β· ${fileLabel}`;
|
|
531
578
|
lastActivityAt = Date.now();
|
|
579
|
+
// Explain-why line: surfaced while fresh. Pulls the dedup reason (which for
|
|
580
|
+
// L2 includes the cosine sim) so the user sees WHY a region was kept/dropped.
|
|
581
|
+
lastWhy = result.deduped
|
|
582
|
+
? `why: deduped@${result.dedupReason ?? "tier"}`
|
|
583
|
+
: `why: compacted β ${result.checkpointId}`;
|
|
584
|
+
// Recall/activity ticker: record this event in the ring buffer.
|
|
585
|
+
const savedK = (saved / 1000).toFixed(1);
|
|
586
|
+
pushTicker(
|
|
587
|
+
result.deduped
|
|
588
|
+
? `${C.green}β»${C.reset} deduped ${fileLabel} Β· ${savedK}k saved`
|
|
589
|
+
: `${C.cyan}π${C.reset} ${result.checkpointId} Β· +${savedK}k Β· ${fileLabel}`,
|
|
590
|
+
);
|
|
532
591
|
// The per-tier trace has settled into the final outcome β fold it back into
|
|
533
592
|
// the activity line and stop showing the live trace.
|
|
534
593
|
tierTrace = undefined;
|
|
@@ -590,6 +649,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
590
649
|
store,
|
|
591
650
|
);
|
|
592
651
|
dashboard.event("recall", { source, query: query.slice(0, 120), injected: result.toInject.length, empty: result.empty });
|
|
652
|
+
if (!result.empty && result.toInject.length > 0) {
|
|
653
|
+
const top = result.toInject[0];
|
|
654
|
+
const scorePct = Math.round((top.score ?? 0) * 100);
|
|
655
|
+
const files = top.checkpoint.filesModified ?? [];
|
|
656
|
+
const label = files.length ? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ") : top.checkpoint.checkpointId;
|
|
657
|
+
pushTicker(`${C.amber}β©${C.reset} recalled ${top.checkpoint.checkpointId} Β· ${scorePct}% Β· ${label}`);
|
|
658
|
+
lastWhy = `why: recalled@${scorePct}% (${result.toInject.length} chkpt)`;
|
|
659
|
+
}
|
|
593
660
|
return result;
|
|
594
661
|
}
|
|
595
662
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mega-compact",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Layered, local, vector-backed context compressor for pi β supersede/collapse/cluster compaction with deduped inline recall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BSD-2-Clause",
|