pi-mega-compact 0.7.1 → 0.7.2
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-pipeline.js +17 -52
- package/dist/extensions/mega-runtime.js +96 -183
- package/extensions/mega-compact-driver.ts +56 -56
- package/extensions/mega-pipeline.ts +394 -481
- package/extensions/mega-runtime.ts +739 -912
- package/package.json +1 -1
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { compactSession } from "../src/engine.js";
|
|
11
|
-
import { recallAndInline, recallAndInlineAsync, formatRecallBlock
|
|
11
|
+
import { recallAndInline, recallAndInlineAsync, formatRecallBlock } from "../src/recall.js";
|
|
12
12
|
import { normalizeSessionId } from "../src/store.js";
|
|
13
13
|
import { estimateBlockTokens } from "../src/tokens.js";
|
|
14
14
|
import { touchSession, logDaily } from "../src/store/sqlite.js";
|
|
15
15
|
import { consolidateMemories } from "../src/memory.js";
|
|
16
|
-
import { C, MARKER_TYPE } from "./mega-runtime.js";
|
|
17
|
-
import { resolveRepoRoot, preserveRecentForPressure
|
|
16
|
+
import { C, MARKER_TYPE, } from "./mega-runtime.js";
|
|
17
|
+
import { resolveRepoRoot, preserveRecentForPressure } from "./mega-config.js";
|
|
18
18
|
import { runRaptor } from "../src/dedup/raptor/index.js";
|
|
19
19
|
import { loadDedupConfig } from "../src/config/dedup.js";
|
|
20
20
|
import { upsertEmbedding as indexUpsertEmbedding } from "../src/store/vectorIndex.js";
|
|
@@ -110,17 +110,13 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
|
|
|
110
110
|
// Grow the rolling "saved" goal so the progress bar always has a fresh
|
|
111
111
|
// denominator (we don't want it pinned at 100% once we pass an old target).
|
|
112
112
|
if (runtime.rt.tokensSaved > runtime.savedGoal)
|
|
113
|
-
runtime.savedGoal =
|
|
114
|
-
Math.ceil((runtime.rt.tokensSaved * 1.25) / 10_000) * 10_000;
|
|
113
|
+
runtime.savedGoal = Math.ceil((runtime.rt.tokensSaved * 1.25) / 10_000) * 10_000;
|
|
115
114
|
// Live toolbar activity: what file/region just got compacted or deduped.
|
|
116
115
|
// Rendered via the rotating ticker line (see snapshot); the ring buffer is
|
|
117
116
|
// cycled one-per-repaint so the single line scrolls through recent files.
|
|
118
117
|
const files = result.filesModified ?? [];
|
|
119
118
|
const fileLabel = files.length
|
|
120
|
-
? files
|
|
121
|
-
.map((f) => f.split("/").pop() ?? f)
|
|
122
|
-
.slice(0, 2)
|
|
123
|
-
.join(", ")
|
|
119
|
+
? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ")
|
|
124
120
|
: result.regionHash.slice(0, 8);
|
|
125
121
|
runtime.lastActivityAt = Date.now();
|
|
126
122
|
// Explain-why line: surfaced while fresh. Pulls the dedup reason (which for
|
|
@@ -172,10 +168,7 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
|
|
|
172
168
|
// waiting for the next turn-cadence tick. Uses the shared runMemoryReview
|
|
173
169
|
// helper (fire-and-forget; doCompact is sync). Best-effort + non-fatal. Only
|
|
174
170
|
// fires above the `high` band so low-pressure compactions don't pay the cost.
|
|
175
|
-
if (!result.deduped &&
|
|
176
|
-
config.memoryAutoReview &&
|
|
177
|
-
runtime.pressureBand !== "low" &&
|
|
178
|
-
runtime.pressureBand !== "medium") {
|
|
171
|
+
if (!result.deduped && config.memoryAutoReview && runtime.pressureBand !== "low" && runtime.pressureBand !== "medium") {
|
|
179
172
|
void runMemoryReview(runtime, view, "pressure");
|
|
180
173
|
}
|
|
181
174
|
// Sentinel marker: a non-LLM bookkeeping entry so subsequent triggers can
|
|
@@ -203,9 +196,7 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
|
|
|
203
196
|
// S25: stamp the tree with the newest checkpoint epoch so the
|
|
204
197
|
// freshness guard in raptorSearchHits can reject stale trees after a
|
|
205
198
|
// later compaction adds newer checkpoints.
|
|
206
|
-
const builtAt = all.length > 0
|
|
207
|
-
? Math.max(...all.map((c) => c.timestamp))
|
|
208
|
-
: Date.now();
|
|
199
|
+
const builtAt = all.length > 0 ? Math.max(...all.map((c) => c.timestamp)) : Date.now();
|
|
209
200
|
runRaptor(leaves, {
|
|
210
201
|
stateDir: runtime.currentStateDir,
|
|
211
202
|
sessionId: sid,
|
|
@@ -323,8 +314,7 @@ export function piCompactWouldNoop(ctx) {
|
|
|
323
314
|
if (m.role !== "toolResult")
|
|
324
315
|
isCut = true;
|
|
325
316
|
const c = m.content;
|
|
326
|
-
const text = typeof c === "string"
|
|
327
|
-
? c
|
|
317
|
+
const text = typeof c === "string" ? c
|
|
328
318
|
: Array.isArray(c)
|
|
329
319
|
? c.map((b) => b?.text ?? "").join(" ")
|
|
330
320
|
: "";
|
|
@@ -377,22 +367,12 @@ export function doRecall(runtime, config, ctx, query, source) {
|
|
|
377
367
|
liveWindow,
|
|
378
368
|
dedupSim: config.dedupSim,
|
|
379
369
|
}, runtime.store);
|
|
380
|
-
runtime.dashboard.event("recall", {
|
|
381
|
-
source,
|
|
382
|
-
query: query.slice(0, 120),
|
|
383
|
-
injected: result.toInject.length,
|
|
384
|
-
empty: result.empty,
|
|
385
|
-
});
|
|
370
|
+
runtime.dashboard.event("recall", { source, query: query.slice(0, 120), injected: result.toInject.length, empty: result.empty });
|
|
386
371
|
if (!result.empty && result.toInject.length > 0) {
|
|
387
372
|
const top = result.toInject[0];
|
|
388
373
|
const scorePct = Math.round((top.score ?? 0) * 100);
|
|
389
374
|
const files = top.checkpoint.filesModified ?? [];
|
|
390
|
-
const label = files.length
|
|
391
|
-
? files
|
|
392
|
-
.map((f) => f.split("/").pop() ?? f)
|
|
393
|
-
.slice(0, 2)
|
|
394
|
-
.join(", ")
|
|
395
|
-
: top.checkpoint.checkpointId;
|
|
375
|
+
const label = files.length ? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ") : top.checkpoint.checkpointId;
|
|
396
376
|
runtime.pushTicker(`${C.amber}↩${C.reset} recalled ${top.checkpoint.checkpointId} · ${scorePct}% · ${label}`);
|
|
397
377
|
runtime.lastWhy = `why: recalled@${scorePct}% (${result.toInject.length} chkpt)`;
|
|
398
378
|
}
|
|
@@ -415,15 +395,9 @@ export async function doRecallAsync(runtime, config, ctx, query, source, opts =
|
|
|
415
395
|
const liveWindow = config.windowDedupe ? extractLiveWindow(ctx) : undefined;
|
|
416
396
|
// Sync same-repo first (fast, never blocks).
|
|
417
397
|
const sameRepo = recallAndInline({
|
|
418
|
-
sessionId: sid,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
source,
|
|
422
|
-
skipInjected: true,
|
|
423
|
-
recallMaxTokens: config.recallMaxTokens,
|
|
424
|
-
windowDedupe: config.windowDedupe,
|
|
425
|
-
liveWindow,
|
|
426
|
-
dedupSim: config.dedupSim,
|
|
398
|
+
sessionId: sid, query, limit: config.autoInlineK, source, skipInjected: true,
|
|
399
|
+
recallMaxTokens: config.recallMaxTokens, windowDedupe: config.windowDedupe,
|
|
400
|
+
liveWindow, dedupSim: config.dedupSim,
|
|
427
401
|
}, runtime.store);
|
|
428
402
|
if (!config.crossRepoEnabled || !opts.crossRepo)
|
|
429
403
|
return sameRepo;
|
|
@@ -432,22 +406,13 @@ export async function doRecallAsync(runtime, config, ctx, query, source, opts =
|
|
|
432
406
|
// Augment: cross-repo HNSW (async) with the stricter floor. Non-fatal.
|
|
433
407
|
try {
|
|
434
408
|
const x = await recallAndInlineAsync({
|
|
435
|
-
sessionId: sid,
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
source,
|
|
439
|
-
skipInjected: true,
|
|
440
|
-
recallMaxTokens: config.recallMaxTokens,
|
|
441
|
-
windowDedupe: config.windowDedupe,
|
|
442
|
-
liveWindow,
|
|
443
|
-
dedupSim: config.crossRepoCosine,
|
|
444
|
-
crossRepo: true,
|
|
409
|
+
sessionId: sid, query, limit: config.autoInlineK, source, skipInjected: true,
|
|
410
|
+
recallMaxTokens: config.recallMaxTokens, windowDedupe: config.windowDedupe,
|
|
411
|
+
liveWindow, dedupSim: config.crossRepoCosine, crossRepo: true,
|
|
445
412
|
globalIndexDir: process.env.MEGACOMPACT_INDEX_DIR,
|
|
446
413
|
}, runtime.store);
|
|
447
414
|
runtime.dashboard.event("recall-crossrepo", {
|
|
448
|
-
source,
|
|
449
|
-
query: query.slice(0, 120),
|
|
450
|
-
injected: x.toInject.length,
|
|
415
|
+
source, query: query.slice(0, 120), injected: x.toInject.length,
|
|
451
416
|
sourceRepos: x.toInject.map((h) => h.repoId).filter(Boolean),
|
|
452
417
|
});
|
|
453
418
|
// Merge, dedup by checkpointId, respect the same token cap by reformatting.
|
|
@@ -16,9 +16,9 @@ import { VectorStore } from "../src/vectorStore.js";
|
|
|
16
16
|
import { toEngineMessages } from "../src/adapt.js";
|
|
17
17
|
import { normalizeSessionId } from "../src/store.js";
|
|
18
18
|
import { Logger } from "../src/log.js";
|
|
19
|
-
import { recordModelSnapshot, latestModelSnapshot, upsertRepoRegistry, recordRepoModel
|
|
19
|
+
import { recordModelSnapshot, latestModelSnapshot, upsertRepoRegistry, recordRepoModel } from "../src/store/sqlite.js";
|
|
20
20
|
import { detectCrossRepoDrift } from "../src/driftDetection.js";
|
|
21
|
-
import { repoStateDir, resolveRepoRoot, pressureRatio, pressureFromPct, pressureBand, effectiveThresholdTokens
|
|
21
|
+
import { repoStateDir, resolveRepoRoot, pressureRatio, pressureFromPct, pressureBand, effectiveThresholdTokens } from "./mega-config.js";
|
|
22
22
|
import { Dashboard } from "./mega-dashboard.js";
|
|
23
23
|
export const STATUS_KEY = "mega-compact";
|
|
24
24
|
export const WIDGET_KEY = "mega-compact-stats";
|
|
@@ -74,25 +74,40 @@ function visibleWidth(s) {
|
|
|
74
74
|
let w = 0;
|
|
75
75
|
for (const ch of stripped) {
|
|
76
76
|
const cp = ch.codePointAt(0) ?? 0;
|
|
77
|
-
const wide = cp >= 0x1100 &&
|
|
78
|
-
(cp <=
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
(cp >= 0xac00 && cp <= 0xd7a3) ||
|
|
85
|
-
(cp >= 0xf900 && cp <= 0xfaff) ||
|
|
86
|
-
(cp >= 0xfe30 && cp <= 0xfe4f) ||
|
|
87
|
-
(cp >= 0xff00 && cp <= 0xff60) ||
|
|
88
|
-
(cp >= 0xffe0 && cp <= 0xffe6) ||
|
|
89
|
-
(cp >= 0x1f300 && cp <= 0x1faff) ||
|
|
90
|
-
(cp >= 0x20000 && cp <= 0x3fffd));
|
|
77
|
+
const wide = cp >= 0x1100 && ((cp <= 0x115f) || (cp >= 0x2e80 && cp <= 0x303e) ||
|
|
78
|
+
(cp >= 0x3041 && cp <= 0x33ff) || (cp >= 0x3400 && cp <= 0x4dbf) ||
|
|
79
|
+
(cp >= 0x4e00 && cp <= 0x9fff) || (cp >= 0xa000 && cp <= 0xa4cf) ||
|
|
80
|
+
(cp >= 0xac00 && cp <= 0xd7a3) || (cp >= 0xf900 && cp <= 0xfaff) ||
|
|
81
|
+
(cp >= 0xfe30 && cp <= 0xfe4f) || (cp >= 0xff00 && cp <= 0xff60) ||
|
|
82
|
+
(cp >= 0xffe0 && cp <= 0xffe6) || (cp >= 0x1f300 && cp <= 0x1faff) ||
|
|
83
|
+
(cp >= 0x20000 && cp <= 0x3fffd));
|
|
91
84
|
w += wide ? 2 : 1;
|
|
92
85
|
}
|
|
93
86
|
return w;
|
|
94
87
|
}
|
|
95
88
|
/** Pad a content string (with ANSI colors) to `width` cells using panel bg. */
|
|
89
|
+
function spreadGroups(width, groups, indent = 0) {
|
|
90
|
+
if (groups.length === 0)
|
|
91
|
+
return panelLine('', width);
|
|
92
|
+
// Calculate visible width of each group
|
|
93
|
+
const groupWidths = groups.map(g => visibleWidth(PANEL_BG + g.replace(/\x1b\[0m/g, PANEL_RST)));
|
|
94
|
+
const totalContent = groupWidths.reduce((a, b) => a + b, 0);
|
|
95
|
+
const separator = ` ${C.dim}│${C.reset} `;
|
|
96
|
+
const sepWidth = visibleWidth(PANEL_BG + separator.replace(/\x1b\[0m/g, PANEL_RST));
|
|
97
|
+
const totalSep = sepWidth * (groups.length - 1);
|
|
98
|
+
const available = width - indent - totalContent - totalSep;
|
|
99
|
+
const gapSize = groups.length > 1 ? Math.max(1, Math.floor(available / (groups.length - 1))) : 0;
|
|
100
|
+
const extra = groups.length > 1 ? available - gapSize * (groups.length - 1) : 0;
|
|
101
|
+
let line = ' '.repeat(indent);
|
|
102
|
+
for (let i = 0; i < groups.length; i++) {
|
|
103
|
+
line += groups[i];
|
|
104
|
+
if (i < groups.length - 1) {
|
|
105
|
+
const gap = gapSize + (i < extra ? 1 : 0);
|
|
106
|
+
line += separator + ' '.repeat(Math.max(0, gap));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return panelLine(line, width);
|
|
110
|
+
}
|
|
96
111
|
function panelLine(content, width) {
|
|
97
112
|
const withBg = PANEL_BG + content.replace(/\x1b\[0m/g, PANEL_RST);
|
|
98
113
|
const pad = Math.max(0, width - visibleWidth(withBg));
|
|
@@ -105,10 +120,8 @@ function panelBar(width, ch = "─") {
|
|
|
105
120
|
/** Token-count formatter: M at/above 1e6, k at/above 1e3, raw below.
|
|
106
121
|
* 5,472,700 → "5.5mil", 24,100 → "24.1k", 142 → "142". */
|
|
107
122
|
function fmtTokens(x) {
|
|
108
|
-
return x >= 1_000_000
|
|
109
|
-
? `${(x /
|
|
110
|
-
: x >= 1000
|
|
111
|
-
? `${(x / 1000).toFixed(1)}k`
|
|
123
|
+
return x >= 1_000_000 ? `${(x / 1_000_000).toFixed(1)}mil`
|
|
124
|
+
: x >= 1000 ? `${(x / 1000).toFixed(1)}k`
|
|
112
125
|
: `${Math.round(x)}`;
|
|
113
126
|
}
|
|
114
127
|
/** Retro gradient bar — `w` cells shaded by fill position (green→amber→red).
|
|
@@ -123,10 +136,8 @@ function ramp(pct, w = 12) {
|
|
|
123
136
|
for (let i = 0; i < full; i++)
|
|
124
137
|
out += (i / w < 0.6 ? C.green : i / w < 0.85 ? C.amber : C.red) + "█";
|
|
125
138
|
if (fracCell)
|
|
126
|
-
out +=
|
|
127
|
-
|
|
128
|
-
out +=
|
|
129
|
-
C.dim + "░".repeat(Math.max(0, w - full - (fracCell ? 1 : 0))) + C.reset;
|
|
139
|
+
out += (full / w < 0.6 ? C.green : full / w < 0.85 ? C.amber : C.red) + fracCell;
|
|
140
|
+
out += C.dim + "░".repeat(Math.max(0, w - full - (fracCell ? 1 : 0))) + C.reset;
|
|
130
141
|
return out;
|
|
131
142
|
}
|
|
132
143
|
/** Human "time since" string from a millisecond delta (or null → "never"). */
|
|
@@ -257,9 +268,7 @@ export class MegaRuntime {
|
|
|
257
268
|
* context event, or a `custom` tier with no tierPct). Always finite + in [0,1].
|
|
258
269
|
*/
|
|
259
270
|
get pressure() {
|
|
260
|
-
if (this.lastCtxWindow > 0 &&
|
|
261
|
-
this.config.tierPct != null &&
|
|
262
|
-
this.lastCtxPercent != null) {
|
|
271
|
+
if (this.lastCtxWindow > 0 && this.config.tierPct != null && this.lastCtxPercent != null) {
|
|
263
272
|
// pressureFromPct(x) = x/100, and x = lastCtxPercent/tierPct, so this is
|
|
264
273
|
// exactly the intended lastCtxPercent/(tierPct*100) 0–1 ratio: at the
|
|
265
274
|
// fire point (lastCtxPercent == tierPct*100) pressure == 1.0, matching the
|
|
@@ -267,9 +276,7 @@ export class MegaRuntime {
|
|
|
267
276
|
// the band doesn't jump when a token-count vs percent-only event arrives.
|
|
268
277
|
return pressureFromPct(this.lastCtxPercent / this.config.tierPct);
|
|
269
278
|
}
|
|
270
|
-
if (this.lastCtxTokens != null &&
|
|
271
|
-
this.lastCtxTokens > 0 &&
|
|
272
|
-
this.config.thresholdTokens > 0) {
|
|
279
|
+
if (this.lastCtxTokens != null && this.lastCtxTokens > 0 && this.config.thresholdTokens > 0) {
|
|
273
280
|
return pressureRatio(this.lastCtxTokens, this.config.thresholdTokens);
|
|
274
281
|
}
|
|
275
282
|
return pressureFromPct(this.lastCtxPercent);
|
|
@@ -295,14 +302,8 @@ export class MegaRuntime {
|
|
|
295
302
|
}
|
|
296
303
|
constructor(config) {
|
|
297
304
|
this.config = config;
|
|
298
|
-
this.store = new VectorStore({
|
|
299
|
-
|
|
300
|
-
stateDir: config.stateDir,
|
|
301
|
-
});
|
|
302
|
-
this.logger = new Logger({
|
|
303
|
-
enabled: config.debug,
|
|
304
|
-
path: join(config.stateDir, "mega-compact.log"),
|
|
305
|
-
});
|
|
305
|
+
this.store = new VectorStore({ dedupSim: config.dedupSim, stateDir: config.stateDir });
|
|
306
|
+
this.logger = new Logger({ enabled: config.debug, path: join(config.stateDir, "mega-compact.log") });
|
|
306
307
|
this.dashboard = new Dashboard(config.stateDir);
|
|
307
308
|
this.currentStateDir = config.stateDir;
|
|
308
309
|
}
|
|
@@ -313,22 +314,14 @@ export class MegaRuntime {
|
|
|
313
314
|
* and events are fully isolated. Falls back to the global default outside git.
|
|
314
315
|
*/
|
|
315
316
|
bindRepo(cwd) {
|
|
316
|
-
const dir = cwd
|
|
317
|
-
|
|
318
|
-
: this.config.stateDir;
|
|
319
|
-
const key = cwd ? (resolveRepoRoot(cwd) ?? dir) : dir;
|
|
317
|
+
const dir = cwd ? repoStateDir(cwd, this.config.stateDir) : this.config.stateDir;
|
|
318
|
+
const key = cwd ? resolveRepoRoot(cwd) ?? dir : dir;
|
|
320
319
|
if (key === this.activeRepoRoot)
|
|
321
320
|
return dir;
|
|
322
321
|
this.activeRepoRoot = key;
|
|
323
322
|
this.currentStateDir = dir;
|
|
324
|
-
this.store = new VectorStore({
|
|
325
|
-
|
|
326
|
-
stateDir: dir,
|
|
327
|
-
});
|
|
328
|
-
this.logger = new Logger({
|
|
329
|
-
enabled: this.config.debug,
|
|
330
|
-
path: join(dir, "mega-compact.log"),
|
|
331
|
-
});
|
|
323
|
+
this.store = new VectorStore({ dedupSim: this.config.dedupSim, stateDir: dir });
|
|
324
|
+
this.logger = new Logger({ enabled: this.config.debug, path: join(dir, "mega-compact.log") });
|
|
332
325
|
this.dashboard = new Dashboard(dir);
|
|
333
326
|
// Aggregate this repo into the machine-wide index so the multi-repo
|
|
334
327
|
// dashboard (Summary / All-repos tabs) can show it alongside every other
|
|
@@ -338,7 +331,7 @@ export class MegaRuntime {
|
|
|
338
331
|
try {
|
|
339
332
|
const repo = this.store.repoStats();
|
|
340
333
|
const di = this.store.dataInvariant();
|
|
341
|
-
const root = key !== dir ? key :
|
|
334
|
+
const root = key !== dir ? key : resolveRepoRoot(cwd ?? dir) ?? dir;
|
|
342
335
|
upsertRepoRegistry({
|
|
343
336
|
repoRoot: root,
|
|
344
337
|
displayName: root.split(/[\\/]/).filter(Boolean).pop() ?? root,
|
|
@@ -378,9 +371,7 @@ export class MegaRuntime {
|
|
|
378
371
|
// armed lights at/above the REAL fire point: max(effectiveThresholdPct,
|
|
379
372
|
// fastGatePct). fastGatePct already equals tierPct*100 by default, but a
|
|
380
373
|
// MEGACOMPACT_FAST_GATE_PCT override can raise it, so we take the max.
|
|
381
|
-
const armed = this.lastCtxPercent != null &&
|
|
382
|
-
this.lastCtxPercent >=
|
|
383
|
-
Math.max(effectiveThresholdPct ?? 0, this.config.fastGatePct);
|
|
374
|
+
const armed = this.lastCtxPercent != null && this.lastCtxPercent >= Math.max(effectiveThresholdPct ?? 0, this.config.fastGatePct);
|
|
384
375
|
const ready = armed && (this.lastCtxTokens ?? 0) >= this.effectiveThreshold;
|
|
385
376
|
this.dashboard.snapshot({
|
|
386
377
|
version: 1,
|
|
@@ -410,32 +401,10 @@ export class MegaRuntime {
|
|
|
410
401
|
dedupSkips: this.rt.dedupSkips,
|
|
411
402
|
dedupAttempts: this.rt.dedupAttempts,
|
|
412
403
|
},
|
|
413
|
-
context: {
|
|
414
|
-
|
|
415
|
-
percent: this.lastCtxPercent,
|
|
416
|
-
contextWindow: this.lastCtxWindow,
|
|
417
|
-
},
|
|
418
|
-
trigger: {
|
|
419
|
-
armed,
|
|
420
|
-
ready,
|
|
421
|
-
currentTokens: this.lastCtxTokens,
|
|
422
|
-
thresholdTokens: this.effectiveThreshold,
|
|
423
|
-
fastGatePct: this.config.fastGatePct,
|
|
424
|
-
tierPct: this.config.tierPct,
|
|
425
|
-
effectiveThresholdPct,
|
|
426
|
-
},
|
|
404
|
+
context: { tokens: this.lastCtxTokens, percent: this.lastCtxPercent, contextWindow: this.lastCtxWindow },
|
|
405
|
+
trigger: { armed, ready, currentTokens: this.lastCtxTokens, thresholdTokens: this.effectiveThreshold, fastGatePct: this.config.fastGatePct, tierPct: this.config.tierPct, effectiveThresholdPct },
|
|
427
406
|
crew: { activeAgents: this.activeAgents, currentTurn: this.currentTurn },
|
|
428
|
-
store: {
|
|
429
|
-
checkpointCount: st.checkpointCount,
|
|
430
|
-
totalTokenEstimate: st.totalTokenEstimate,
|
|
431
|
-
originalTokens: st.originalTokens,
|
|
432
|
-
tokensSaved: this.rt.tokensSaved,
|
|
433
|
-
injectedCount: st.injectedCount,
|
|
434
|
-
dedupHitRate: st.dedupHitRate,
|
|
435
|
-
storageDedupRate: st.storageDedupRate,
|
|
436
|
-
dedupAttempts: st.dedupAttempts,
|
|
437
|
-
dedupCollapsed: st.dedupCollapsed,
|
|
438
|
-
},
|
|
407
|
+
store: { checkpointCount: st.checkpointCount, totalTokenEstimate: st.totalTokenEstimate, originalTokens: st.originalTokens, tokensSaved: this.rt.tokensSaved, injectedCount: st.injectedCount, dedupHitRate: st.dedupHitRate, storageDedupRate: st.storageDedupRate, dedupAttempts: st.dedupAttempts, dedupCollapsed: st.dedupCollapsed },
|
|
439
408
|
// Reconciled token accounting (single canonical formula, session + repo).
|
|
440
409
|
// Freed = In − Out; In = Freed + Out. session.Freed = rt.tokensSaved (incl.
|
|
441
410
|
// deduped-away originals); repo.Freed = repo.tokensSaved meta counter.
|
|
@@ -444,19 +413,14 @@ export class MegaRuntime {
|
|
|
444
413
|
tokensIn: this.rt.tokensSaved + st.totalTokenEstimate,
|
|
445
414
|
tokensOut: st.totalTokenEstimate,
|
|
446
415
|
tokensFreed: this.rt.tokensSaved,
|
|
447
|
-
compressionPct: this.rt.tokensSaved + st.totalTokenEstimate > 0
|
|
448
|
-
? this.rt.tokensSaved /
|
|
449
|
-
(this.rt.tokensSaved + st.totalTokenEstimate)
|
|
450
|
-
: 0,
|
|
416
|
+
compressionPct: (this.rt.tokensSaved + st.totalTokenEstimate) > 0 ? this.rt.tokensSaved / (this.rt.tokensSaved + st.totalTokenEstimate) : 0,
|
|
451
417
|
dedupPct: st.storageDedupRate,
|
|
452
418
|
},
|
|
453
419
|
repo: {
|
|
454
420
|
tokensIn: repo.tokensSaved + repo.totalTokenEstimate,
|
|
455
421
|
tokensOut: repo.totalTokenEstimate,
|
|
456
422
|
tokensFreed: repo.tokensSaved,
|
|
457
|
-
compressionPct: repo.tokensSaved + repo.totalTokenEstimate > 0
|
|
458
|
-
? repo.tokensSaved / (repo.tokensSaved + repo.totalTokenEstimate)
|
|
459
|
-
: 0,
|
|
423
|
+
compressionPct: (repo.tokensSaved + repo.totalTokenEstimate) > 0 ? repo.tokensSaved / (repo.tokensSaved + repo.totalTokenEstimate) : 0,
|
|
460
424
|
dedupPct: repo.storageDedupRate,
|
|
461
425
|
},
|
|
462
426
|
},
|
|
@@ -481,24 +445,14 @@ export class MegaRuntime {
|
|
|
481
445
|
// Live stats widget above the editor
|
|
482
446
|
if (ctx) {
|
|
483
447
|
// ── gather widget data (computed per snapshot, rendered per frame) ────
|
|
484
|
-
const tokStr = this.lastCtxTokens != null
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const maxStr = this.lastCtxWindow > 0
|
|
488
|
-
? `${Math.round(this.lastCtxWindow / 1000)}k`
|
|
489
|
-
: "?";
|
|
490
|
-
const pctStr = this.lastCtxPercent != null
|
|
491
|
-
? `${Math.round(this.lastCtxPercent * 10) / 10}%`
|
|
492
|
-
: "?%";
|
|
448
|
+
const tokStr = this.lastCtxTokens != null ? `${Math.round(this.lastCtxTokens / 1000)}k` : "?";
|
|
449
|
+
const maxStr = this.lastCtxWindow > 0 ? `${Math.round(this.lastCtxWindow / 1000)}k` : "?";
|
|
450
|
+
const pctStr = this.lastCtxPercent != null ? `${Math.round(this.lastCtxPercent * 10) / 10}%` : "?%";
|
|
493
451
|
// S24: the tier label is the LIVE pressure band (low/medium/high/ultra/
|
|
494
452
|
// mega), not the static env preset. It climbs as context fills.
|
|
495
453
|
const liveBand = this.pressureBand;
|
|
496
454
|
const tierLabel = `${C.bold}${liveBand}${C.reset}${C.gray}·${this.config.tier}${C.reset}`;
|
|
497
|
-
const triggerLabel = ready
|
|
498
|
-
? `${C.green}● ready${C.reset}`
|
|
499
|
-
: armed
|
|
500
|
-
? `${C.amber}◐ armed${C.reset}`
|
|
501
|
-
: `${C.gray}○ idle${C.reset}`;
|
|
455
|
+
const triggerLabel = ready ? `${C.green}● ready${C.reset}` : armed ? `${C.amber}◐ armed${C.reset}` : `${C.gray}○ idle${C.reset}`;
|
|
502
456
|
// Storage dedup rate is cumulative (store-wide, per-repo) and survives
|
|
503
457
|
// session resets. Always show a number (decimal for sub-10%).
|
|
504
458
|
const storageRate = st.storageDedupRate; // 0..1
|
|
@@ -523,55 +477,27 @@ export class MegaRuntime {
|
|
|
523
477
|
const ctxPct = this.lastCtxPercent != null ? this.lastCtxPercent / 100 : 0;
|
|
524
478
|
// Model + provider (S26 capture) for the header.
|
|
525
479
|
const modelName = modelSnap?.modelName ?? modelSnap?.modelId ?? "?";
|
|
526
|
-
const modelStr = modelSnap?.provider
|
|
527
|
-
? `${modelName}·${modelSnap.provider}`
|
|
528
|
-
: modelName;
|
|
480
|
+
const modelStr = modelSnap?.provider ? `${modelName}·${modelSnap.provider}` : modelName;
|
|
529
481
|
// Since-last-compact (ms; null until first compaction this session).
|
|
530
|
-
const sinceCompact = this.rt.lastCompactAt != null
|
|
531
|
-
? Date.now() - this.rt.lastCompactAt
|
|
532
|
-
: null;
|
|
482
|
+
const sinceCompact = this.rt.lastCompactAt != null ? Date.now() - this.rt.lastCompactAt : null;
|
|
533
483
|
// Memory store: embedder + compression ratio (original / stored).
|
|
534
484
|
const embedderName = this.embedderName();
|
|
535
485
|
const compRatio = st.originalTokens > 0 && st.totalTokenEstimate > 0
|
|
536
486
|
? st.originalTokens / st.totalTokenEstimate
|
|
537
|
-
: st.originalTokens > 0
|
|
538
|
-
? 1
|
|
539
|
-
: 0;
|
|
487
|
+
: (st.originalTokens > 0 ? 1 : 0);
|
|
540
488
|
const compStr = compRatio >= 1 ? `${compRatio.toFixed(1)}x` : "—";
|
|
541
489
|
// Cross-repo drift status (cached, read-only).
|
|
542
490
|
const driftStatus = this.driftStatus();
|
|
543
491
|
const agentsActive = this.activeAgents > 0;
|
|
544
492
|
this.widgetData = {
|
|
545
493
|
version: ownVersion(),
|
|
546
|
-
tierLabel,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
ctxPct,
|
|
552
|
-
chk: st.checkpointCount,
|
|
553
|
-
agentStr,
|
|
554
|
-
turnStr,
|
|
555
|
-
dedupStr,
|
|
556
|
-
sessIn,
|
|
557
|
-
sessKept,
|
|
558
|
-
sTxt,
|
|
559
|
-
repoIn,
|
|
560
|
-
repoKept,
|
|
561
|
-
rTxt,
|
|
562
|
-
repoChk: repo.checkpointCount,
|
|
563
|
-
repoSess: repo.sessionCount,
|
|
564
|
-
modelStr,
|
|
565
|
-
sinceCompact,
|
|
566
|
-
embedderName,
|
|
567
|
-
compStr,
|
|
568
|
-
driftStatus,
|
|
569
|
-
agentsActive,
|
|
494
|
+
tierLabel, triggerLabel, pctStr, tokStr, maxStr, ctxPct,
|
|
495
|
+
chk: st.checkpointCount, agentStr, turnStr, dedupStr,
|
|
496
|
+
sessIn, sessKept, sTxt, repoIn, repoKept, rTxt,
|
|
497
|
+
repoChk: repo.checkpointCount, repoSess: repo.sessionCount,
|
|
498
|
+
modelStr, sinceCompact, embedderName, compStr, driftStatus, agentsActive,
|
|
570
499
|
fresh: Date.now() - this.lastActivityAt < 4000,
|
|
571
|
-
ticker: this.ticker,
|
|
572
|
-
lastWhy: this.lastWhy,
|
|
573
|
-
tierTrace: this.tierTrace,
|
|
574
|
-
pulsing: this.pulsing,
|
|
500
|
+
ticker: this.ticker, lastWhy: this.lastWhy, tierTrace: this.tierTrace, pulsing: this.pulsing,
|
|
575
501
|
};
|
|
576
502
|
// Auto-fit: register a factory so pi re-renders the panel at the REAL
|
|
577
503
|
// terminal width every frame (tui.columns), instead of guessing with
|
|
@@ -594,24 +520,31 @@ export class MegaRuntime {
|
|
|
594
520
|
buildWidgetLines(width) {
|
|
595
521
|
const wd = this.widgetData;
|
|
596
522
|
if (!wd) {
|
|
597
|
-
return [
|
|
598
|
-
panelBar(width, "─"),
|
|
599
|
-
panelLine(" mega-compact: warming up…", width),
|
|
600
|
-
panelBar(width, "─"),
|
|
601
|
-
];
|
|
523
|
+
return [panelBar(width, "─"), panelLine(" mega-compact: warming up…", width), panelBar(width, "─")];
|
|
602
524
|
}
|
|
603
|
-
const pulse = wd.pulsing
|
|
604
|
-
? `${C.cyan}${PULSE[Math.floor(Date.now() / 250) % PULSE.length]}${C.reset} `
|
|
605
|
-
: "";
|
|
525
|
+
const pulse = wd.pulsing ? `${C.cyan}${PULSE[Math.floor(Date.now() / 250) % PULSE.length]}${C.reset} ` : "";
|
|
606
526
|
const lines = [
|
|
607
527
|
// top border
|
|
608
528
|
panelBar(width, "─"),
|
|
609
529
|
// L1 — header: tier + ctx bar + pct/tokens + status + model + chk + agents/turn
|
|
610
|
-
|
|
530
|
+
spreadGroups(width, [
|
|
531
|
+
`${C.amber}⚡ ${wd.tierLabel}${C.reset} v${C.bold}${wd.version}${C.reset} ${ramp(wd.ctxPct, 20)} ${C.bold}${wd.pctStr}${C.reset} ${wd.tokStr}/${wd.maxStr}`,
|
|
532
|
+
wd.triggerLabel,
|
|
533
|
+
`${C.cyan}${wd.modelStr}${C.reset}`,
|
|
534
|
+
`${wd.chk} chk${wd.agentStr}${wd.turnStr}`,
|
|
535
|
+
]),
|
|
611
536
|
// L2 — savings reconciled (session + all-time)
|
|
612
|
-
|
|
537
|
+
spreadGroups(width, [
|
|
538
|
+
`${C.magenta}dup ${wd.dedupStr}${C.reset}`,
|
|
539
|
+
`${C.gray}sess${C.reset} ${fmtTokens(wd.sessIn)}→${fmtTokens(wd.sessKept)} kept ${C.green}(${wd.sTxt}% freed)${C.reset} · ${C.gray}all-time${C.reset} ${fmtTokens(wd.repoIn)}→${fmtTokens(wd.repoKept)} kept ${C.blue}(${wd.rTxt}% freed)${C.reset}`,
|
|
540
|
+
`${wd.repoChk} chk/${wd.repoSess} sess`,
|
|
541
|
+
]),
|
|
613
542
|
// L3 — memory store + compression + drift + since-compact (NEW)
|
|
614
|
-
|
|
543
|
+
spreadGroups(width, [
|
|
544
|
+
`${C.gray}mem${C.reset} ${wd.embedderName} · ${wd.chk} chunks · ${C.blue}comp ${wd.compStr}${C.reset}`,
|
|
545
|
+
`${C.gray}drift${C.reset} ${wd.driftStatus === "ok" ? C.green : C.amber}${wd.driftStatus}${C.reset}`,
|
|
546
|
+
`${C.gray}compact${C.reset} ${sinceCompactStr(wd.sinceCompact)}`,
|
|
547
|
+
]),
|
|
615
548
|
];
|
|
616
549
|
// L4 — agents block (S27, count + status; per-agent tokens gated on P0)
|
|
617
550
|
if (wd.agentsActive) {
|
|
@@ -626,9 +559,7 @@ export class MegaRuntime {
|
|
|
626
559
|
const idx = wd.ticker.length - 1 - (step % wd.ticker.length);
|
|
627
560
|
const head = wd.ticker[idx].text;
|
|
628
561
|
const why = wd.lastWhy ? ` ${C.gray}· ${wd.lastWhy}${C.reset}` : "";
|
|
629
|
-
const more = wd.ticker.length > 1
|
|
630
|
-
? ` ${C.dim}(+${wd.ticker.length - 1} more)${C.reset}`
|
|
631
|
-
: "";
|
|
562
|
+
const more = wd.ticker.length > 1 ? ` ${C.dim}(+${wd.ticker.length - 1} more)${C.reset}` : "";
|
|
632
563
|
lines.push(panelLine(` ${wd.fresh ? C.teal : C.dim}${head}${why}${more}${C.reset}`, width));
|
|
633
564
|
}
|
|
634
565
|
else if (wd.pulsing) {
|
|
@@ -642,8 +573,7 @@ export class MegaRuntime {
|
|
|
642
573
|
embedderName() {
|
|
643
574
|
// MINILM_EMBEDDER flag lives in src/config/dedup.ts; read the same env var
|
|
644
575
|
// the embedder factory uses so the label matches what's actually running.
|
|
645
|
-
return process.env.MEGACOMPACT_MINILM === "true" ||
|
|
646
|
-
process.env.MEGACOMPACT_MINILM === "1"
|
|
576
|
+
return process.env.MEGACOMPACT_MINILM === "true" || process.env.MEGACOMPACT_MINILM === "1"
|
|
647
577
|
? "MiniLM"
|
|
648
578
|
: "Trigram";
|
|
649
579
|
}
|
|
@@ -703,18 +633,13 @@ export class MegaRuntime {
|
|
|
703
633
|
this.appendEvent("captureModel:no-model", { cwd: ctx.cwd });
|
|
704
634
|
return;
|
|
705
635
|
}
|
|
706
|
-
if (this.currentModel &&
|
|
707
|
-
this.currentModel.modelId === m.id &&
|
|
708
|
-
this.currentModel.provider === m.provider)
|
|
636
|
+
if (this.currentModel && this.currentModel.modelId === m.id && this.currentModel.provider === m.provider)
|
|
709
637
|
return;
|
|
710
638
|
let providerName = null;
|
|
711
639
|
try {
|
|
712
|
-
providerName =
|
|
713
|
-
ctx.modelRegistry?.getProviderDisplayName(m.provider) ?? null;
|
|
714
|
-
}
|
|
715
|
-
catch {
|
|
716
|
-
/* optional */
|
|
640
|
+
providerName = ctx.modelRegistry?.getProviderDisplayName(m.provider) ?? null;
|
|
717
641
|
}
|
|
642
|
+
catch { /* optional */ }
|
|
718
643
|
const snap = {
|
|
719
644
|
provider: m.provider,
|
|
720
645
|
providerName,
|
|
@@ -736,18 +661,14 @@ export class MegaRuntime {
|
|
|
736
661
|
try {
|
|
737
662
|
recordModelSnapshot(repo, snap, this.currentStateDir);
|
|
738
663
|
this.appendEvent("captureModel:recorded", {
|
|
739
|
-
repo,
|
|
740
|
-
|
|
741
|
-
provider: snap.provider,
|
|
742
|
-
inputRate: snap.inputRate,
|
|
743
|
-
outputRate: snap.outputRate,
|
|
664
|
+
repo, modelId: snap.modelId, provider: snap.provider,
|
|
665
|
+
inputRate: snap.inputRate, outputRate: snap.outputRate,
|
|
744
666
|
});
|
|
745
667
|
}
|
|
746
668
|
catch (e) {
|
|
747
669
|
this.diagCaptureModelFails++;
|
|
748
670
|
this.appendEvent("captureModel:record-failed", {
|
|
749
|
-
repo,
|
|
750
|
-
modelId: snap.modelId,
|
|
671
|
+
repo, modelId: snap.modelId,
|
|
751
672
|
error: e instanceof Error ? e.message : String(e),
|
|
752
673
|
stack: e instanceof Error ? e.stack : undefined,
|
|
753
674
|
});
|
|
@@ -768,8 +689,7 @@ export class MegaRuntime {
|
|
|
768
689
|
}
|
|
769
690
|
catch (e) {
|
|
770
691
|
this.appendEvent("captureModel:index-record-failed", {
|
|
771
|
-
repo,
|
|
772
|
-
modelId: snap.modelId,
|
|
692
|
+
repo, modelId: snap.modelId,
|
|
773
693
|
error: e instanceof Error ? e.message : String(e),
|
|
774
694
|
});
|
|
775
695
|
}
|
|
@@ -785,9 +705,7 @@ export class MegaRuntime {
|
|
|
785
705
|
mkdirSync(this.currentStateDir, { recursive: true });
|
|
786
706
|
appendFileSync(join(this.currentStateDir, "events.log"), JSON.stringify({ ts: Date.now(), event, ...fields }) + "\n");
|
|
787
707
|
}
|
|
788
|
-
catch {
|
|
789
|
-
/* non-fatal */
|
|
790
|
-
}
|
|
708
|
+
catch { /* non-fatal */ }
|
|
791
709
|
}
|
|
792
710
|
/** S21: state dir of the currently bound repo (where memories live). */
|
|
793
711
|
getStateDir() {
|
|
@@ -797,13 +715,10 @@ export class MegaRuntime {
|
|
|
797
715
|
makeTierCallback(ctx) {
|
|
798
716
|
const order = ["L0", "L1", "L2", "new"];
|
|
799
717
|
const seen = new Map();
|
|
800
|
-
const glyph = (status) => status === "deduped"
|
|
801
|
-
? `${C.
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
: status === "scanning"
|
|
805
|
-
? `${C.amber}…${C.reset}`
|
|
806
|
-
: `${C.cyan}●${C.reset}`;
|
|
718
|
+
const glyph = (status) => status === "deduped" ? `${C.green}✓${C.reset}` :
|
|
719
|
+
status === "passed" ? `${C.dim}○${C.reset}` :
|
|
720
|
+
status === "scanning" ? `${C.amber}…${C.reset}` :
|
|
721
|
+
`${C.cyan}●${C.reset}`;
|
|
807
722
|
return (ev) => {
|
|
808
723
|
const label = ev.tier === "new"
|
|
809
724
|
? `${C.cyan}stored${C.reset}`
|
|
@@ -820,9 +735,7 @@ export class MegaRuntime {
|
|
|
820
735
|
try {
|
|
821
736
|
this.snapshot(ctx);
|
|
822
737
|
}
|
|
823
|
-
catch {
|
|
824
|
-
/* non-fatal */
|
|
825
|
-
}
|
|
738
|
+
catch { /* non-fatal */ }
|
|
826
739
|
};
|
|
827
740
|
}
|
|
828
741
|
// Phase 3 — recall/activity ticker ring buffer.
|