pi-mega-compact 0.4.14 → 0.4.16
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/dashboard-server.js +30 -9
- package/dist/extensions/mega-commands.js +223 -0
- package/dist/extensions/mega-compact.js +19 -1073
- 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/dashboard-server.ts +30 -9
- package/extensions/mega-commands.ts +250 -0
- package/extensions/mega-compact.test.ts +30 -0
- package/extensions/mega-compact.ts +20 -1214
- 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
|
@@ -69,6 +69,15 @@ function dashboardHtml(tierName) {
|
|
|
69
69
|
.card.safe h2 { color: #3fb950; }
|
|
70
70
|
.safe-note { font-size: 12px; color: #8b949e; margin: 12px 0 0; line-height: 1.5; }
|
|
71
71
|
.value.ok { color: #3fb950; }
|
|
72
|
+
.label {
|
|
73
|
+
cursor: help;
|
|
74
|
+
border-bottom: 1px dotted #484f58;
|
|
75
|
+
}
|
|
76
|
+
.card.legend { grid-column: 1 / -1; }
|
|
77
|
+
.legend-list { margin: 0; padding-left: 18px; color: #c9d1d9; }
|
|
78
|
+
.legend-list li { margin-bottom: 8px; line-height: 1.5; }
|
|
79
|
+
.legend-list b { color: #f0f6fc; }
|
|
80
|
+
.legend-note { font-size: 12px; color: #8b949e; margin: 12px 0 0; font-style: italic; }
|
|
72
81
|
.card h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .5px; color: #8b949e; margin-bottom: 12px; font-weight: 600; }
|
|
73
82
|
.meter-track { background: #21262d; border-radius: 4px; height: 20px; overflow: hidden; margin: 8px 0; }
|
|
74
83
|
.meter-fill { height: 100%; border-radius: 4px; transition: width .6s ease; min-width: 2px; }
|
|
@@ -126,15 +135,15 @@ function dashboardHtml(tierName) {
|
|
|
126
135
|
<div class="card">
|
|
127
136
|
<h2>Vector Store</h2>
|
|
128
137
|
<div class="stat-grid">
|
|
129
|
-
<span class="label">Checkpoints</span><span class="value" id="st-count">0</span>
|
|
130
|
-
<span class="label">Tokens Stored</span><span class="value" id="st-tokens">0</span>
|
|
131
|
-
<span class="label">Original Tokens</span><span class="value" id="st-orig">0</span>
|
|
132
|
-
<span class="label">Tokens Saved</span><span class="value" id="st-saved">0</span>
|
|
133
|
-
<span class="label">Injected</span><span class="value" id="st-injected">0</span>
|
|
134
|
-
<span class="label">
|
|
135
|
-
<span class="label">Storage Dedup</span><span class="value" id="st-sdedup">0%</span>
|
|
136
|
-
<span class="label">Collapsed</span><span class="value" id="st-collapsed">0</span>
|
|
137
|
-
<span class="label">Last ID</span><span class="value" id="st-lastid">—</span>
|
|
138
|
+
<span class="label" title="A saved summary of a chunk of your conversation that was compacted to free up space.">Checkpoints</span><span class="value" id="st-count">0</span>
|
|
139
|
+
<span class="label" title="How much conversation we are currently holding as compact summaries (the 'memory' this extension keeps). Smaller is better.">Tokens Stored</span><span class="value" id="st-tokens">0</span>
|
|
140
|
+
<span class="label" title="Total size of the original conversation text before it was compacted.">Original Tokens</span><span class="value" id="st-orig">0</span>
|
|
141
|
+
<span class="label" title="How much conversation space we have freed up for you (original size minus the compact summary we kept).">Tokens Saved</span><span class="value" id="st-saved">0</span>
|
|
142
|
+
<span class="label" title="How many times old context was automatically brought back into the conversation because it was relevant to what you were doing.">Injected</span><span class="value" id="st-injected">0</span>
|
|
143
|
+
<span class="label" title="Of the times we recalled old context, how often it was actually on-topic.">Recall Relevance</span><span class="value" id="st-dedup">0%</span>
|
|
144
|
+
<span class="label" title="How often new content matched something we already had, so we skipped storing a duplicate copy. Higher = less wasted space.">Storage Dedup</span><span class="value" id="st-sdedup">0%</span>
|
|
145
|
+
<span class="label" title="How many duplicate chunks we collapsed into one instead of storing separately.">Collapsed</span><span class="value" id="st-collapsed">0</span>
|
|
146
|
+
<span class="label" title="The ID of the most recent saved checkpoint.">Last ID</span><span class="value" id="st-lastid">—</span>
|
|
138
147
|
</div>
|
|
139
148
|
</div>
|
|
140
149
|
<div class="card">
|
|
@@ -177,6 +186,18 @@ function dashboardHtml(tierName) {
|
|
|
177
186
|
<span class="label">Status</span><span class="value" id="cr-status">idle</span>
|
|
178
187
|
</div>
|
|
179
188
|
</div>
|
|
189
|
+
<div class="card legend">
|
|
190
|
+
<h2>What these numbers mean</h2>
|
|
191
|
+
<ul class="legend-list">
|
|
192
|
+
<li><b>Tokens saved</b> — conversation space this extension has freed up for you (it compacted old text into short summaries).</li>
|
|
193
|
+
<li><b>Tokens stored</b> — how much "memory" (compact summaries) the extension is currently holding for this repo.</li>
|
|
194
|
+
<li><b>Injected</b> — times old context was automatically pasted back in because it was relevant to your current task.</li>
|
|
195
|
+
<li><b>Recall relevance</b> — of those, how often the recalled context was actually on-topic.</li>
|
|
196
|
+
<li><b>Storage dedup</b> — how often new content matched something already saved, so a duplicate copy was skipped (saves space).</li>
|
|
197
|
+
<li><b>Data safety</b> — every compacted region is kept verbatim (compressed). Nothing is permanently deleted; you can restore any of it.</li>
|
|
198
|
+
</ul>
|
|
199
|
+
<p class="legend-note">Hover any label above for a quick explanation.</p>
|
|
200
|
+
</div>
|
|
180
201
|
</div>
|
|
181
202
|
|
|
182
203
|
<div class="events">
|
|
@@ -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
|
+
}
|