pi-mega-compact 0.4.15 → 0.4.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/dist/extensions/mega-commands.js +223 -0
- package/dist/extensions/mega-compact.js +19 -1092
- package/dist/extensions/mega-compact.test.js +28 -0
- package/dist/extensions/mega-config.js +100 -0
- package/dist/extensions/mega-dashboard-cmds.js +214 -0
- package/dist/extensions/mega-dashboard.js +35 -0
- package/dist/extensions/mega-events.js +167 -0
- package/dist/extensions/mega-pipeline.js +140 -0
- package/dist/extensions/mega-runtime.js +370 -0
- package/dist/src/store/sqlite.js +60 -0
- package/extensions/mega-commands.ts +250 -0
- package/extensions/mega-compact.test.ts +30 -0
- package/extensions/mega-compact.ts +20 -1236
- package/extensions/mega-config.ts +120 -0
- package/extensions/mega-dashboard-cmds.ts +209 -0
- package/extensions/mega-dashboard.ts +107 -0
- package/extensions/mega-events.ts +180 -0
- package/extensions/mega-pipeline.ts +179 -0
- package/extensions/mega-runtime.ts +386 -0
- package/package.json +1 -1
- package/src/store/sqlite.ts +96 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mega-commands.ts — the data/inspection slash commands.
|
|
3
|
+
*
|
|
4
|
+
* Registers the 8 user-facing commands that operate on the local vector store
|
|
5
|
+
* and live runtime state. The cost estimate in /mega-status now uses the real
|
|
6
|
+
* captured model rate (model_snapshots in SQLite) instead of a $3/1M stub.
|
|
7
|
+
*/
|
|
8
|
+
import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import { normalizeSessionId } from "../src/store.js";
|
|
10
|
+
import { listCheckpoints, latestModelSnapshot } from "../src/store/sqlite.js";
|
|
11
|
+
import { decompressSmart } from "../src/store/compression.js";
|
|
12
|
+
import { loadMetrics, fpRate, p95 } from "../src/monitoring.js";
|
|
13
|
+
import { C, recentUserQuery } from "./mega-runtime.js";
|
|
14
|
+
import { runCompact, doRecall } from "./mega-pipeline.js";
|
|
15
|
+
import { setTier, COMPACT_TIERS } from "./mega-config.js";
|
|
16
|
+
/** Resolve a checkpoint by id (or "recent"/"last") from this session's store. */
|
|
17
|
+
export function findCheckpoint(runtime, sid, ref) {
|
|
18
|
+
const all = listCheckpoints(sid, runtime.currentStateDir);
|
|
19
|
+
if (all.length === 0)
|
|
20
|
+
return undefined;
|
|
21
|
+
if (!ref || ref === "recent" || ref === "last")
|
|
22
|
+
return all[all.length - 1];
|
|
23
|
+
return all.find((c) => c.checkpointId === ref) ?? all.find((c) => c.checkpointId.endsWith(ref));
|
|
24
|
+
}
|
|
25
|
+
/** Register all data/inspection commands. */
|
|
26
|
+
export function registerCommands(pi, runtime, config) {
|
|
27
|
+
pi.registerCommand("mega-compact", {
|
|
28
|
+
description: "Compress current session context into the local vector store.",
|
|
29
|
+
handler: async (args, ctx) => {
|
|
30
|
+
const sessionEntries = ctx.sessionManager.getEntries();
|
|
31
|
+
// Project entries (branch-aware) into the message view.
|
|
32
|
+
const messages = sessionEntries.flatMap((e) => sessionEntryToContextMessages(e));
|
|
33
|
+
const summaryArg = args.trim();
|
|
34
|
+
const ran = runCompact(pi, runtime, config, ctx, messages, summaryArg ? { summary: summaryArg } : {});
|
|
35
|
+
if ("skipped" in ran && ran.skipped) {
|
|
36
|
+
ctx.ui.notify("[mega-compact] Nothing to compact (session too small).");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const r = ran.result;
|
|
40
|
+
ctx.ui.notify(`[mega-compact] ${r.deduped ? "region already compacted (deduped)" : `persisted ${r.checkpointId}`} · ` +
|
|
41
|
+
`${r.tokenEstimate} tok · ${runtime.currentStateDir}`);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
pi.registerCommand("mega-recall", {
|
|
45
|
+
description: "Recall relevant compacted context from the vector store and inline it.",
|
|
46
|
+
handler: async (args, ctx) => {
|
|
47
|
+
const query = args.trim() || recentUserQuery(ctx);
|
|
48
|
+
if (!query) {
|
|
49
|
+
ctx.ui.notify("[mega-compact] /mega-recall needs a query or a prior user message.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const r = doRecall(runtime, config, ctx, query, "command");
|
|
53
|
+
if (r.empty) {
|
|
54
|
+
runtime.logger.info("recall-empty", { query });
|
|
55
|
+
ctx.ui.notify(`[mega-compact] recall found nothing new for "${query}".`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Stage the block so the next before_agent_start prepends it (actual
|
|
59
|
+
// injection). Report what was selected now for immediate feedback.
|
|
60
|
+
runtime.pendingRecallBlock = r.block;
|
|
61
|
+
const list = r.report.map((l) => l).join("\n");
|
|
62
|
+
runtime.logger.info("recall", { query, injected: r.toInject.map((h) => h.checkpoint.checkpointId) });
|
|
63
|
+
runtime.setStatus(ctx, `mega-compact: recalled ${r.toInject.length} chkpt`);
|
|
64
|
+
ctx.ui.notify(`[mega-compact] recall staged ${r.toInject.length} checkpoint(s) for "${query}":\n${list}\n` +
|
|
65
|
+
`(injected at the next turn via system prompt)`);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
pi.registerCommand("mega-status", {
|
|
69
|
+
description: "Show mega-compact config, context usage, and the data-safety invariant.",
|
|
70
|
+
handler: async (_args, ctx) => {
|
|
71
|
+
runtime.bindRepo(ctx.cwd);
|
|
72
|
+
const usage = ctx.getContextUsage();
|
|
73
|
+
const pct = usage?.percent != null ? `${usage.percent}%` : "n/a";
|
|
74
|
+
const tokens = usage?.tokens != null ? `${usage.tokens} tok` : "n/a";
|
|
75
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
76
|
+
const st = runtime.store.stats(sid);
|
|
77
|
+
const repo = runtime.store.repoStats();
|
|
78
|
+
const di = runtime.store.dataInvariant();
|
|
79
|
+
const fmtB = (b) => b >= 1_048_576 ? `${(b / 1_048_576).toFixed(1)} MiB` :
|
|
80
|
+
b >= 1024 ? `${(b / 1024).toFixed(1)} KiB` : `${b} B`;
|
|
81
|
+
// Real cost: tokens saved × the captured model's input rate (USD/token),
|
|
82
|
+
// read from the model_snapshots table (Phase 5b schema). Falls back to 0
|
|
83
|
+
// when no model has been captured yet. contextWindow ÷ savedRate = context
|
|
84
|
+
// windows extended (how much "extra" conversation the freed space buys).
|
|
85
|
+
const model = latestModelSnapshot(runtime.currentStateDir);
|
|
86
|
+
const rate = model?.inputRate ?? 0;
|
|
87
|
+
const usd = (repo.tokensSaved * rate).toFixed(4);
|
|
88
|
+
const ctxWindow = usage?.contextWindow ?? 0;
|
|
89
|
+
const daysExtended = ctxWindow > 0 && repo.tokensSaved > 0
|
|
90
|
+
? (repo.tokensSaved / ctxWindow).toFixed(1)
|
|
91
|
+
: "0";
|
|
92
|
+
// Identified model/provider (captured on model_select / session_start).
|
|
93
|
+
// Shows the human model name + provider so the user knows WHICH model's
|
|
94
|
+
// pricing drives the cost figure. Falls back when none captured yet.
|
|
95
|
+
const modelStr = model
|
|
96
|
+
? `${model.modelName ?? model.modelId} · ${model.providerName ?? model.provider}`
|
|
97
|
+
: "unknown (no model captured)";
|
|
98
|
+
const costStr = `≈ $${usd} saved · ${daysExtended} context-windows extended`;
|
|
99
|
+
// Recall-quality badge (Phase 4): trust score from monitoring metrics.
|
|
100
|
+
const m = loadMetrics(runtime.currentStateDir);
|
|
101
|
+
const fp = fpRate(m, "L2");
|
|
102
|
+
const p95L2 = p95(m.latency.L2 ?? []);
|
|
103
|
+
const relPct = (st.dedupHitRate * 100).toFixed(0);
|
|
104
|
+
const qualityStr = `recall ${relPct}% relevant · FP ${(fp * 100).toFixed(1)}% · L2 p95 ${p95L2.toFixed(0)}ms`;
|
|
105
|
+
ctx.ui.notify(`[mega-compact] pct=${pct} tokens=${tokens} tier=${config.tier} fastGate=${config.fastGatePct}% ` +
|
|
106
|
+
`threshold=${config.thresholdTokens} auto=${config.auto} autoInline=${config.autoInline}\n` +
|
|
107
|
+
`[mega-compact] store: ${st.checkpointCount} chkpt · ` +
|
|
108
|
+
`${st.totalTokenEstimate} tok · last=${st.lastCheckpointId ?? "—"} · ` +
|
|
109
|
+
`injected=${st.injectedCount} · dedup=${(st.dedupHitRate * 100).toFixed(0)}%\n` +
|
|
110
|
+
`[mega-compact] anchor=${config.anchorUserMessages} preserveRecent=${config.preserveRecent} ` +
|
|
111
|
+
`autoInlineK=${config.autoInlineK} dedupSim=${config.dedupSim} debug=${config.debug}\n` +
|
|
112
|
+
`[mega-compact] 🛡 data-safe: ${di.regionsRetained} regions retained ` +
|
|
113
|
+
`(${fmtB(di.compressedOriginalBytes)} compressed-original) · ` +
|
|
114
|
+
`${di.duplicatesCollapsed} dedup-duplicates collapsed · ` +
|
|
115
|
+
`${C.green}0 bytes permanently deleted${C.reset}\n` +
|
|
116
|
+
`[mega-compact] 💰 ${costStr}\n` +
|
|
117
|
+
`[mega-compact] 🤖 model: ${modelStr}\n` +
|
|
118
|
+
`[mega-compact] 🎯 ${qualityStr}\n` +
|
|
119
|
+
`[mega-compact] stateDir=${runtime.currentStateDir}`);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
// ---- Phase 4: cheap standout commands (data is already persisted) -------
|
|
123
|
+
pi.registerCommand("mega-restore", {
|
|
124
|
+
description: "Re-inject a checkpoint's verbatim original region into context. Usage: /mega-restore <chkpt|recent>",
|
|
125
|
+
handler: async (args, ctx) => {
|
|
126
|
+
runtime.bindRepo(ctx.cwd);
|
|
127
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
128
|
+
const cp = findCheckpoint(runtime, sid, args.trim());
|
|
129
|
+
if (!cp) {
|
|
130
|
+
ctx.ui.notify(`[mega-compact] no checkpoint found${args.trim() ? ` for "${args.trim()}"` : ""} in this session. Try /mega-history.`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!cp.compressedOriginal) {
|
|
134
|
+
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} has no recoverable original (pre-blob or direct add). Cannot restore verbatim.`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
|
|
138
|
+
// Re-inject verbatim via before_agent_start (PREVENT-PI-003) — never
|
|
139
|
+
// touches live messages, only prepends the restored region to systemPrompt.
|
|
140
|
+
runtime.pendingRecallBlock = `The following compacted context was RESTORED from checkpoint ${cp.checkpointId} (verbatim original region):\n\n${original}`;
|
|
141
|
+
const files = cp.filesModified?.length ? cp.filesModified.join(", ") : "(no files captured)";
|
|
142
|
+
ctx.ui.notify(`[mega-compact] ♻ restored ${cp.checkpointId} — ${original.length} chars re-injected on next turn.\n` +
|
|
143
|
+
`[mega-compact] files: ${files}`);
|
|
144
|
+
runtime.dashboard.event("restore", { checkpointId: cp.checkpointId, chars: original.length });
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
pi.registerCommand("mega-history", {
|
|
148
|
+
description: "List this session's checkpoints (id, date, files, tokens). Usage: /mega-history",
|
|
149
|
+
handler: async (_args, ctx) => {
|
|
150
|
+
runtime.bindRepo(ctx.cwd);
|
|
151
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
152
|
+
const all = listCheckpoints(sid, runtime.currentStateDir);
|
|
153
|
+
if (all.length === 0) {
|
|
154
|
+
ctx.ui.notify("[mega-compact] no checkpoints in this session yet.");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const rows = all.map((c) => {
|
|
158
|
+
const when = c.timestamp ? new Date(c.timestamp).toISOString().slice(0, 16).replace("T", " ") : "—";
|
|
159
|
+
const files = c.filesModified?.length ? c.filesModified.map((f) => f.split("/").pop()).join(", ") : "—";
|
|
160
|
+
const orig = c.originalTokenEstimate ?? 0;
|
|
161
|
+
const stored = c.tokenEstimate ?? 0;
|
|
162
|
+
const saved = Math.max(0, orig - stored);
|
|
163
|
+
return ` ${c.checkpointId} ${when} ${C.cyan}${saved}t saved${C.reset} ${files}`;
|
|
164
|
+
});
|
|
165
|
+
ctx.ui.notify(`[mega-compact] ${all.length} checkpoint(s) in this session:\n` + rows.join("\n") +
|
|
166
|
+
`\n[mega-compact] /mega-view <chkpt> to see the original region · /mega-restore <chkpt> to re-inject it`);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
pi.registerCommand("mega-view", {
|
|
170
|
+
description: "Show a checkpoint's verbatim original region. Usage: /mega-view <chkpt|recent>",
|
|
171
|
+
handler: async (args, ctx) => {
|
|
172
|
+
runtime.bindRepo(ctx.cwd);
|
|
173
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
174
|
+
const cp = findCheckpoint(runtime, sid, args.trim());
|
|
175
|
+
if (!cp) {
|
|
176
|
+
ctx.ui.notify(`[mega-compact] no checkpoint found${args.trim() ? ` for "${args.trim()}"` : ""}. Try /mega-history.`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!cp.compressedOriginal) {
|
|
180
|
+
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} summary:\n${cp.summary.slice(0, 500)}${cp.summary.length > 500 ? "…" : ""}\n(no verbatim original stored)`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
|
|
184
|
+
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} — original region (${original.length} chars):\n` +
|
|
185
|
+
`${original.slice(0, 1500)}${original.length > 1500 ? "\n…(truncated)" : ""}`);
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
pi.registerCommand("mega-help", {
|
|
189
|
+
description: "Plain-language glossary of what mega-compact's stats mean.",
|
|
190
|
+
handler: async (_args, ctx) => {
|
|
191
|
+
ctx.ui.notify(`[mega-compact] glossary — what the numbers mean:\n` +
|
|
192
|
+
`• token — a chunk of text (~4 chars). Context window = how much text fits in memory at once.\n` +
|
|
193
|
+
`• space freed — how much conversation we've compressed away to make room (the win).\n` +
|
|
194
|
+
`• memory held — how much compact summary we're currently keeping as your 'notes'.\n` +
|
|
195
|
+
`• saved checkpoint — a compact summary of an old conversation chunk we stored.\n` +
|
|
196
|
+
`• repeat-skipped — how often new text matched something we already had, so we didn't store a duplicate.\n` +
|
|
197
|
+
`• injected — times we pasted an old saved note back into the chat because it was relevant.\n` +
|
|
198
|
+
`• recall relevance — of those, how often the note was actually on-topic.\n` +
|
|
199
|
+
`• data safety — every compressed region is kept verbatim; nothing is permanently deleted. /mega-restore brings any of it back.`);
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
pi.registerCommand("mega-tier", {
|
|
203
|
+
description: "Show or change the compaction tier at runtime. Usage: /mega-tier [low|medium|high|ultra|mega]",
|
|
204
|
+
handler: async (args, ctx) => {
|
|
205
|
+
const arg = args.trim().toLowerCase();
|
|
206
|
+
if (!arg) {
|
|
207
|
+
// Show current tier and available options.
|
|
208
|
+
ctx.ui.notify(`[mega-compact] current tier: ${config.tier} (${config.thresholdTokens} tok)\n` +
|
|
209
|
+
`[mega-compact] available tiers: ${Object.entries(COMPACT_TIERS).map(([k, v]) => `${k}=${v}`).join(", ")}`);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (!(arg in COMPACT_TIERS)) {
|
|
213
|
+
ctx.ui.notify(`[mega-compact] unknown tier "${arg}". Available: ${Object.keys(COMPACT_TIERS).join(", ")}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const newTier = arg;
|
|
217
|
+
setTier(config, newTier);
|
|
218
|
+
runtime.setStatus(ctx, `mega-compact: tier → ${newTier} (${config.thresholdTokens} tok)`);
|
|
219
|
+
ctx.ui.notify(`[mega-compact] tier changed to ${newTier} (threshold: ${config.thresholdTokens} tokens)`);
|
|
220
|
+
runtime.snapshot(ctx);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
}
|