@monotykamary/pi-vcc 0.7.5 → 0.8.1
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/README.md +8 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/core/content.ts +22 -0
- package/src/core/search-entries.ts +5 -2
- package/src/hooks/before-compact.ts +43 -4
package/README.md
CHANGED
|
@@ -236,12 +236,18 @@ pi -e https://github.com/monotykamary/pi-vcc@tom
|
|
|
236
236
|
Once installed, pi-vcc registers a `session_before_compact` hook.
|
|
237
237
|
|
|
238
238
|
- Run `/pi-vcc` to trigger pi-vcc compaction manually.
|
|
239
|
-
- By default, pi-vcc handles all compaction paths (`/compact`, auto-threshold, `/pi-vcc`). Set `overrideDefaultCompaction: false` in the config to fall back to pi core's LLM-based compaction for `/compact` and auto-threshold.
|
|
239
|
+
- By default, pi-vcc handles all compaction paths (`/compact`, auto-threshold, `/pi-vcc`). Set `overrideDefaultCompaction: false` in the config to fall back to pi core's LLM-based compaction for `/compact` and auto-threshold. When pi-fabric's compaction engine is active, pi-vcc retains its threshold and recovery triggers but delegates non-`/pi-vcc` summary compilation to pi-fabric.
|
|
240
240
|
- To search older active-lineage history after compaction, use `vcc_recall`.
|
|
241
241
|
- To intentionally search across all lineages, pass `scope:"all"` to `vcc_recall` or run `/pi-vcc-recall <query> scope:all`.
|
|
242
242
|
- To search and feed results to agent yourself, run `/pi-vcc-recall <query> [page:N]`.
|
|
243
243
|
- Tip: type `/recall` and Pi will autocomplete to `/pi-vcc-recall`.
|
|
244
244
|
|
|
245
|
+
### pi-fabric interop
|
|
246
|
+
|
|
247
|
+
When `PI_FABRIC_COMPACTION_ENGINE=fabric`, pi-vcc defers non-explicit summary compilation to pi-fabric while preserving its proactive-threshold and Codex recovery trigger behavior. pi-fabric marks an event it has already claimed with `_fabricCompaction === true`, which prevents pi-vcc from replacing that result. An explicit `/pi-vcc` uses the `__pi_vcc__` instruction sentinel and always runs pi-vcc's deterministic compiler.
|
|
248
|
+
|
|
249
|
+
The precedence is: explicit `/pi-vcc` sentinel > pi-fabric engine > pi-vcc default override.
|
|
250
|
+
|
|
245
251
|
### How compaction works
|
|
246
252
|
|
|
247
253
|
Pi splits the conversation at the **last user message**. Everything after — the **kept tail** — stays intact and untouched. pi-vcc only summarizes the older portion before that cut point.
|
|
@@ -573,7 +579,7 @@ Config lives at `~/.pi/agent/pi-vcc-config.json` (auto-scaffolded on first load
|
|
|
573
579
|
}
|
|
574
580
|
```
|
|
575
581
|
|
|
576
|
-
- **`overrideDefaultCompaction`** *(default `true`)*: when `true` (default), pi-vcc handles all compaction paths (`/compact`, auto-threshold, `/pi-vcc`). Set `false` to let pi core handle `/compact` and auto-threshold compactions via its default LLM-based compaction.
|
|
582
|
+
- **`overrideDefaultCompaction`** *(default `true`)*: when `true` (default), pi-vcc handles all compaction paths (`/compact`, auto-threshold, `/pi-vcc`) unless the active pi-fabric engine owns summary compilation. Set `false` to let pi core handle `/compact` and auto-threshold compactions via its default LLM-based compaction. Explicit `/pi-vcc` always uses pi-vcc.
|
|
577
583
|
- **`debug`** *(default `false`)*: when `true`, each compaction writes detailed info to `/tmp/pi-vcc-debug.json` — message counts, cut boundary, summary preview, sections.
|
|
578
584
|
- **`modelThresholds`** *(default: none)*: per-model compaction thresholds. Keys match against `"provider/modelId"` (e.g., `"neuralwatt/zai-org/GLM-5.1-FP8"`) or just `"modelId"` (e.g., `"GLM-5.1"` — matched only when `provider/modelId` doesn't). Each value has:
|
|
579
585
|
- **`reserveTokens`**: tokens to reserve for the LLM response. Overrides pi-core's global `compaction.reserveTokens` for matching models. Controls *when* compaction triggers: `contextTokens > contextWindow − reserveTokens`. A higher value compacts earlier (more conservative); a lower value lets context grow larger. Takes precedence over `compactAtTokens` and `compactPercent` when multiple are set.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monotykamary/pi-vcc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@monotykamary/pi-vcc",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.8.0",
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"knip": "6.14.1",
|
|
12
12
|
"typescript": "6.0.3"
|
package/package.json
CHANGED
package/src/core/content.ts
CHANGED
|
@@ -59,6 +59,28 @@ const thinkingParts = (content: Message["content"]): string[] => {
|
|
|
59
59
|
export const thinkingOf = (content: Message["content"]): string =>
|
|
60
60
|
thinkingParts(content).join("\n");
|
|
61
61
|
|
|
62
|
+
const toolCallArgText = (args: Record<string, unknown>): string => {
|
|
63
|
+
const vals: string[] = [];
|
|
64
|
+
for (const v of Object.values(args ?? {})) {
|
|
65
|
+
if (typeof v === "string" && v.length > 0) vals.push(v);
|
|
66
|
+
}
|
|
67
|
+
return vals.join("\n");
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const toolCallParts = (content: Message["content"]): string[] => {
|
|
71
|
+
if (!content || typeof content === "string") return [];
|
|
72
|
+
return content
|
|
73
|
+
.filter((part) => part.type === "toolCall")
|
|
74
|
+
.map((part) => toolCallArgText(part.arguments));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** Extract all string-valued arguments from toolCall content parts.
|
|
78
|
+
* Lets vcc_recall match against tool invocations — e.g. a bash
|
|
79
|
+
* toolCall's `arguments.command`, a grep's `pattern`, an edit's
|
|
80
|
+
* `oldText`/`newText`. Non-string args are skipped. */
|
|
81
|
+
export const toolCallsOf = (content: Message["content"]): string =>
|
|
82
|
+
toolCallParts(content).filter(Boolean).join("\n");
|
|
83
|
+
|
|
62
84
|
/** Extract a snippet of ~`radius` chars around the first match of `term` in `text`. */
|
|
63
85
|
const snippet = (text: string, term: string, radius = 60): string | null => {
|
|
64
86
|
const idx = text.toLowerCase().indexOf(term.toLowerCase());
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Message } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { RenderedEntry } from "./render-entries";
|
|
3
|
-
import { textOf, thinkingOf } from "./content";
|
|
3
|
+
import { textOf, thinkingOf, toolCallsOf } from "./content";
|
|
4
4
|
|
|
5
5
|
export interface SearchHit extends RenderedEntry {
|
|
6
6
|
/** Context snippet around the first matched term (only when query provided) */
|
|
@@ -270,10 +270,13 @@ const fullText = (msg: Message): string => {
|
|
|
270
270
|
if ((msg as any).role === "bashExecution") {
|
|
271
271
|
return `${(msg as any).command ?? ""} ${(msg as any).output ?? ""}`;
|
|
272
272
|
}
|
|
273
|
-
// Include thinking
|
|
273
|
+
// Include thinking + toolCall arguments so recall can match against
|
|
274
|
+
// model reasoning and tool invocations (e.g. a bash toolCall's command).
|
|
274
275
|
let text = textOf(msg.content);
|
|
275
276
|
const thinking = thinkingOf(msg.content);
|
|
276
277
|
if (thinking) text = thinking + "\n" + text;
|
|
278
|
+
const toolArgs = toolCallsOf(msg.content);
|
|
279
|
+
if (toolArgs) text = toolArgs + "\n" + text;
|
|
277
280
|
return text;
|
|
278
281
|
};
|
|
279
282
|
|
|
@@ -28,6 +28,8 @@ let lastCompactWasPiVcc = false;
|
|
|
28
28
|
let lastCompactWasCodexRecovery = false;
|
|
29
29
|
let lastCompactWasProactive = false;
|
|
30
30
|
let lastCompactHandledByVcc = false;
|
|
31
|
+
let lastCompactDeferredToFabric = false;
|
|
32
|
+
let hasNotifiedFabricDeferral = false;
|
|
31
33
|
export const getLastCompactionStats = () => lastStats;
|
|
32
34
|
|
|
33
35
|
const formatTokens = (n: number): string => {
|
|
@@ -459,6 +461,9 @@ export function shouldTriggerResumeForCompaction(
|
|
|
459
461
|
|
|
460
462
|
export const registerBeforeCompactHook = (pi: ExtensionAPI) => {
|
|
461
463
|
pi.on("session_before_compact", (event, ctx) => {
|
|
464
|
+
// pi-fabric may run before pi-vcc and mark the shared event after claiming it.
|
|
465
|
+
if ((event as any)._fabricCompaction === true) return;
|
|
466
|
+
|
|
462
467
|
const { preparation, branchEntries, customInstructions } = event;
|
|
463
468
|
const settings = loadSettings();
|
|
464
469
|
|
|
@@ -495,6 +500,32 @@ export const registerBeforeCompactHook = (pi: ExtensionAPI) => {
|
|
|
495
500
|
const isPiVccHandled =
|
|
496
501
|
isPiVcc || isCodexOutputLimitCompaction || isCodexContextOverflowCompaction;
|
|
497
502
|
|
|
503
|
+
// Explicit /pi-vcc takes precedence over the pi-fabric engine. For every
|
|
504
|
+
// other compaction, retain pi-vcc's trigger/recovery bookkeeping but let
|
|
505
|
+
// pi-fabric compile the summary.
|
|
506
|
+
if (!isPiVcc && process.env.PI_FABRIC_COMPACTION_ENGINE === "fabric") {
|
|
507
|
+
if (!isPiVccHandled && !settings.overrideDefaultCompaction) return;
|
|
508
|
+
if (isCodexContextOverflowCompaction) clearCodexContextOverflowPending();
|
|
509
|
+
|
|
510
|
+
lastCompactWasPiVcc = false;
|
|
511
|
+
lastCompactWasCodexRecovery =
|
|
512
|
+
isCodexOutputLimitCompaction || isCodexContextOverflowCompaction;
|
|
513
|
+
lastCompactWasProactive = isProactiveTriggerActive();
|
|
514
|
+
lastCompactHandledByVcc = true;
|
|
515
|
+
lastCompactDeferredToFabric = true;
|
|
516
|
+
|
|
517
|
+
if (settings.overrideDefaultCompaction && !hasNotifiedFabricDeferral) {
|
|
518
|
+
hasNotifiedFabricDeferral = true;
|
|
519
|
+
try {
|
|
520
|
+
ctx?.ui?.notify?.(
|
|
521
|
+
"pi-vcc: deferring compaction to pi-fabric engine (explicit /pi-vcc still uses pi-vcc)",
|
|
522
|
+
"info",
|
|
523
|
+
);
|
|
524
|
+
} catch {}
|
|
525
|
+
}
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
498
529
|
// Always handle explicit /pi-vcc and Codex recovery markers. Otherwise,
|
|
499
530
|
// only handle when the user opted in via settings.
|
|
500
531
|
if (!isPiVccHandled && !settings.overrideDefaultCompaction) return;
|
|
@@ -672,6 +703,7 @@ export const registerBeforeCompactHook = (pi: ExtensionAPI) => {
|
|
|
672
703
|
isCodexOutputLimitCompaction || isCodexContextOverflowCompaction;
|
|
673
704
|
lastCompactWasProactive = isProactiveTriggerActive();
|
|
674
705
|
lastCompactHandledByVcc = true;
|
|
706
|
+
lastCompactDeferredToFabric = false;
|
|
675
707
|
|
|
676
708
|
// Signal to neuralwatt-mcr that pi-vcc is handling compaction
|
|
677
709
|
// so it doesn't cancel the event. Without this flag, neuralwatt-mcr
|
|
@@ -689,6 +721,10 @@ export const registerBeforeCompactHook = (pi: ExtensionAPI) => {
|
|
|
689
721
|
};
|
|
690
722
|
});
|
|
691
723
|
|
|
724
|
+
pi.on("session_start", () => {
|
|
725
|
+
hasNotifiedFabricDeferral = false;
|
|
726
|
+
});
|
|
727
|
+
|
|
692
728
|
// After compaction completes, check if the agent loop stalled and needs
|
|
693
729
|
// an invisible continue to resume. This handles threshold compaction
|
|
694
730
|
// where willRetry=false — pi-core doesn't auto-retry, and the agent loop
|
|
@@ -697,17 +733,20 @@ export const registerBeforeCompactHook = (pi: ExtensionAPI) => {
|
|
|
697
733
|
// that isn't a clean end_turn), the agent was interrupted and should
|
|
698
734
|
// continue.
|
|
699
735
|
pi.on("session_compact", (event, ctx) => {
|
|
700
|
-
//
|
|
736
|
+
// Act when pi-vcc compiled the summary or tracked a compaction delegated
|
|
737
|
+
// to pi-fabric so proactive and Codex recovery continuation still works.
|
|
701
738
|
if (!lastCompactHandledByVcc) return;
|
|
702
739
|
const wasCodexRecoveryCompaction = lastCompactWasCodexRecovery;
|
|
703
740
|
const wasProactiveCompaction = lastCompactWasProactive;
|
|
741
|
+
const wasDeferredToFabric = lastCompactDeferredToFabric;
|
|
704
742
|
lastCompactHandledByVcc = false;
|
|
705
743
|
lastCompactWasCodexRecovery = false;
|
|
706
744
|
lastCompactWasProactive = false;
|
|
745
|
+
lastCompactDeferredToFabric = false;
|
|
707
746
|
|
|
708
|
-
// Fire success toast for /compact path only (delayed to let UI
|
|
709
|
-
// /pi-vcc
|
|
710
|
-
if (!lastCompactWasPiVcc) {
|
|
747
|
+
// Fire success toast for pi-vcc's /compact path only (delayed to let UI
|
|
748
|
+
// settle). /pi-vcc has its own callback, and pi-fabric owns delegated UI.
|
|
749
|
+
if (!lastCompactWasPiVcc && !wasDeferredToFabric) {
|
|
711
750
|
const stats = lastStats;
|
|
712
751
|
const count = countPiVccCompactionsFromSession(ctx?.sessionManager as any);
|
|
713
752
|
const compactionLabel = count > 0
|