pi-mega-compact 0.20.30 → 0.20.32

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.
@@ -50,8 +50,8 @@ export const SETTINGS = [
50
50
  boolFlag("MEGACOMPACT_MEMORY_GRAPH", "Memory Graph", "Dashboard-oriented memory graph traversal", true),
51
51
  boolFlag("MEGACOMPACT_HYDE", "HyDE", "Generate hypothetical answer via LLM, embed it, RRF-fuse", true, true),
52
52
  boolFlag("MEGACOMPACT_NEW_UI", "New Dashboard UI", "Tailwind + shadcn visual design (sidebar, glass panels)", true),
53
- boolDirect("MEGACOMPACT_MESSAGE_SEPARATION", "Message Separation (P2)", "PLAN_V2: split conversation thread from tool results to grow stable cache prefix", false),
54
- boolDirect("MEGACOMPACT_CACHE_STRIPING", "Cache Striping (P3)", "PLAN_V2: order stable context by stability score so durable chunks lead the prompt", false),
53
+ boolDirect("MEGACOMPACT_MESSAGE_SEPARATION", "Message Separation (P2)", "PLAN_V2: split conversation thread from tool results to grow stable cache prefix", true),
54
+ boolDirect("MEGACOMPACT_CACHE_STRIPING", "Cache Striping (P3)", "PLAN_V2: order stable context by stability score so durable chunks lead the prompt", true),
55
55
  ],
56
56
  },
