@mnemom/mnemom 0.17.22 → 0.17.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -15
- package/dist/commands/agent.d.ts +13 -4
- package/dist/commands/agent.js +23 -10
- package/dist/commands/experimental.js +8 -1
- package/dist/index.js +8 -24
- package/dist/lib/agent.d.ts +30 -17
- package/dist/lib/agent.js +42 -30
- package/dist/lib/experimental.d.ts +13 -10
- package/dist/lib/experimental.js +19 -38
- package/dist/lib/launcher-config.d.ts +5 -6
- package/dist/lib/launcher-config.js +4 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,22 +193,33 @@ which request is a compaction (a gateway that does not read them ignores them).
|
|
|
193
193
|
never sets or changes your own auto-compaction settings (`CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`,
|
|
194
194
|
`CLAUDE_CODE_AUTO_COMPACT_WINDOW`, or `autoCompactWindow` in settings.json).
|
|
195
195
|
|
|
196
|
-
**
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
`x-mnemom-session-config-dropped`) and the session behaves
|
|
204
|
-
|
|
196
|
+
**Compaction intercept: on by default (since 0.17.23).** Every launch sends
|
|
197
|
+
`GATEWAY_USAGE_REAL_SIZE=on` and `GATEWAY_COMPACTION_INTERCEPT=on` in the per-session config
|
|
198
|
+
header, asking the gateway to report the real context size (so Claude Code compacts at its own
|
|
199
|
+
threshold) and to answer that compaction at once from its fold instead of a blocking model call.
|
|
200
|
+
This matches the production gateway cell's own default, so the header mainly makes the setting
|
|
201
|
+
explicit and keeps every cell consistent; the launch banner shows it as
|
|
202
|
+
`compaction: intercept on (gateway)`. A gateway without the companion support drops both keys
|
|
203
|
+
(they are echoed back in `x-mnemom-session-config-dropped`) and the session behaves as before.
|
|
204
|
+
|
|
205
|
+
It used to be experimental (`mnemom experimental enable compaction-intercept`); that command is
|
|
206
|
+
now a harmless no-op that says so. To turn it off, use any of:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
mnemom agent my-task --no-compaction-intercept # this launch only
|
|
210
|
+
mnemom agent config set compaction_intercept false # persists in ~/.mnemom/launcher.toml
|
|
211
|
+
export MNEMOM_AGENT_COMPACTION_INTERCEPT=0 # for every launch in this shell
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
An opt-out sends both keys as `off` by name, so it also turns the intercept off on a cell whose
|
|
215
|
+
own default is on (sending nothing would leave that cell intercepting).
|
|
205
216
|
|
|
206
217
|
#### Compaction target (`--compact-at`)
|
|
207
218
|
|
|
208
219
|
`--compact-at <n|200k|1m|off>` lets you play with WHEN the gateway pulls this session's own
|
|
209
220
|
compaction point forward, instead of leaving it entirely to Claude Code's normal 1M-window
|
|
210
221
|
schedule. **Unset, `1m`, or `off` all mean no target** — Claude Code runs its normal 1M window
|
|
211
|
-
and the launcher sends
|
|
222
|
+
and the launcher sends no target key (only the default intercept keys above). A
|
|
212
223
|
token count below 1M (k/m suffixes OK, e.g. `200k` or `350000`, from 50k up to just under 1M)
|
|
213
224
|
arms a gateway-side target for this session: the per-session config header carries
|
|
214
225
|
`GATEWAY_USAGE_REAL_SIZE=on` + `GATEWAY_COMPACTION_INTERCEPT=on` (the two keys a target needs to
|
|
@@ -223,10 +234,10 @@ nothing back, so the launcher prints a warning at launch (and in `--dry-run`) wh
|
|
|
223
234
|
the target will be ignored, and a note when it can't tell the window (a passthrough `-- --model`,
|
|
224
235
|
a resume, or a CLI other than Claude Code).
|
|
225
236
|
|
|
226
|
-
**Arming a target needs
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
237
|
+
**Arming a target needs no opt-in** (since 0.17.23 it rides on the default-on intercept). A
|
|
238
|
+
target arms the intercept's two keys even when a standing `compaction_intercept = false` or
|
|
239
|
+
`MNEMOM_AGENT_COMPACTION_INTERCEPT=0` turned it off, since the target cannot work without them.
|
|
240
|
+
Passing `--no-compaction-intercept` together with an armed
|
|
230
241
|
`--compact-at` is refused outright (they contradict: the target cannot arm without the intercept
|
|
231
242
|
you just turned off). So is an armed `--compact-at` (or `--compaction-intercept`) with context
|
|
232
243
|
profile `off`: with the fold off there is no fold to answer the compaction from.
|
|
@@ -235,7 +246,6 @@ Set it per launch, as a standing default, or in the environment (flag > env > `l
|
|
|
235
246
|
default):
|
|
236
247
|
|
|
237
248
|
```bash
|
|
238
|
-
mnemom experimental enable compaction-intercept # one-time opt-in
|
|
239
249
|
mnemom agent my-task --compact-at 200k # this launch only
|
|
240
250
|
mnemom agent config set compact_at 200k # persists in ~/.mnemom/launcher.toml
|
|
241
251
|
export MNEMOM_COMPACT_AT=200k # for every launch in this shell
|
package/dist/commands/agent.d.ts
CHANGED
|
@@ -94,10 +94,11 @@ export interface AgentOptions {
|
|
|
94
94
|
*/
|
|
95
95
|
contextHandoff?: boolean;
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
98
|
-
* `GATEWAY_USAGE_REAL_SIZE=on` + `GATEWAY_COMPACTION_INTERCEPT=on` for this session
|
|
99
|
-
* context size in usage, so Claude Code compacts at its OWN threshold; the compaction
|
|
100
|
-
* answered at once from the gateway's fold).
|
|
97
|
+
* ON by default since 0.17.23 (payload-bound fix; graduated from experimental): tells the
|
|
98
|
+
* gateway `GATEWAY_USAGE_REAL_SIZE=on` + `GATEWAY_COMPACTION_INTERCEPT=on` for this session
|
|
99
|
+
* (real context size in usage, so Claude Code compacts at its OWN threshold; the compaction
|
|
100
|
+
* request answered at once from the gateway's fold). `false` (--no-compaction-intercept) sends
|
|
101
|
+
* both `"off"`; absent ⇒ MNEMOM_AGENT_COMPACTION_INTERCEPT / launcher.toml, else on.
|
|
101
102
|
*/
|
|
102
103
|
compactionIntercept?: boolean;
|
|
103
104
|
/**
|
|
@@ -135,6 +136,12 @@ export interface AgentOptions {
|
|
|
135
136
|
/** Print the resolved launch plan and exit — no key read, no spawn. */
|
|
136
137
|
dryRun?: boolean;
|
|
137
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* The intercept state as the launch banner and the dry-run plan print it. Context profile `off`
|
|
141
|
+
* sends the intercept off (`buildSessionConfig`), so it reads off there whatever the setting; an
|
|
142
|
+
* armed `--compact-at` target turns it on even over a standing opt-out.
|
|
143
|
+
*/
|
|
144
|
+
export declare function describeCompactionIntercept(profile: ContextProfile | null, compactionIntercept: boolean, compactAt: number | null): string;
|
|
138
145
|
/** Entry point for `mnemom agent [scenario]`. Throws on fatal misconfig. */
|
|
139
146
|
export declare function agentCommand(scenarioArg: string | undefined, options?: AgentOptions): Promise<void>;
|
|
140
147
|
/** The Claude Code session id a passthrough `--resume <id>` / `-r <id>` / `--resume=<id>` names. */
|
|
@@ -399,6 +406,8 @@ export declare function printPlan(ctx: {
|
|
|
399
406
|
contextProfile: ContextProfile | null;
|
|
400
407
|
/** The resolved compaction target (`resolveCompactAt`); `null` = no target (default). */
|
|
401
408
|
compactAt: number | null;
|
|
409
|
+
/** The resolved compaction intercept (`resolveCompactionIntercept`); on by default. */
|
|
410
|
+
compactionIntercept?: boolean;
|
|
402
411
|
/** The decoded `x-mnemom-session-config` overlay (`buildSessionConfig`); empty ⇒ no header. */
|
|
403
412
|
sessionConfig: Record<string, string>;
|
|
404
413
|
/** The experimental features on for this launch (the header's `experimental` array). */
|
package/dist/commands/agent.js
CHANGED
|
@@ -53,21 +53,30 @@ import { CLI_VERSION } from "../version.js";
|
|
|
53
53
|
/** The CLI's own provider-key store (zero 1Password): ~/.mnemom/launcher.json, 0600. */
|
|
54
54
|
const CODE_STORE = LAUNCHER_STORE_PATH;
|
|
55
55
|
const say = (line = "") => console.error(line);
|
|
56
|
-
/** The one-line launch note when the compaction intercept is ON. */
|
|
57
|
-
const COMPACTION_INTERCEPT_NOTE = "mnemom agent: compaction intercept ON (experimental) — requested from the gateway (GATEWAY_USAGE_REAL_SIZE, GATEWAY_COMPACTION_INTERCEPT); a gateway without the companion support drops both keys and the session runs as before.";
|
|
58
|
-
const OFF_DROPS_COMPACTION_NOTE = "mnemom agent: compaction intercept off for this session — context profile off leaves compaction to the coding agent, so the standing compaction_intercept / compact_at setting is not sent.";
|
|
59
56
|
/**
|
|
60
|
-
* The
|
|
61
|
-
*
|
|
62
|
-
*
|
|
57
|
+
* The intercept state as the launch banner and the dry-run plan print it. Context profile `off`
|
|
58
|
+
* sends the intercept off (`buildSessionConfig`), so it reads off there whatever the setting; an
|
|
59
|
+
* armed `--compact-at` target turns it on even over a standing opt-out.
|
|
60
|
+
*/
|
|
61
|
+
export function describeCompactionIntercept(profile, compactionIntercept, compactAt) {
|
|
62
|
+
if (profile === "off")
|
|
63
|
+
return "intercept off (context profile off)";
|
|
64
|
+
if (compactionIntercept || compactAt !== null)
|
|
65
|
+
return "intercept on (gateway)";
|
|
66
|
+
return "intercept off (opted out)";
|
|
67
|
+
}
|
|
68
|
+
/** Context profile off drops a standing compaction target: say so rather than show it as set. */
|
|
69
|
+
const OFF_DROPS_TARGET_NOTE = "mnemom agent: context profile off leaves compaction to the coding agent, so the standing compact_at target is not sent.";
|
|
70
|
+
/**
|
|
71
|
+
* The compaction lines for a resolved launch: the intercept (on by default since 0.17.23 — no
|
|
72
|
+
* longer an experimental line) and the compaction target.
|
|
63
73
|
*/
|
|
64
74
|
function sayCompaction(profile, compactionIntercept, compactAt, window) {
|
|
65
75
|
const off = profile === "off";
|
|
76
|
+
say(`mnemom agent: compaction: ${describeCompactionIntercept(profile, compactionIntercept, compactAt)}`);
|
|
66
77
|
sayCompactAt(off ? null : compactAt, window);
|
|
67
|
-
if (off &&
|
|
68
|
-
say(
|
|
69
|
-
else if (compactionIntercept)
|
|
70
|
-
say(COMPACTION_INTERCEPT_NOTE);
|
|
78
|
+
if (off && compactAt !== null)
|
|
79
|
+
say(OFF_DROPS_TARGET_NOTE);
|
|
71
80
|
}
|
|
72
81
|
/**
|
|
73
82
|
* The one-line launch note for the context profile: `null` (none chosen — nothing is sent) names
|
|
@@ -310,6 +319,7 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
310
319
|
cli: planCli,
|
|
311
320
|
contextProfile,
|
|
312
321
|
compactAt,
|
|
322
|
+
compactionIntercept,
|
|
313
323
|
sessionConfig,
|
|
314
324
|
experimental,
|
|
315
325
|
plugin: pluginFor(planCli.name).line,
|
|
@@ -1766,6 +1776,9 @@ export function printPlan(ctx) {
|
|
|
1766
1776
|
L.push(` yolo: ${ctx.yolo ? "on (--dangerously-skip-permissions)" : "off"}`);
|
|
1767
1777
|
L.push(` context: ${ctx.contextProfile ?? "cell default"}`);
|
|
1768
1778
|
L.push(` compaction: ${describeCompactAt(ctx.compactAt)}`);
|
|
1779
|
+
if (ctx.compactionIntercept !== undefined) {
|
|
1780
|
+
L.push(` intercept: ${describeCompactionIntercept(ctx.contextProfile, ctx.compactionIntercept, ctx.compactAt).replace(/^intercept /, "")}`);
|
|
1781
|
+
}
|
|
1769
1782
|
const overlay = Object.entries(ctx.sessionConfig);
|
|
1770
1783
|
if (overlay.length > 0) {
|
|
1771
1784
|
L.push(` session config (${SESSION_CONFIG_HEADER}):`);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* features on and off (registry: lib/experimental.ts; stored in ~/.mnemom/config.json).
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, readdirSync } from "node:fs";
|
|
6
|
-
import { EXPERIMENTAL_CONTRACT, EXPERIMENTAL_ENV, EXPERIMENTAL_FEATURES, EXPERIMENTAL_IDS, isExperimentalId, migrateExperimental, resolveExperimental, } from "../lib/experimental.js";
|
|
6
|
+
import { EXPERIMENTAL_CONTRACT, EXPERIMENTAL_ENV, EXPERIMENTAL_FEATURES, EXPERIMENTAL_IDS, graduatedNote, isExperimentalId, migrateExperimental, resolveExperimental, } from "../lib/experimental.js";
|
|
7
7
|
import { loadCliConfig, setExperimentalEnabled } from "../lib/cli-config.js";
|
|
8
8
|
import { MNEMOM_DIR } from "../lib/config.js";
|
|
9
9
|
import { launcherEntries, loadLauncherConfig } from "../lib/launcher-config.js";
|
|
@@ -50,6 +50,13 @@ export function experimentalListCommand(opts = {}, deps = defaultDeps()) {
|
|
|
50
50
|
deps.log("Turn one on with `mnemom experimental enable <id>`.");
|
|
51
51
|
}
|
|
52
52
|
function toggle(verb, rawId, deps) {
|
|
53
|
+
// A feature that graduated to on-by-default: accept its old id as a no-op with a note, so
|
|
54
|
+
// a script or an old README that still runs `mnemom experimental enable <id>` keeps working.
|
|
55
|
+
const note = graduatedNote((rawId ?? "").trim().toLowerCase());
|
|
56
|
+
if (note) {
|
|
57
|
+
deps.log(note);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
53
60
|
const id = requireId(rawId, verb);
|
|
54
61
|
const current = new Set(resolveExperimental({ stored: deps.stored(), env: {} }).enabled);
|
|
55
62
|
if (verb === "enable")
|
package/dist/index.js
CHANGED
|
@@ -204,7 +204,7 @@ const agentCmd = program
|
|
|
204
204
|
throw new InvalidArgumentError(e.message);
|
|
205
205
|
}
|
|
206
206
|
}))
|
|
207
|
-
.addOption(new Option("--compact-at <n|200k|1m|off>", 'Play with WHEN the gateway pulls this session\'s own compaction point forward, instead of leaving it to Claude Code\'s normal 1M-window schedule. A token count below 1M (k/m suffix OK, e.g. "200k") arms the gateway\'s compaction target for this session; unset, "1m" or "off" all mean no target — Claude Code runs its normal 1M window and nothing new is sent.
|
|
207
|
+
.addOption(new Option("--compact-at <n|200k|1m|off>", 'Play with WHEN the gateway pulls this session\'s own compaction point forward, instead of leaving it to Claude Code\'s normal 1M-window schedule. A token count below 1M (k/m suffix OK, e.g. "200k") arms the gateway\'s compaction target for this session; unset, "1m" or "off" all mean no target — Claude Code runs its normal 1M window and nothing new is sent. A target rides on the compaction intercept (on by default) and is refused if you also pass --no-compaction-intercept. Never touches Claude Code\'s own autocompact env/window. Also: config key compact_at, env MNEMOM_COMPACT_AT.').argParser((v) => {
|
|
208
208
|
// Validate with the same parser the other two surfaces (MNEMOM_COMPACT_AT, launcher.toml
|
|
209
209
|
// compact_at) use, but return the validated RAW string rather than parseCompactAt's
|
|
210
210
|
// `number | null` — commander's own option-value handling coerces a parseArg return of
|
|
@@ -222,8 +222,8 @@ const agentCmd = program
|
|
|
222
222
|
}))
|
|
223
223
|
.addOption(new Option("--context-handoff", "EXPERIMENTAL (`mnemom experimental enable context-handoff`): register the `handoff(note)` MCP tool and tell the gateway to turn on the context-handoff capability for this session").hideHelp(hiddenUnless("context-handoff")))
|
|
224
224
|
.option("--no-context-handoff", "Keep context handoff off for this launch even when launcher.toml (context_handoff = true) or MNEMOM_AGENT_CONTEXT_HANDOFF turns it on")
|
|
225
|
-
.
|
|
226
|
-
.option("--no-compaction-intercept", "
|
|
225
|
+
.option("--compaction-intercept", "Turn the compaction intercept on for this launch even when launcher.toml (compaction_intercept = false) or MNEMOM_AGENT_COMPACTION_INTERCEPT=0 turns it off. On by default: the gateway reports the real context size (so Claude Code compacts at its own threshold) and answers the compaction at once from its fold")
|
|
226
|
+
.option("--no-compaction-intercept", "Turn the compaction intercept off for this launch (it is on by default) — Claude Code's compaction goes to the model as usual. To turn it off for every launch: config key compaction_intercept = false, or env MNEMOM_AGENT_COMPACTION_INTERCEPT=0")
|
|
227
227
|
.option("--dry-run", "Print the resolved launch plan and exit — no key read, no spawn")
|
|
228
228
|
.option("--first-run", "Show the first-run look again: what Mnemom would have saved on your last 30 days of Claude Code (runs on this machine, read-only, nothing uploaded) — then exit")
|
|
229
229
|
.action(async (scenario, passthrough, opts) => {
|
|
@@ -278,19 +278,6 @@ const agentCmd = program
|
|
|
278
278
|
used: opts.contextHandoff === true,
|
|
279
279
|
},
|
|
280
280
|
{ what: "--implicit", id: "implicit", used: opts.implicit === true },
|
|
281
|
-
{
|
|
282
|
-
what: "--compaction-intercept",
|
|
283
|
-
id: "compaction-intercept",
|
|
284
|
-
used: opts.compactionIntercept === true,
|
|
285
|
-
},
|
|
286
|
-
// --compact-at arms the SAME two gateway keys --compaction-intercept does
|
|
287
|
-
// (buildSessionConfig ORs them) — it needs the identical opt-in, not a free pass
|
|
288
|
-
// around it. `null`/unset ("1m"/"off"/no flag) is not a target, so it never gates.
|
|
289
|
-
{
|
|
290
|
-
what: "--compact-at",
|
|
291
|
-
id: "compaction-intercept",
|
|
292
|
-
used: typeof compactAtFlag === "number",
|
|
293
|
-
},
|
|
294
281
|
], experimental);
|
|
295
282
|
if (opts.gateway)
|
|
296
283
|
process.env.MNEMOM_AGENT_GATEWAY = opts.gateway;
|
|
@@ -379,16 +366,13 @@ const agentCmd = program
|
|
|
379
366
|
slack: opts.slack ?? cfg.slackListen,
|
|
380
367
|
context: opts.context,
|
|
381
368
|
contextProfile: opts.contextProfile,
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
// user the env value is ignored, so this is what makes that true.
|
|
385
|
-
compactAt: experimental.includes("compaction-intercept") ? compactAtFlag : null,
|
|
369
|
+
// undefined ⇒ MNEMOM_COMPACT_AT / launcher.toml compact_at (resolveCompactAt).
|
|
370
|
+
compactAt: compactAtFlag,
|
|
386
371
|
// Off ⇒ an explicit false, so MNEMOM_AGENT_CONTEXT_HANDOFF cannot turn it on.
|
|
387
372
|
contextHandoff: experimental.includes("context-handoff") ? opts.contextHandoff : false,
|
|
388
|
-
//
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
: false,
|
|
373
|
+
// On by default (since 0.17.23, no longer experimental): undefined ⇒
|
|
374
|
+
// MNEMOM_AGENT_COMPACTION_INTERCEPT / launcher.toml compaction_intercept, else ON.
|
|
375
|
+
compactionIntercept: opts.compactionIntercept,
|
|
392
376
|
experimental,
|
|
393
377
|
setup: opts.setup,
|
|
394
378
|
governance,
|
package/dist/lib/agent.d.ts
CHANGED
|
@@ -342,16 +342,24 @@ export declare const CONTEXT_HEAD_RECLAIM_KEY = "CONTEXT_RUNTIME_HEAD_BREAKPOINT
|
|
|
342
342
|
export declare const CONTEXT_SIZE_POLICY_KEY = "CONTEXT_RUNTIME_SIZE_POLICY";
|
|
343
343
|
/**
|
|
344
344
|
* The two gateway env keys the `compaction_intercept` setting turns on for a single session
|
|
345
|
-
* (payload-bound fix; both
|
|
345
|
+
* (payload-bound fix; both read from the per-session overlay). The us-2 prod cell runs both on in
|
|
346
|
+
* its own cell env; the test and us-1 preview cells leave them at the gateway default (off). Since
|
|
347
|
+
* 0.17.23 the CLI asks for them on every launch — a deliberate, authorized rollout decision
|
|
348
|
+
* (MNE-8532, CTO 2026-10-12): every cell a `mnemom agent` session runs on then behaves like
|
|
349
|
+
* prod, rather than the CLI deferring to a non-prod cell's off default. The keys are TUNE-tier
|
|
350
|
+
* (gateway session-config allowlist, honored for any authenticated agent), so a cell without
|
|
351
|
+
* the companion support drops them and the session behaves as before.
|
|
346
352
|
* - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
|
|
347
353
|
* REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
|
|
348
354
|
* auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
|
|
349
355
|
* `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
|
|
350
356
|
* - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
|
|
351
357
|
* gateway's own fold digest (no model call), so the compaction never blocks the user.
|
|
352
|
-
* Sent together, value `"on"`, when the `compaction_intercept` setting is on
|
|
353
|
-
* (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below)
|
|
354
|
-
* target cannot be honored without both.
|
|
358
|
+
* Sent together, value `"on"`, when the `compaction_intercept` setting is on — the DEFAULT since
|
|
359
|
+
* 0.17.23 (`resolveCompactionIntercept`) — OR when `--compact-at` arms a target below 1M (below):
|
|
360
|
+
* a target cannot be honored without both. An opt-out (`--no-compaction-intercept`,
|
|
361
|
+
* `compaction_intercept = false`, `MNEMOM_AGENT_COMPACTION_INTERCEPT=0`) and the `off` context
|
|
362
|
+
* profile send both as `"off"`, so the opt-out holds on a cell whose own default is on.
|
|
355
363
|
*/
|
|
356
364
|
export declare const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
|
|
357
365
|
export declare const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
|
|
@@ -461,8 +469,7 @@ export declare function resolveCompactAt(opts: {
|
|
|
461
469
|
* (either silently re-arming the intercept the user just turned off, or silently sending an
|
|
462
470
|
* inert upload-target the gateway can never act on). `compactionIntercept` here is the raw,
|
|
463
471
|
* pre-`resolveCompactionIntercept` flag value: `false` only when `--no-compaction-intercept`
|
|
464
|
-
* was explicitly passed
|
|
465
|
-
* past either — see index.ts's `assertEnabled`), never the mere absence of `--compaction-intercept`.
|
|
472
|
+
* was explicitly passed, never the mere absence of `--compaction-intercept`.
|
|
466
473
|
*/
|
|
467
474
|
export declare function assertCompactAtCompatible(opts: {
|
|
468
475
|
compactionIntercept?: boolean;
|
|
@@ -648,18 +655,23 @@ export declare function resolveContextProfile(opts: {
|
|
|
648
655
|
* no profile was chosen), then `CONTEXT_HANDOFF_ENABLED: "true"` when context handoff is ON, then
|
|
649
656
|
* `GATEWAY_USAGE_SAVINGS: "on"` when measured savings is ON (under every profile), then
|
|
650
657
|
* `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` when EITHER the
|
|
651
|
-
* `compaction_intercept` setting is ON OR `--compact-at` arms a target below 1M (the
|
|
652
|
-
* cannot be honored without the intercept)
|
|
653
|
-
*
|
|
658
|
+
* `compaction_intercept` setting is ON (the default) OR `--compact-at` arms a target below 1M (the
|
|
659
|
+
* target cannot be honored without the intercept) — or both as `"off"` when the setting is
|
|
660
|
+
* explicitly `false` (an opt-out) and no target is armed, so the opt-out holds on a cell whose own
|
|
661
|
+
* env turns them on — then `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"` when a target is set. The `off` profile wins over the intercept and the target: a session with
|
|
654
662
|
* no fold never has its compaction intercepted (`assertOffProfileCompatible` refuses the explicit
|
|
655
663
|
* flag pair; a standing intercept or target from the environment or launcher.toml is dropped).
|
|
656
|
-
* Empty with no profile chosen
|
|
657
|
-
* no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
|
|
664
|
+
* Empty with no profile chosen, everything else off and `compactionIntercept` absent (callers
|
|
665
|
+
* that do not resolve it) — then no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
|
|
658
666
|
*/
|
|
659
667
|
export declare function buildSessionConfig(opts: {
|
|
660
668
|
/** `resolveContextProfile` output: `null` ⇒ no profile chosen, no fold key sent. */
|
|
661
669
|
profile: ContextProfile | null;
|
|
662
670
|
contextHandoff: boolean;
|
|
671
|
+
/**
|
|
672
|
+
* `resolveCompactionIntercept` output: `true` (the default) ⇒ both keys `"on"`; `false` (an
|
|
673
|
+
* opt-out) ⇒ both `"off"`; absent ⇒ neither key is sent (the cell's own default stands).
|
|
674
|
+
*/
|
|
663
675
|
compactionIntercept?: boolean;
|
|
664
676
|
/** `resolveCompactAt` output: `null` (or absent) ⇒ no target, send nothing new. */
|
|
665
677
|
compactAt?: number | null;
|
|
@@ -691,8 +703,8 @@ export declare function buildSessionConfigPayload(opts: {
|
|
|
691
703
|
* `aggressive` → the three fold-tuning keys + `CONTEXT_RUNTIME_SIZE_POLICY: "off"`,
|
|
692
704
|
* `balanced` → `CONTEXT_RUNTIME_SIZE_POLICY: "off"`, `adaptive` →
|
|
693
705
|
* `CONTEXT_RUNTIME_SIZE_POLICY: "banded"`, none chosen → nothing;
|
|
694
|
-
* - `compactionIntercept: true` → `GATEWAY_USAGE_REAL_SIZE` +
|
|
695
|
-
* `"on"` (
|
|
706
|
+
* - `compactionIntercept: true` (the default) → `GATEWAY_USAGE_REAL_SIZE` +
|
|
707
|
+
* `GATEWAY_COMPACTION_INTERCEPT` `"on"`; `false` (an opt-out) → both `"off"`;
|
|
696
708
|
* - `compactAt: <N>` (`--compact-at`, below 1M) → the SAME two intercept keys plus
|
|
697
709
|
* `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"`; unset, `1m` or `off` → nothing beyond
|
|
698
710
|
* what `compactionIntercept` already sent (Claude Code's own 1M window, untouched);
|
|
@@ -725,10 +737,11 @@ export declare function resolveContextHandoff(opts: {
|
|
|
725
737
|
}): boolean;
|
|
726
738
|
/**
|
|
727
739
|
* Is the compaction intercept (`GATEWAY_USAGE_REAL_SIZE` + `GATEWAY_COMPACTION_INTERCEPT` in the
|
|
728
|
-
* session-config header) ON for this launch?
|
|
729
|
-
* `
|
|
730
|
-
* wins, else `MNEMOM_AGENT_COMPACTION_INTERCEPT` (which
|
|
731
|
-
* `compaction_intercept` config key
|
|
740
|
+
* session-config header) ON for this launch? ON by default since 0.17.23 (it graduated from the
|
|
741
|
+
* `compaction-intercept` experimental feature). An explicit `--compaction-intercept` /
|
|
742
|
+
* `--no-compaction-intercept` wins, else `MNEMOM_AGENT_COMPACTION_INTERCEPT` (which
|
|
743
|
+
* `applyConfigToEnv` sets from the `compaction_intercept` config key: `0`/`false`/`off`/`no`
|
|
744
|
+
* opt out), else ON.
|
|
732
745
|
*/
|
|
733
746
|
export declare function resolveCompactionIntercept(opts: {
|
|
734
747
|
compactionIntercept?: boolean;
|
package/dist/lib/agent.js
CHANGED
|
@@ -503,16 +503,24 @@ export const CONTEXT_HEAD_RECLAIM_KEY = "CONTEXT_RUNTIME_HEAD_BREAKPOINT_RECLAIM
|
|
|
503
503
|
export const CONTEXT_SIZE_POLICY_KEY = "CONTEXT_RUNTIME_SIZE_POLICY";
|
|
504
504
|
/**
|
|
505
505
|
* The two gateway env keys the `compaction_intercept` setting turns on for a single session
|
|
506
|
-
* (payload-bound fix; both
|
|
506
|
+
* (payload-bound fix; both read from the per-session overlay). The us-2 prod cell runs both on in
|
|
507
|
+
* its own cell env; the test and us-1 preview cells leave them at the gateway default (off). Since
|
|
508
|
+
* 0.17.23 the CLI asks for them on every launch — a deliberate, authorized rollout decision
|
|
509
|
+
* (MNE-8532, CTO 2026-10-12): every cell a `mnemom agent` session runs on then behaves like
|
|
510
|
+
* prod, rather than the CLI deferring to a non-prod cell's off default. The keys are TUNE-tier
|
|
511
|
+
* (gateway session-config allowlist, honored for any authenticated agent), so a cell without
|
|
512
|
+
* the companion support drops them and the session behaves as before.
|
|
507
513
|
* - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
|
|
508
514
|
* REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
|
|
509
515
|
* auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
|
|
510
516
|
* `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
|
|
511
517
|
* - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
|
|
512
518
|
* gateway's own fold digest (no model call), so the compaction never blocks the user.
|
|
513
|
-
* Sent together, value `"on"`, when the `compaction_intercept` setting is on
|
|
514
|
-
* (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below)
|
|
515
|
-
* target cannot be honored without both.
|
|
519
|
+
* Sent together, value `"on"`, when the `compaction_intercept` setting is on — the DEFAULT since
|
|
520
|
+
* 0.17.23 (`resolveCompactionIntercept`) — OR when `--compact-at` arms a target below 1M (below):
|
|
521
|
+
* a target cannot be honored without both. An opt-out (`--no-compaction-intercept`,
|
|
522
|
+
* `compaction_intercept = false`, `MNEMOM_AGENT_COMPACTION_INTERCEPT=0`) and the `off` context
|
|
523
|
+
* profile send both as `"off"`, so the opt-out holds on a cell whose own default is on.
|
|
516
524
|
*/
|
|
517
525
|
export const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
|
|
518
526
|
export const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
|
|
@@ -576,12 +584,12 @@ export const CONTEXT_HANDOFF_KEY = "CONTEXT_HANDOFF_ENABLED";
|
|
|
576
584
|
// Lets an operator play with WHEN the gateway pulls this session's own client-visible
|
|
577
585
|
// compaction point forward (GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS, #2251), instead of
|
|
578
586
|
// leaving Claude Code to compact on its own 1M-window schedule. Unset / `1m` / `off` all
|
|
579
|
-
// mean the SAME thing — no target — so
|
|
580
|
-
//
|
|
581
|
-
//
|
|
582
|
-
//
|
|
583
|
-
//
|
|
584
|
-
//
|
|
587
|
+
// mean the SAME thing — no target — so no target key is sent: Claude Code's own 1M window, no
|
|
588
|
+
// gateway-triggered compaction. A value strictly below 1,000,000 sends the target itself and
|
|
589
|
+
// arms the compaction intercept (USAGE_REAL_SIZE_KEY + COMPACTION_INTERCEPT_KEY, above — on by
|
|
590
|
+
// default since 0.17.23; #2216: both are required for the upload pull to be honored instead of
|
|
591
|
+
// silently inert), even over a standing opt-out in launcher.toml or the environment; only an
|
|
592
|
+
// explicit --no-compaction-intercept in the same launch is refused (assertCompactAtCompatible). Refold (GATEWAY_COMPACTION_REFOLD)
|
|
585
593
|
// is a SEPARATE, costlier opt-in (+9.5pts measured) — this setting never touches it. This never
|
|
586
594
|
// sets a Claude Code autocompact env/window: Claude Code's own compaction math is untouched;
|
|
587
595
|
// only what the GATEWAY reports back changes.
|
|
@@ -704,15 +712,13 @@ export function resolveCompactAt(opts) {
|
|
|
704
712
|
* (either silently re-arming the intercept the user just turned off, or silently sending an
|
|
705
713
|
* inert upload-target the gateway can never act on). `compactionIntercept` here is the raw,
|
|
706
714
|
* pre-`resolveCompactionIntercept` flag value: `false` only when `--no-compaction-intercept`
|
|
707
|
-
* was explicitly passed
|
|
708
|
-
* past either — see index.ts's `assertEnabled`), never the mere absence of `--compaction-intercept`.
|
|
715
|
+
* was explicitly passed, never the mere absence of `--compaction-intercept`.
|
|
709
716
|
*/
|
|
710
717
|
export function assertCompactAtCompatible(opts) {
|
|
711
718
|
if (opts.compactionIntercept === false && opts.compactAt !== null) {
|
|
712
|
-
throw new Error("mnemom agent: --compact-at needs the compaction intercept to arm, but
|
|
713
|
-
"
|
|
714
|
-
"
|
|
715
|
-
"enable compaction-intercept`), or pass --compact-at off.");
|
|
719
|
+
throw new Error("mnemom agent: --compact-at needs the compaction intercept to arm, but " +
|
|
720
|
+
"--no-compaction-intercept turns it off for this launch. Drop --no-compaction-intercept, " +
|
|
721
|
+
"or pass --compact-at off.");
|
|
716
722
|
}
|
|
717
723
|
}
|
|
718
724
|
/**
|
|
@@ -1039,13 +1045,14 @@ export function resolveContextProfile(opts) {
|
|
|
1039
1045
|
* no profile was chosen), then `CONTEXT_HANDOFF_ENABLED: "true"` when context handoff is ON, then
|
|
1040
1046
|
* `GATEWAY_USAGE_SAVINGS: "on"` when measured savings is ON (under every profile), then
|
|
1041
1047
|
* `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` when EITHER the
|
|
1042
|
-
* `compaction_intercept` setting is ON OR `--compact-at` arms a target below 1M (the
|
|
1043
|
-
* cannot be honored without the intercept)
|
|
1044
|
-
*
|
|
1048
|
+
* `compaction_intercept` setting is ON (the default) OR `--compact-at` arms a target below 1M (the
|
|
1049
|
+
* target cannot be honored without the intercept) — or both as `"off"` when the setting is
|
|
1050
|
+
* explicitly `false` (an opt-out) and no target is armed, so the opt-out holds on a cell whose own
|
|
1051
|
+
* env turns them on — then `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"` when a target is set. The `off` profile wins over the intercept and the target: a session with
|
|
1045
1052
|
* no fold never has its compaction intercepted (`assertOffProfileCompatible` refuses the explicit
|
|
1046
1053
|
* flag pair; a standing intercept or target from the environment or launcher.toml is dropped).
|
|
1047
|
-
* Empty with no profile chosen
|
|
1048
|
-
* no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
|
|
1054
|
+
* Empty with no profile chosen, everything else off and `compactionIntercept` absent (callers
|
|
1055
|
+
* that do not resolve it) — then no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
|
|
1049
1056
|
*/
|
|
1050
1057
|
export function buildSessionConfig(opts) {
|
|
1051
1058
|
const config = {};
|
|
@@ -1068,6 +1075,12 @@ export function buildSessionConfig(opts) {
|
|
|
1068
1075
|
config[USAGE_REAL_SIZE_KEY] = "on";
|
|
1069
1076
|
config[COMPACTION_INTERCEPT_KEY] = "on";
|
|
1070
1077
|
}
|
|
1078
|
+
else if (opts.compactionIntercept === false) {
|
|
1079
|
+
// An opt-out says "off" by name: sending nothing would leave a cell whose own env turns the
|
|
1080
|
+
// intercept on (us-2) intercepting anyway.
|
|
1081
|
+
config[USAGE_REAL_SIZE_KEY] = "off";
|
|
1082
|
+
config[COMPACTION_INTERCEPT_KEY] = "off";
|
|
1083
|
+
}
|
|
1071
1084
|
if (hasCompactionTarget) {
|
|
1072
1085
|
config[GATEWAY_COMPACTION_UPLOAD_TARGET_KEY] = String(opts.compactAt);
|
|
1073
1086
|
}
|
|
@@ -1095,8 +1108,8 @@ export function buildSessionConfigPayload(opts) {
|
|
|
1095
1108
|
* `aggressive` → the three fold-tuning keys + `CONTEXT_RUNTIME_SIZE_POLICY: "off"`,
|
|
1096
1109
|
* `balanced` → `CONTEXT_RUNTIME_SIZE_POLICY: "off"`, `adaptive` →
|
|
1097
1110
|
* `CONTEXT_RUNTIME_SIZE_POLICY: "banded"`, none chosen → nothing;
|
|
1098
|
-
* - `compactionIntercept: true` → `GATEWAY_USAGE_REAL_SIZE` +
|
|
1099
|
-
* `"on"` (
|
|
1111
|
+
* - `compactionIntercept: true` (the default) → `GATEWAY_USAGE_REAL_SIZE` +
|
|
1112
|
+
* `GATEWAY_COMPACTION_INTERCEPT` `"on"`; `false` (an opt-out) → both `"off"`;
|
|
1100
1113
|
* - `compactAt: <N>` (`--compact-at`, below 1M) → the SAME two intercept keys plus
|
|
1101
1114
|
* `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"`; unset, `1m` or `off` → nothing beyond
|
|
1102
1115
|
* what `compactionIntercept` already sent (Claude Code's own 1M window, untouched);
|
|
@@ -1131,18 +1144,17 @@ export function resolveContextHandoff(opts) {
|
|
|
1131
1144
|
}
|
|
1132
1145
|
/**
|
|
1133
1146
|
* Is the compaction intercept (`GATEWAY_USAGE_REAL_SIZE` + `GATEWAY_COMPACTION_INTERCEPT` in the
|
|
1134
|
-
* session-config header) ON for this launch?
|
|
1135
|
-
* `
|
|
1136
|
-
* wins, else `MNEMOM_AGENT_COMPACTION_INTERCEPT` (which
|
|
1137
|
-
* `compaction_intercept` config key
|
|
1147
|
+
* session-config header) ON for this launch? ON by default since 0.17.23 (it graduated from the
|
|
1148
|
+
* `compaction-intercept` experimental feature). An explicit `--compaction-intercept` /
|
|
1149
|
+
* `--no-compaction-intercept` wins, else `MNEMOM_AGENT_COMPACTION_INTERCEPT` (which
|
|
1150
|
+
* `applyConfigToEnv` sets from the `compaction_intercept` config key: `0`/`false`/`off`/`no`
|
|
1151
|
+
* opt out), else ON.
|
|
1138
1152
|
*/
|
|
1139
1153
|
export function resolveCompactionIntercept(opts) {
|
|
1140
1154
|
if (opts.compactionIntercept !== undefined)
|
|
1141
1155
|
return opts.compactionIntercept;
|
|
1142
1156
|
const raw = (opts.env?.MNEMOM_AGENT_COMPACTION_INTERCEPT ?? "").trim().toLowerCase();
|
|
1143
|
-
|
|
1144
|
-
return false;
|
|
1145
|
-
return raw === "1" || raw === "true" || raw === "on" || raw === "yes";
|
|
1157
|
+
return !(raw === "0" || raw === "false" || raw === "off" || raw === "no");
|
|
1146
1158
|
}
|
|
1147
1159
|
/**
|
|
1148
1160
|
* Does the gateway measure this launch's saving (`GATEWAY_USAGE_SAVINGS` in the header, and the
|
|
@@ -12,16 +12,20 @@
|
|
|
12
12
|
* Everything here is pure or dependency-injected; index.ts and the command
|
|
13
13
|
* modules are the thin drivers.
|
|
14
14
|
*/
|
|
15
|
-
export type ExperimentalId = "context-handoff" | "slack" | "implicit" | "
|
|
15
|
+
export type ExperimentalId = "context-handoff" | "slack" | "implicit" | "measured-savings";
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* admitting a value the real parser would reject anyway.
|
|
17
|
+
* Features that used to be experimental and are now on by default for everyone. Their ids are
|
|
18
|
+
* no longer in the registry, but `mnemom experimental enable|disable <id>` still accepts them
|
|
19
|
+
* as a no-op (with a one-line note naming the release and the real opt-out) instead of failing
|
|
20
|
+
* on an id a user, a script or an old README still names. Value: the release that graduated it
|
|
21
|
+
* and how to turn it off now.
|
|
23
22
|
*/
|
|
24
|
-
export declare
|
|
23
|
+
export declare const GRADUATED_FEATURES: Readonly<Record<string, {
|
|
24
|
+
since: string;
|
|
25
|
+
optOut: string;
|
|
26
|
+
}>>;
|
|
27
|
+
/** The one-line note for `mnemom experimental enable|disable <graduated id>`; null otherwise. */
|
|
28
|
+
export declare function graduatedNote(id: string): string | null;
|
|
25
29
|
export interface ExperimentalFeature {
|
|
26
30
|
id: ExperimentalId;
|
|
27
31
|
summary: string;
|
|
@@ -82,8 +86,7 @@ export declare function assertEnabled(uses: ReadonlyArray<{
|
|
|
82
86
|
export declare function experimentalIdForConfigKey(key: string, value: string): ExperimentalId | undefined;
|
|
83
87
|
/**
|
|
84
88
|
* The stderr lines for experimental settings a launch ignores because their feature
|
|
85
|
-
* is off: launcher.toml keys (`entries` as `[key, value]`)
|
|
86
|
-
* MNEMOM_AGENT_COMPACTION_INTERCEPT and MNEMOM_COMPACT_AT (an armed target only).
|
|
89
|
+
* is off: launcher.toml keys (`entries` as `[key, value]`) and MNEMOM_AGENT_CONTEXT_HANDOFF.
|
|
87
90
|
*/
|
|
88
91
|
export declare function ignoredSettingLines(opts: {
|
|
89
92
|
entries: ReadonlyArray<[string, string]>;
|
package/dist/lib/experimental.js
CHANGED
|
@@ -13,16 +13,24 @@
|
|
|
13
13
|
* modules are the thin drivers.
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* admitting a value the real parser would reject anyway.
|
|
16
|
+
* Features that used to be experimental and are now on by default for everyone. Their ids are
|
|
17
|
+
* no longer in the registry, but `mnemom experimental enable|disable <id>` still accepts them
|
|
18
|
+
* as a no-op (with a one-line note naming the release and the real opt-out) instead of failing
|
|
19
|
+
* on an id a user, a script or an old README still names. Value: the release that graduated it
|
|
20
|
+
* and how to turn it off now.
|
|
22
21
|
*/
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export const GRADUATED_FEATURES = {
|
|
23
|
+
"compaction-intercept": {
|
|
24
|
+
since: "0.17.23",
|
|
25
|
+
optOut: "--no-compaction-intercept, `compaction_intercept = false` in launcher.toml, or MNEMOM_AGENT_COMPACTION_INTERCEPT=0",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
/** The one-line note for `mnemom experimental enable|disable <graduated id>`; null otherwise. */
|
|
29
|
+
export function graduatedNote(id) {
|
|
30
|
+
const g = GRADUATED_FEATURES[id];
|
|
31
|
+
if (!g)
|
|
32
|
+
return null;
|
|
33
|
+
return `${id} is no longer experimental: it is on by default since ${g.since}, so this changes nothing. To turn it off: ${g.optOut}.`;
|
|
26
34
|
}
|
|
27
35
|
export const EXPERIMENTAL_FEATURES = [
|
|
28
36
|
{
|
|
@@ -58,17 +66,6 @@ export const EXPERIMENTAL_FEATURES = [
|
|
|
58
66
|
env: [],
|
|
59
67
|
},
|
|
60
68
|
},
|
|
61
|
-
{
|
|
62
|
-
id: "compaction-intercept",
|
|
63
|
-
summary: "Have the gateway report the real context size (so Claude Code compacts at its own threshold) and answer the compaction at once from its fold",
|
|
64
|
-
since: "0.17.4",
|
|
65
|
-
gates: {
|
|
66
|
-
flags: ["--compaction-intercept"],
|
|
67
|
-
configKeys: ["compaction_intercept"],
|
|
68
|
-
commands: [],
|
|
69
|
-
env: ["MNEMOM_AGENT_COMPACTION_INTERCEPT"],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
69
|
{
|
|
73
70
|
// No flag, launcher.toml key or env of its own: `mnemom experimental enable` is the switch.
|
|
74
71
|
id: "measured-savings",
|
|
@@ -162,25 +159,19 @@ export function experimentalIdForConfigKey(key, value) {
|
|
|
162
159
|
return value === "true" ? "slack" : undefined;
|
|
163
160
|
case "context_handoff":
|
|
164
161
|
return value === "true" ? "context-handoff" : undefined;
|
|
165
|
-
case "compaction_intercept":
|
|
166
|
-
return value === "true" ? "compaction-intercept" : undefined;
|
|
167
|
-
case "compact_at":
|
|
168
|
-
// Arms the SAME gateway keys compaction_intercept does — same gate.
|
|
169
|
-
return compactAtArmed(value) ? "compaction-intercept" : undefined;
|
|
170
162
|
case "goal_mode":
|
|
171
163
|
return value === "implicit" ? "implicit" : undefined;
|
|
172
164
|
default:
|
|
173
165
|
return undefined;
|
|
174
166
|
}
|
|
175
167
|
}
|
|
176
|
-
/** Is an env value one of the truthy spellings resolveContextHandoff
|
|
168
|
+
/** Is an env value one of the truthy spellings resolveContextHandoff accepts? */
|
|
177
169
|
function truthy(raw) {
|
|
178
170
|
return ["1", "true", "on", "yes"].includes((raw ?? "").trim().toLowerCase());
|
|
179
171
|
}
|
|
180
172
|
/**
|
|
181
173
|
* The stderr lines for experimental settings a launch ignores because their feature
|
|
182
|
-
* is off: launcher.toml keys (`entries` as `[key, value]`)
|
|
183
|
-
* MNEMOM_AGENT_COMPACTION_INTERCEPT and MNEMOM_COMPACT_AT (an armed target only).
|
|
174
|
+
* is off: launcher.toml keys (`entries` as `[key, value]`) and MNEMOM_AGENT_CONTEXT_HANDOFF.
|
|
184
175
|
*/
|
|
185
176
|
export function ignoredSettingLines(opts) {
|
|
186
177
|
const lines = [];
|
|
@@ -193,14 +184,6 @@ export function ignoredSettingLines(opts) {
|
|
|
193
184
|
if (truthy(opts.env.MNEMOM_AGENT_CONTEXT_HANDOFF) && !opts.enabled.includes("context-handoff")) {
|
|
194
185
|
lines.push(`mnemom agent: ignoring ${gatedMessage("MNEMOM_AGENT_CONTEXT_HANDOFF", "context-handoff")}`);
|
|
195
186
|
}
|
|
196
|
-
if (truthy(opts.env.MNEMOM_AGENT_COMPACTION_INTERCEPT) &&
|
|
197
|
-
!opts.enabled.includes("compaction-intercept")) {
|
|
198
|
-
lines.push(`mnemom agent: ignoring ${gatedMessage("MNEMOM_AGENT_COMPACTION_INTERCEPT", "compaction-intercept")}`);
|
|
199
|
-
}
|
|
200
|
-
if (compactAtArmed(opts.env.MNEMOM_COMPACT_AT) &&
|
|
201
|
-
!opts.enabled.includes("compaction-intercept")) {
|
|
202
|
-
lines.push(`mnemom agent: ignoring ${gatedMessage("MNEMOM_COMPACT_AT", "compaction-intercept")}`);
|
|
203
|
-
}
|
|
204
187
|
return lines;
|
|
205
188
|
}
|
|
206
189
|
/** The features an existing launcher.toml already uses (the one-time migration). */
|
|
@@ -250,8 +233,6 @@ export function configKeyFeature(key) {
|
|
|
250
233
|
return "slack";
|
|
251
234
|
if (key === "context_handoff")
|
|
252
235
|
return "context-handoff";
|
|
253
|
-
if (key === "compaction_intercept")
|
|
254
|
-
return "compaction-intercept";
|
|
255
236
|
if (key === "goal_mode")
|
|
256
237
|
return "implicit";
|
|
257
238
|
return undefined;
|
|
@@ -50,9 +50,9 @@ export interface LauncherConfig {
|
|
|
50
50
|
*/
|
|
51
51
|
contextHandoff?: boolean;
|
|
52
52
|
/**
|
|
53
|
-
* Compaction-intercept default (
|
|
53
|
+
* Compaction-intercept default (ON when unset, since 0.17.23): `true` sends
|
|
54
54
|
* `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` in the per-session
|
|
55
|
-
* config header for every launch
|
|
55
|
+
* config header for every launch; `false` opts out and sends both as `"off"`.
|
|
56
56
|
*/
|
|
57
57
|
compactionIntercept?: boolean;
|
|
58
58
|
/**
|
|
@@ -121,9 +121,8 @@ export declare function launcherEntries(cfg: LauncherConfig): Array<[string, str
|
|
|
121
121
|
/**
|
|
122
122
|
* `cfg` without the settings of experimental features that are off (a copy; `cfg` is
|
|
123
123
|
* untouched): `slack_*` while `slack` is off, `context_handoff` while `context-handoff` is
|
|
124
|
-
* off, `
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* off (`goal_mode = off` is kept).
|
|
124
|
+
* off, and `goal_mode = implicit` while `implicit` is off (`goal_mode = off` is kept).
|
|
125
|
+
* `compaction_intercept` / `compact_at` are not experimental (on by default since 0.17.23) and
|
|
126
|
+
* always pass through.
|
|
128
127
|
*/
|
|
129
128
|
export declare function withoutDisabledExperimental(cfg: LauncherConfig, enabled: readonly ExperimentalId[]): LauncherConfig;
|
|
@@ -20,7 +20,6 @@ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "
|
|
|
20
20
|
import { dirname, join } from "node:path";
|
|
21
21
|
import { parse as parseToml, stringify as stringifyToml, TomlError } from "smol-toml";
|
|
22
22
|
import { MNEMOM_DIR } from "./config.js";
|
|
23
|
-
import { compactAtArmed } from "./experimental.js";
|
|
24
23
|
import { CONTEXT_PROFILES, isPositiveInt, isPositiveNumber, parseCompactAt, parseContextProfile, } from "./agent.js";
|
|
25
24
|
/** The human-editable settings file. Secret key lives elsewhere (launcher.json). */
|
|
26
25
|
export const LAUNCHER_CONFIG_PATH = join(MNEMOM_DIR, "launcher.toml");
|
|
@@ -207,7 +206,7 @@ export const CONFIG_KEYS = [
|
|
|
207
206
|
},
|
|
208
207
|
{
|
|
209
208
|
key: "compaction_intercept",
|
|
210
|
-
describe: "
|
|
209
|
+
describe: "Compaction intercept: the gateway reports the real context size and answers Claude Code's compaction from its fold (GATEWAY_USAGE_REAL_SIZE + GATEWAY_COMPACTION_INTERCEPT; on by default, false opts out)",
|
|
211
210
|
get: (c) => c.compactionIntercept,
|
|
212
211
|
set: (c, v) => {
|
|
213
212
|
c.compactionIntercept = coerceBool("compaction_intercept", v);
|
|
@@ -467,10 +466,9 @@ export function launcherEntries(cfg) {
|
|
|
467
466
|
/**
|
|
468
467
|
* `cfg` without the settings of experimental features that are off (a copy; `cfg` is
|
|
469
468
|
* untouched): `slack_*` while `slack` is off, `context_handoff` while `context-handoff` is
|
|
470
|
-
* off, `
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
* off (`goal_mode = off` is kept).
|
|
469
|
+
* off, and `goal_mode = implicit` while `implicit` is off (`goal_mode = off` is kept).
|
|
470
|
+
* `compaction_intercept` / `compact_at` are not experimental (on by default since 0.17.23) and
|
|
471
|
+
* always pass through.
|
|
474
472
|
*/
|
|
475
473
|
export function withoutDisabledExperimental(cfg, enabled) {
|
|
476
474
|
const out = { ...cfg };
|
|
@@ -481,11 +479,6 @@ export function withoutDisabledExperimental(cfg, enabled) {
|
|
|
481
479
|
}
|
|
482
480
|
if (!enabled.includes("context-handoff"))
|
|
483
481
|
delete out.contextHandoff;
|
|
484
|
-
if (!enabled.includes("compaction-intercept")) {
|
|
485
|
-
delete out.compactionIntercept;
|
|
486
|
-
if (compactAtArmed(out.compactAt))
|
|
487
|
-
delete out.compactAt;
|
|
488
|
-
}
|
|
489
482
|
if (!enabled.includes("implicit") && out.goalMode === "implicit")
|
|
490
483
|
delete out.goalMode;
|
|
491
484
|
return out;
|