57
57
  {
@@ -0,0 +1 @@
1
+ export {};
@@ -167,8 +167,11 @@ export function loadConfig() {
167
167
  recallMaxTokens: envFlag("MEGACOMPACT_RECALL_MAX_TOKENS", 1500),
168
168
  windowDedupe: envBool("MEGACOMPACT_WINDOW_DEDUPE", true),
169
169
  recallTailInject: envBool("MEGACOMPACT_RECALL_TAIL_INJECT", true),
170
- messageSeparation: envBool("MEGACOMPACT_MESSAGE_SEPARATION", false),
171
- cacheStriping: envBool("MEGACOMPACT_CACHE_STRIPING", false),
170
+ // PC-A: positive sprint flag, default ON. =0 byte-identical to the
171
+ // pre-change OFF state (single gate lives at the call site in tailResult.ts).
172
+ messageSeparation: envBool("MEGACOMPACT_MESSAGE_SEPARATION", true),
173
+ // positive sprint flag: default ON, =0 byte-identical to OFF
174
+ cacheStriping: envBool("MEGACOMPACT_CACHE_STRIPING", true),
172
175
  tuiWidget: envBool("MEGACOMPACT_TUI_WIDGET", true),
173
176
  ragQueryReformulation: envBool("MEGACOMPACT_QUERY_REFORMULATION", false),
174
177
  ragTieredRouter: envBool("MEGACOMPACT_TIERED_ROUTER", false),
@@ -12,8 +12,11 @@
12
12
  * 3 (thread: user/assistant turns) -> 4 (tool results at tail).
13
13
  *
14
14
  * Feature-gated by MEGACOMPACT_CACHE_STRIPING (default OFF).
15
- * MEGACOMPACT_MESSAGE_SEPARATION must also be ON for any layering to occur.
16
15
  * Flag-OFF = byte-identical to pre-sprint — returns messages unchanged.
16
+ *
17
+ * PC-A: buildSeparatedPrompt is PURE — the MEGACOMPACT_MESSAGE_SEPARATION gate
18
+ * lives at the single call site (tailResult.ts, config.messageSeparation),
19
+ * not inside this function.
17
20
  */
18
21
  import { openStore } from "../../src/store/sqlite/utils.js";
19
22
  import { getStateDir } from "../../src/store.js";
@@ -29,14 +32,11 @@ const TOPIC_SHIFT_THRESHOLD = 0.7;
29
32
  * Layer order: 0 (system) -> 1 (summary) -> 3 (thread: user/assistant turns) ->
30
33
  * 4 (tool results at tail).
31
34
  *
32
- * Feature gate: MEGACOMPACT_MESSAGE_SEPARATION env var. When OFF (default),
33
- * returns `messages` unchanged (byte-identical to pre-sprint).
35
+ * PURE function: the MEGACOMPACT_MESSAGE_SEPARATION gate moved to the single
36
+ * call site (tailResult.ts, config.messageSeparation) — this never reads env.
37
+ * When there is nothing to reorder, returns `messages` unchanged (byte-identical).
34
38
  */
35
39
  export function buildSeparatedPrompt(messages, _opts) {
36
- const flag = process.env.MEGACOMPACT_MESSAGE_SEPARATION;
37
- if (flag === "0" || flag === "false" || flag === undefined || flag === "") {
38
- return messages;
39
- }
40
40
  // pi's AgentMessage union has no "system" role — the system prompt lives in
41
41
  // AgentState.systemPrompt, separate from this array. The cache-relevant,
42
42
  // low-risk transformation is moving volatile tool results/executions to the
@@ -169,18 +169,12 @@ export function refreshStripeAssignments(stateDir, epochId, limit = DEFAULT_STRI
169
169
  * Build a cache-optimized prompt with 5 layers:
170
170
  * 0 (system) -> 1 (summary) -> 2 (cache stripes) -> 3 (thread) -> 4 (tool)
171
171
  *
172
- * Feature gate: MEGACOMPACT_CACHE_STRIPING (default OFF). When OFF, delegates
173
- * to buildSeparatedPrompt (byte-identical to Phase 2 behavior).
174
- *
175
- * When ON but MEGACOMPACT_MESSAGE_SEPARATION is OFF, also delegates to
176
- * buildSeparatedPrompt (which returns messages unchanged).
172
+ * Positive sprint flag driven by config.cacheStriping at the call site
173
+ * (tailResult.ts); this function is pure and never reads process.env.
174
+ * With flag ON but no stripe rows for the epoch, it returns the base
175
+ * separated prompt unchanged (byte-identical to buildSeparatedPrompt).
177
176
  */
178
177
  export function buildCacheOptimizedPrompt(messages, opts) {
179
- const flag = process.env.MEGACOMPACT_CACHE_STRIPING;
180
- if (flag === "0" || flag === "false" || flag === undefined || flag === "") {
181
- // Flag OFF: delegate to buildSeparatedPrompt (byte-identical).
182
- return buildSeparatedPrompt(messages, opts);
183
- }
184
178
  // Build the base 4-layer structure first.
185
179
  const base = buildSeparatedPrompt(messages, opts);
186
180
  // If base equals messages, separation is OFF — return unchanged.
@@ -126,13 +126,13 @@ export const SETTINGS: ReadonlyArray<SettingGroup> = [
126
126
  "MEGACOMPACT_MESSAGE_SEPARATION",
127
127
  "Message Separation (P2)",
128
128
  "PLAN_V2: split conversation thread from tool results to grow stable cache prefix",
129
- false,
129
+ true,
130
130
  ),
131
131
  boolDirect(
132
132
  "MEGACOMPACT_CACHE_STRIPING",
133
133
  "Cache Striping (P3)",
134
134
  "PLAN_V2: order stable context by stability score so durable chunks lead the prompt",
135
- false,
135
+ true,
136
136
  ),
137
137
  ],
138
138
  },
@@ -0,0 +1,181 @@
1
+ /**
2
+ * mega-config-types.ts — MegaConfig type-only declarations for the extension.
3
+ *
4
+ * Split out of mega-config.ts (delegate-shell) so the runtime barrel stays under
5
+ * the extensions/ soft line limit. Type-only file: no runtime code, no logic.
6
+ * `import type` keeps the only cross-reference (CompactTier) erased at build,
7
+ * so there is no runtime import cycle.
8
+ */
9
+ import type { CompactTier } from "./mega-config.js";
10
+
11
+ /**
12
+ * Resolved, frozen-at-load config. `tier` is the base compaction PRESET chosen
13
+ * by env (low/medium/high/ultra/mega) — it sets the threshold token budget and
14
+ * is NOT changed at runtime (the /mega-tier command was removed in S24). The
15
+ * *displayed* tier the user sees in the toolbar/dashboard is the LIVE pressure
16
+ * band (see MegaRuntime.pressureBand), which climbs low→mega as context fills.
17
+ */
18
+ export interface MegaConfig {
19
+ tier: CompactTier | "custom";
20
+ /**
21
+ * Compaction threshold as a fraction of the model context window (e.g. 0.70
22
+ * for "high"). null for `custom` (explicit MEGACOMPACT_THRESHOLD_TOKENS, which
23
+ * stays an ABSOLUTE token count, never percent-scaled).
24
+ */
25
+ tierPct: number | null;
26
+ thresholdTokens: number;
27
+ stateDir: string;
28
+ fastGatePct: number;
29
+ anchorUserMessages: number;
30
+ preserveRecent: number;
31
+ /** High-pressure floor for preserveRecent — when context is near the limit
32
+ * we compact deeper, but never below this (keeps recent turns for coherence). */
33
+ preserveRecentMin: number;
34
+ /** D.1: minimum context-growth percentage delta before re-compacting instead of
35
+ * replaying the cached trim (Default 50). Set via MEGACOMPACT_RECOMPACT_PCT_DELTA.*/
36
+ recompactPctDelta: number;
37
+ auto: boolean;
38
+ autoInline: boolean;
39
+ autoInlineK: number;
40
+ /** S28: auto-continue the agent after a max-output-token length stop by
41
+ * reusing the existing S16 resume-nudge. Default true. Off = silent (the
42
+ * prior behavior). PREVENT-PI-003: restart via user-role sendUserMessage. */
43
+ autoContinueLengthStop: boolean;
44
+ /** S38: max retries for transient errors (5xx/429/network/max-output-token
45
+ * text that is NOT a length stopReason — S28 owns those). Default 5.
46
+ * `0` disables all transient retries (reverts to S28-only). */
47
+ autoRetryTransientMax: number;
48
+ /** S38: max retries for permanent errors (auth/config/malformed). Default 1.
49
+ * `0` disables permanent-error retries. */
50
+ autoRetryPermanentMax: number;
51
+ /** S38.5: strict race-guard — 30s cooldown + deferred ctx.compact() re-check
52
+ * (closes the first-race-in-burst window). Default true. `false` reverts to
53
+ * the v0.7.4 synchronous 10s-cooldown behavior. */
54
+ raceGuardStrict: boolean;
55
+ /** S38.6: max consecutive errors before circuit-breaker trips (stops retrying).
56
+ * Default 10. When `errorRetryCount` exceeds this across multiple turns,
57
+ * the extension stops retrying until a successful turn resets it. */
58
+ maxConsecutiveErrors: number;
59
+ /** S38.7: hard-stop switch — when true, ALL error retries are disabled.
60
+ * Default false. Set via env to force S28-only behavior (length-stop continues
61
+ * only). */
62
+ errorRetryHardStop: boolean;
63
+ /** R1 (retry redesign): base unit (ms) for errorRetryBackoffMs(count) pacing.
64
+ * The schedule is base, 2*base, 4*base, 6*base (cap) — so the default 5000
65
+ * yields 5s/10s/20s/30s. errorRetryUntil is now GATING (previously it was
66
+ * documented as non-gating); a nudge cannot fire before errorRetryUntil
67
+ * elapses. */
68
+ errorRetryBackoffMs: number;
69
+ /** R2: session-global cap on total S38 nudges across ALL bursts. Hitting it
70
+ * is terminal for the session — the extension stops nudging entirely,
71
+ * independent of the per-burst max and the circuit breaker. Default 3.
72
+ * `0` disables (reverts to per-burst + circuit-breaker only). */
73
+ errorRetrySessionMax: number;
74
+ /** R3: consecutive identical error-text count at which a 'transient'
75
+ * classification is upgraded to 'poisoned-context' (the stateful repeat
76
+ * signal). Default 3. Raise to make the upgrade less aggressive. */
77
+ poisonedContextRepeatThreshold: number;
78
+ /** R10: consecutive transient errors at which a calm "provider outage"
79
+ * advisory is sent to the user (distinct from the poisoned /clear advise).
80
+ * Default 3. `0` disables the advisory entirely. */
81
+ providerOutageAdviseThreshold: number;
82
+ /** R13: when true (default), poisoned-context and provider-outage advisories
83
+ * are dashboard-only (events tab + log) — no user-visible message injection.
84
+ * When false, the legacy sendUserMessage path runs (byte-identical pre-R13). */
85
+ advisoryChannel: boolean;
86
+ /** S29: override the auto-compact fire point for tiered configs, as a
87
+ * fraction of the context window (e.g. 0.85). null = inherit the tier's
88
+ * tierPct (default; preserves existing fire points). The context-handler
89
+ * gate fires on context % (reliable), not token count (under-reported),
90
+ * so it catches the overshoot that causes max-output-token truncation.
91
+ * `custom` (tierPct null) ignores this — it keeps the absolute token gate. */
92
+ autoPctTrigger: number | null;
93
+ dedupSim: number;
94
+ /** RAPTOR hierarchical recall enabled (Fix D). Drives both live recall and
95
+ * the durable-trim summary source (root summary). */
96
+ raptorEnabled: boolean;
97
+ /** Legacy v0.4.28 behavior: auto-trigger calls ctx.compact() (which STOPS
98
+ * the agent). Default false — the S16 redesign uses the live context-event
99
+ * trim + pi native auto-compaction instead (compact and continue). Kept for
100
+ * one release as rollback. */
101
+ legacyDurableTrim: boolean;
102
+ /** S27: durable raw-transcript DB mirror (MEGACOMPACT_DB_MIRROR). When on,
103
+ * raw message bytes + checkpoint-epoch bookkeeping are appended to the
104
+ * SQLite store so a compacted window can be rehydrated locally instead of
105
+ * from the pi runtime transcript. Default OFF — additive, no behavior
106
+ * change until flipped on. legacyDurableTrim takes precedence (the legacy
107
+ * v0.4.28 ctx.compact() path does not emit the S27 mirror hook). */
108
+ dbMirror: boolean;
109
+ /** S49: isolated per-turn store (turns.db). Default ON. OFF = legacy main-db
110
+ * turn path (S48 behavior — byte-identical). Mirrors TurnsConfig.TURNS_DB_ENABLED. */
111
+ turnsDbEnabled: boolean;
112
+ /** S51: auto-categorizing wiki (k-means + TF-IDF over real embeddings). Default ON.
113
+ * Mirrors TurnsConfig.AUTO_WIKI_ENABLED. Rebuild fires every Nth compaction. */
114
+ autoWikiEnabled: boolean;
115
+ /** Cross-repo recall enabled (S17). Resume + /mega-recall --cross-repo can
116
+ * pull checkpoints from OTHER repos via the PGlite HNSW index. Default true. */
117
+ crossRepoEnabled: boolean;
118
+ /** Stricter cosine floor for cross-repo hits (S17). Default 0.90 (trigram) /
119
+ * tighter than same-repo so only genuinely-relevant cross-repo context is
120
+ * injected. */
121
+ crossRepoCosine: number;
122
+ /** Memory-RAG auto-review enabled (S20). Every memoryReviewInterval turns the
123
+ * conversation is auto-reviewed into durable add/replace/remove memories. */
124
+ memoryAutoReview: boolean;
125
+ /** Turn cadence for the auto-review scan (S20). Default 10. */
126
+ memoryReviewInterval: number;
127
+ /** Token ceiling for the re-injected recall block (Fix C). Recall stops
128
+ * adding checkpoints once the block would exceed this — bounds read-path
129
+ * token cost so it can never net-inflate the window. */
130
+ recallMaxTokens: number;
131
+ /** Inline-dedupe recalled checkpoints against the live window (Fix C): drop
132
+ * a hit whose summary is ≥ dedupSim similar to a live message — "dedupe on
133
+ * inline/read" so we never re-inject context already resident. */
134
+ windowDedupe: boolean;
135
+ /** S53: Recall Tail Injection — inject staged recall block as a user message at
136
+ * the tail of the view when auto is OFF AND no trim action is needed. Default ON
137
+ * (true). When false, restores the pre-sprint systemPrompt prepend behavior. */
138
+ recallTailInject: boolean;
139
+ /** A1 PLAN_V2 Phase 2: Message Separation — isolate user/assistant turns
140
+ * from volatile tool results so the prompt-cache prefix stays stable.
141
+ * PC-A: positive sprint flag, now default ON; flag-OFF (=0) is byte-identical
142
+ * to the pre-change OFF state. The single gate lives at the call site
143
+ * (tailResult.ts, config.messageSeparation), not inside buildSeparatedPrompt. */
144
+ messageSeparation: boolean;
145
+ /** P3: Cache-aware striping (PLAN_V2 Phase 3). Inserts stability-ordered
146
+ * cache stripes between summaries and thread. Default OFF. */
147
+ cacheStriping: boolean;
148
+ debug: boolean;
149
+ /** Master reconciliation: TUI shutdown widget (MEGACOMPACT_TUI_WIDGET=0 to disable). */
150
+ tuiWidget: boolean;
151
+ /** S57 B1: Query reformulation via embedding-neighbor keyword expansion. */
152
+ ragQueryReformulation: boolean;
153
+ /** S57 B2: Tiered recall router (L0 cache -> L1 FTS5 -> L2). */
154
+ ragTieredRouter: boolean;
155
+ /** S57 B3: Recall quality metrics (precision/recall scoring + logging). */
156
+ ragRecallMetrics: boolean;
157
+ /** S57 B4: Memory graph traversal (dashboard-oriented). */
158
+ ragMemoryGraph: boolean;
159
+ /** D1: Seed initial wiki topic model from live turns when no context_chunks exist yet. */
160
+ wikiSeedFromTurns: boolean;
161
+ /** D3 Source A: Include structural turn nodes in the memory graph (metadata only, no content). */
162
+ memoryGraphSeedTurns: boolean;
163
+ /** D3 Source B: Include raw_transcript content nodes in the memory graph (requires dbMirror). */
164
+ memoryGraphSeedTurnContent: boolean;
165
+ /** D3 Source C: Include memory review nodes in the memory graph. */
166
+ memoryGraphSeedMemories: boolean;
167
+ /** D3 edges: Stricter cosine floor for cross-type edges (e.g. turn↔checkpoint). */
168
+ memoryGraphCrossTypeThreshold: number;
169
+ /** D3 edges: Cosine floor for within-type semantic edges. */
170
+ memoryGraphWithinTypeThreshold: number;
171
+ /** v0.12: Context health monitoring (drift + output quality + cache poison). Default ON. */
172
+ contextHealth: boolean;
173
+ /** Sub-flag: drift detection (topic drift + error escalation + prefix instability). */
174
+ contextHealthDrift: boolean;
175
+ /** Sub-flag: output quality analysis (repetition, coherence, token salad). */
176
+ contextHealthOutputQuality: boolean;
177
+ /** Sub-flag: tri-layer KV cache poison validation. */
178
+ contextHealthCachePoison: boolean;
179
+ /** v0.12: KV cache poison mitigation — inject prefix break on mismatch. Default OFF. */
180
+ contextHealthMitigate: boolean;
181
+ }
@@ -10,6 +10,7 @@
10
10
  import { STATE_DIR_DEFAULT } from "../src/config.js";
11
11
  import { join } from "node:path";
12
12
  import { execSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: read-only `git rev-parse` to scope the store per-repo
13
+ import type { MegaConfig } from "./mega-config-types.js";
13
14
 
14
15
  /**
15
16
  * Named compaction tiers. A tier sets the token threshold at which the
@@ -40,176 +41,9 @@ export const TIER_PCT: Record<CompactTier, number> = {
40
41
  mega: 0.75,
41
42
  };
42
43
 
43
- /**
44
- * Resolved, frozen-at-load config. `tier` is the base compaction PRESET chosen
45
- * by env (low/medium/high/ultra/mega) it sets the threshold token budget and
46
- * is NOT changed at runtime (the /mega-tier command was removed in S24). The
47
- * *displayed* tier the user sees in the toolbar/dashboard is the LIVE pressure
48
- * band (see MegaRuntime.pressureBand), which climbs low→mega as context fills.
49
- */
50
- export interface MegaConfig {
51
- tier: CompactTier | "custom";
52
- /**
53
- * Compaction threshold as a fraction of the model context window (e.g. 0.70
54
- * for "high"). null for `custom` (explicit MEGACOMPACT_THRESHOLD_TOKENS, which
55
- * stays an ABSOLUTE token count, never percent-scaled).
56
- */
57
- tierPct: number | null;
58
- thresholdTokens: number;
59
- stateDir: string;
60
- fastGatePct: number;
61
- anchorUserMessages: number;
62
- preserveRecent: number;
63
- /** High-pressure floor for preserveRecent — when context is near the limit
64
- * we compact deeper, but never below this (keeps recent turns for coherence). */
65
- preserveRecentMin: number;
66
- /** D.1: minimum context-growth percentage delta before re-compacting instead of
67
- * replaying the cached trim (Default 50). Set via MEGACOMPACT_RECOMPACT_PCT_DELTA.*/
68
- recompactPctDelta: number;
69
- auto: boolean;
70
- autoInline: boolean;
71
- autoInlineK: number;
72
- /** S28: auto-continue the agent after a max-output-token length stop by
73
- * reusing the existing S16 resume-nudge. Default true. Off = silent (the
74
- * prior behavior). PREVENT-PI-003: restart via user-role sendUserMessage. */
75
- autoContinueLengthStop: boolean;
76
- /** S38: max retries for transient errors (5xx/429/network/max-output-token
77
- * text that is NOT a length stopReason — S28 owns those). Default 5.
78
- * `0` disables all transient retries (reverts to S28-only). */
79
- autoRetryTransientMax: number;
80
- /** S38: max retries for permanent errors (auth/config/malformed). Default 1.
81
- * `0` disables permanent-error retries. */
82
- autoRetryPermanentMax: number;
83
- /** S38.5: strict race-guard — 30s cooldown + deferred ctx.compact() re-check
84
- * (closes the first-race-in-burst window). Default true. `false` reverts to
85
- * the v0.7.4 synchronous 10s-cooldown behavior. */
86
- raceGuardStrict: boolean;
87
- /** S38.6: max consecutive errors before circuit-breaker trips (stops retrying).
88
- * Default 10. When `errorRetryCount` exceeds this across multiple turns,
89
- * the extension stops retrying until a successful turn resets it. */
90
- maxConsecutiveErrors: number;
91
- /** S38.7: hard-stop switch — when true, ALL error retries are disabled.
92
- * Default false. Set via env to force S28-only behavior (length-stop continues
93
- * only). */
94
- errorRetryHardStop: boolean;
95
- /** R1 (retry redesign): base unit (ms) for errorRetryBackoffMs(count) pacing.
96
- * The schedule is base, 2*base, 4*base, 6*base (cap) — so the default 5000
97
- * yields 5s/10s/20s/30s. errorRetryUntil is now GATING (previously it was
98
- * documented as non-gating); a nudge cannot fire before errorRetryUntil
99
- * elapses. */
100
- errorRetryBackoffMs: number;
101
- /** R2: session-global cap on total S38 nudges across ALL bursts. Hitting it
102
- * is terminal for the session — the extension stops nudging entirely,
103
- * independent of the per-burst max and the circuit breaker. Default 3.
104
- * `0` disables (reverts to per-burst + circuit-breaker only). */
105
- errorRetrySessionMax: number;
106
- /** R3: consecutive identical error-text count at which a 'transient'
107
- * classification is upgraded to 'poisoned-context' (the stateful repeat
108
- * signal). Default 3. Raise to make the upgrade less aggressive. */
109
- poisonedContextRepeatThreshold: number;
110
- /** R10: consecutive transient errors at which a calm "provider outage"
111
- * advisory is sent to the user (distinct from the poisoned /clear advise).
112
- * Default 3. `0` disables the advisory entirely. */
113
- providerOutageAdviseThreshold: number;
114
- /** R13: when true (default), poisoned-context and provider-outage advisories
115
- * are dashboard-only (events tab + log) — no user-visible message injection.
116
- * When false, the legacy sendUserMessage path runs (byte-identical pre-R13). */
117
- advisoryChannel: boolean;
118
- /** S29: override the auto-compact fire point for tiered configs, as a
119
- * fraction of the context window (e.g. 0.85). null = inherit the tier's
120
- * tierPct (default; preserves existing fire points). The context-handler
121
- * gate fires on context % (reliable), not token count (under-reported),
122
- * so it catches the overshoot that causes max-output-token truncation.
123
- * `custom` (tierPct null) ignores this — it keeps the absolute token gate. */
124
- autoPctTrigger: number | null;
125
- dedupSim: number;
126
- /** RAPTOR hierarchical recall enabled (Fix D). Drives both live recall and
127
- * the durable-trim summary source (root summary). */
128
- raptorEnabled: boolean;
129
- /** Legacy v0.4.28 behavior: auto-trigger calls ctx.compact() (which STOPS
130
- * the agent). Default false — the S16 redesign uses the live context-event
131
- * trim + pi native auto-compaction instead (compact and continue). Kept for
132
- * one release as rollback. */
133
- legacyDurableTrim: boolean;
134
- /** S27: durable raw-transcript DB mirror (MEGACOMPACT_DB_MIRROR). When on,
135
- * raw message bytes + checkpoint-epoch bookkeeping are appended to the
136
- * SQLite store so a compacted window can be rehydrated locally instead of
137
- * from the pi runtime transcript. Default OFF — additive, no behavior
138
- * change until flipped on. legacyDurableTrim takes precedence (the legacy
139
- * v0.4.28 ctx.compact() path does not emit the S27 mirror hook). */
140
- dbMirror: boolean;
141
- /** S49: isolated per-turn store (turns.db). Default ON. OFF = legacy main-db
142
- * turn path (S48 behavior — byte-identical). Mirrors TurnsConfig.TURNS_DB_ENABLED. */
143
- turnsDbEnabled: boolean;
144
- /** S51: auto-categorizing wiki (k-means + TF-IDF over real embeddings). Default ON.
145
- * Mirrors TurnsConfig.AUTO_WIKI_ENABLED. Rebuild fires every Nth compaction. */
146
- autoWikiEnabled: boolean;
147
- /** Cross-repo recall enabled (S17). Resume + /mega-recall --cross-repo can
148
- * pull checkpoints from OTHER repos via the PGlite HNSW index. Default true. */
149
- crossRepoEnabled: boolean;
150
- /** Stricter cosine floor for cross-repo hits (S17). Default 0.90 (trigram) /
151
- * tighter than same-repo so only genuinely-relevant cross-repo context is
152
- * injected. */
153
- crossRepoCosine: number;
154
- /** Memory-RAG auto-review enabled (S20). Every memoryReviewInterval turns the
155
- * conversation is auto-reviewed into durable add/replace/remove memories. */
156
- memoryAutoReview: boolean;
157
- /** Turn cadence for the auto-review scan (S20). Default 10. */
158
- memoryReviewInterval: number;
159
- /** Token ceiling for the re-injected recall block (Fix C). Recall stops
160
- * adding checkpoints once the block would exceed this — bounds read-path
161
- * token cost so it can never net-inflate the window. */
162
- recallMaxTokens: number;
163
- /** Inline-dedupe recalled checkpoints against the live window (Fix C): drop
164
- * a hit whose summary is ≥ dedupSim similar to a live message — "dedupe on
165
- * inline/read" so we never re-inject context already resident. */
166
- windowDedupe: boolean;
167
- /** S53: Recall Tail Injection — inject staged recall block as a user message at
168
- * the tail of the view when auto is OFF AND no trim action is needed. Default ON
169
- * (true). When false, restores the pre-sprint systemPrompt prepend behavior. */
170
- recallTailInject: boolean;
171
- /** A1 PLAN_V2 Phase 2: Message Separation — isolate user/assistant turns
172
- * from volatile tool results so the prompt-cache prefix stays stable.
173
- * Default OFF (flag-OFF = byte-identical pre-sprint). */
174
- messageSeparation: boolean;
175
- /** P3: Cache-aware striping (PLAN_V2 Phase 3). Inserts stability-ordered
176
- * cache stripes between summaries and thread. Default OFF. */
177
- cacheStriping: boolean;
178
- debug: boolean;
179
- /** Master reconciliation: TUI shutdown widget (MEGACOMPACT_TUI_WIDGET=0 to disable). */
180
- tuiWidget: boolean;
181
- /** S57 B1: Query reformulation via embedding-neighbor keyword expansion. */
182
- ragQueryReformulation: boolean;
183
- /** S57 B2: Tiered recall router (L0 cache -> L1 FTS5 -> L2). */
184
- ragTieredRouter: boolean;
185
- /** S57 B3: Recall quality metrics (precision/recall scoring + logging). */
186
- ragRecallMetrics: boolean;
187
- /** S57 B4: Memory graph traversal (dashboard-oriented). */
188
- ragMemoryGraph: boolean;
189
- /** D1: Seed initial wiki topic model from live turns when no context_chunks exist yet. */
190
- wikiSeedFromTurns: boolean;
191
- /** D3 Source A: Include structural turn nodes in the memory graph (metadata only, no content). */
192
- memoryGraphSeedTurns: boolean;
193
- /** D3 Source B: Include raw_transcript content nodes in the memory graph (requires dbMirror). */
194
- memoryGraphSeedTurnContent: boolean;
195
- /** D3 Source C: Include memory review nodes in the memory graph. */
196
- memoryGraphSeedMemories: boolean;
197
- /** D3 edges: Stricter cosine floor for cross-type edges (e.g. turn↔checkpoint). */
198
- memoryGraphCrossTypeThreshold: number;
199
- /** D3 edges: Cosine floor for within-type semantic edges. */
200
- memoryGraphWithinTypeThreshold: number;
201
- /** v0.12: Context health monitoring (drift + output quality + cache poison). Default ON. */
202
- contextHealth: boolean;
203
- /** Sub-flag: drift detection (topic drift + error escalation + prefix instability). */
204
- contextHealthDrift: boolean;
205
- /** Sub-flag: output quality analysis (repetition, coherence, token salad). */
206
- contextHealthOutputQuality: boolean;
207
- /** Sub-flag: tri-layer KV cache poison validation. */
208
- contextHealthCachePoison: boolean;
209
- /** v0.12: KV cache poison mitigation — inject prefix break on mismatch. Default OFF. */
210
- contextHealthMitigate: boolean;
211
- }
212
-
44
+ // MegaConfig type moved to mega-config-types.ts (delegate-shell split, PC-A)
45
+ // so this runtime config barrel stays under the 400-line soft limit.
46
+ export type { MegaConfig } from "./mega-config-types.js";
213
47
  function envFlag(name: string, fallback: number): number {
214
48
  const v = process.env[name];
215
49
  if (v == null || v === "") return fallback;
@@ -369,8 +203,11 @@ export function loadConfig(): MegaConfig {
369
203
  recallMaxTokens: envFlag("MEGACOMPACT_RECALL_MAX_TOKENS", 1500),
370
204
  windowDedupe: envBool("MEGACOMPACT_WINDOW_DEDUPE", true),
371
205
  recallTailInject: envBool("MEGACOMPACT_RECALL_TAIL_INJECT", true),
372
- messageSeparation: envBool("MEGACOMPACT_MESSAGE_SEPARATION", false),
373
- cacheStriping: envBool("MEGACOMPACT_CACHE_STRIPING", false),
206
+ // PC-A: positive sprint flag, default ON. =0 byte-identical to the
207
+ // pre-change OFF state (single gate lives at the call site in tailResult.ts).
208
+ messageSeparation: envBool("MEGACOMPACT_MESSAGE_SEPARATION", true),
209
+ // positive sprint flag: default ON, =0 byte-identical to OFF
210
+ cacheStriping: envBool("MEGACOMPACT_CACHE_STRIPING", true),
374
211
  tuiWidget: envBool("MEGACOMPACT_TUI_WIDGET", true),
375
212
  ragQueryReformulation: envBool("MEGACOMPACT_QUERY_REFORMULATION", false),
376
213
  ragTieredRouter: envBool("MEGACOMPACT_TIERED_ROUTER", false),
@@ -12,8 +12,11 @@
12
12
  * 3 (thread: user/assistant turns) -> 4 (tool results at tail).
13
13
  *
14
14
  * Feature-gated by MEGACOMPACT_CACHE_STRIPING (default OFF).
15
- * MEGACOMPACT_MESSAGE_SEPARATION must also be ON for any layering to occur.
16
15
  * Flag-OFF = byte-identical to pre-sprint — returns messages unchanged.
16
+ *
17
+ * PC-A: buildSeparatedPrompt is PURE — the MEGACOMPACT_MESSAGE_SEPARATION gate
18
+ * lives at the single call site (tailResult.ts, config.messageSeparation),
19
+ * not inside this function.
17
20
  */
18
21
 
19
22
  import type { AgentMessage } from "@earendil-works/pi-agent-core";
@@ -61,18 +64,14 @@ const TOPIC_SHIFT_THRESHOLD = 0.7;
61
64
  * Layer order: 0 (system) -> 1 (summary) -> 3 (thread: user/assistant turns) ->
62
65
  * 4 (tool results at tail).
63
66
  *
64
- * Feature gate: MEGACOMPACT_MESSAGE_SEPARATION env var. When OFF (default),
65
- * returns `messages` unchanged (byte-identical to pre-sprint).
67
+ * PURE function: the MEGACOMPACT_MESSAGE_SEPARATION gate moved to the single
68
+ * call site (tailResult.ts, config.messageSeparation) — this never reads env.
69
+ * When there is nothing to reorder, returns `messages` unchanged (byte-identical).
66
70
  */
67
71
  export function buildSeparatedPrompt(
68
72
  messages: AgentMessage[],
69
73
  _opts?: SeparatedPromptOptions,
70
74
  ): AgentMessage[] {
71
- const flag = process.env.MEGACOMPACT_MESSAGE_SEPARATION;
72
- if (flag === "0" || flag === "false" || flag === undefined || flag === "") {
73
- return messages;
74
- }
75
-
76
75
  // pi's AgentMessage union has no "system" role — the system prompt lives in
77
76
  // AgentState.systemPrompt, separate from this array. The cache-relevant,
78
77
  // low-risk transformation is moving volatile tool results/executions to the
@@ -237,22 +236,15 @@ export function refreshStripeAssignments(
237
236
  * Build a cache-optimized prompt with 5 layers:
238
237
  * 0 (system) -> 1 (summary) -> 2 (cache stripes) -> 3 (thread) -> 4 (tool)
239
238
  *
240
- * Feature gate: MEGACOMPACT_CACHE_STRIPING (default OFF). When OFF, delegates
241
- * to buildSeparatedPrompt (byte-identical to Phase 2 behavior).
242
- *
243
- * When ON but MEGACOMPACT_MESSAGE_SEPARATION is OFF, also delegates to
244
- * buildSeparatedPrompt (which returns messages unchanged).
239
+ * Positive sprint flag driven by config.cacheStriping at the call site
240
+ * (tailResult.ts); this function is pure and never reads process.env.
241
+ * With flag ON but no stripe rows for the epoch, it returns the base
242
+ * separated prompt unchanged (byte-identical to buildSeparatedPrompt).
245
243
  */
246
244
  export function buildCacheOptimizedPrompt(
247
245
  messages: AgentMessage[],
248
246
  opts?: SeparatedPromptOptions,
249
247
  ): AgentMessage[] {
250
- const flag = process.env.MEGACOMPACT_CACHE_STRIPING;
251
- if (flag === "0" || flag === "false" || flag === undefined || flag === "") {
252
- // Flag OFF: delegate to buildSeparatedPrompt (byte-identical).
253
- return buildSeparatedPrompt(messages, opts);
254
- }
255
-
256
248
  // Build the base 4-layer structure first.
257
249
  const base = buildSeparatedPrompt(messages, opts);
258
250
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.20.30",
3
+ "version": "0.20.32",
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-3-Clause",