@mnemom/mnemom 0.17.7-next.1 → 0.17.7-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/commands/agent.js +30 -8
- package/dist/index.js +1 -1
- package/dist/lib/agent.d.ts +38 -19
- package/dist/lib/agent.js +54 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,7 +103,12 @@ default is. Each profile serves a different set of use cases:
|
|
|
103
103
|
`aggressive` budgets from 200k to 1M, and `balanced` above 1M. It sends
|
|
104
104
|
`CONTEXT_RUNTIME_SIZE_POLICY=banded` in the per-session config; the band thresholds are the
|
|
105
105
|
gateway's defaults.
|
|
106
|
-
- **`off`** leaves compaction to the coding agent.
|
|
106
|
+
- **`off`** leaves compaction to the coding agent. It sends `CONTEXT_RUNTIME_ENABLED=false`
|
|
107
|
+
plus `GATEWAY_USAGE_REAL_SIZE=off` and `GATEWAY_COMPACTION_INTERCEPT=off`, so a session with
|
|
108
|
+
no fold never has its compaction intercepted or its reported context size rewritten, even on
|
|
109
|
+
a cell whose default turns the intercept on. `--compaction-intercept` or `--compact-at <n>` on
|
|
110
|
+
the same launch is refused; a standing `compaction_intercept` / `compact_at` setting is left
|
|
111
|
+
out for that session (the launch note says so).
|
|
107
112
|
|
|
108
113
|
Choose it for one launch, as a standing default, or in the environment (flag > env >
|
|
109
114
|
`launcher.toml`). Only `mnemom agent config set` (or editing `launcher.toml`) saves a default;
|
|
@@ -191,7 +196,8 @@ enable compaction-intercept`) — a target arms the identical pair of gateway ke
|
|
|
191
196
|
the identical gate; the flag itself stays visible in `--help` (it's the knob you asked for), only
|
|
192
197
|
actually _arming_ a target is gated. Passing `--no-compaction-intercept` together with an armed
|
|
193
198
|
`--compact-at` is refused outright (they contradict: the target cannot arm without the intercept
|
|
194
|
-
you just turned off).
|
|
199
|
+
you just turned off). So is an armed `--compact-at` (or `--compaction-intercept`) with context
|
|
200
|
+
profile `off`: with the fold off there is no fold to answer the compaction from.
|
|
195
201
|
|
|
196
202
|
Set it per launch, as a standing default, or in the environment (flag > env > `launcher.toml` >
|
|
197
203
|
default):
|
package/dist/commands/agent.js
CHANGED
|
@@ -45,7 +45,7 @@ import { authConfigured, chooseAuth, detectClaudeLogin, readClaudeLoginState, }
|
|
|
45
45
|
import { requireConsoleKey, readConsoleKey } from "../lib/console-key.js";
|
|
46
46
|
import { goalAlignmentLine, resolveSessionSetup } from "./agent-session.js";
|
|
47
47
|
import { AgentIdentityMismatchError, defaultAgentSlug, ensureGovernedAgent, ensureSessionAndBalance, isQuietPreambleExit, resolveDefaultSlug, resolvePreflightedAccount, } from "./agent-setup.js";
|
|
48
|
-
import { assembleContract, buildGoalModeHeader, buildCustomHeaders, buildHandoffMcpConfigJson, buildSessionConfig, buildSessionConfigB64, assertCompactAtCompatible, compactAtWindowWarning, describeCompactAt, launchWindow, resolveCompactAt, applyGatewayHintHeaders, resolveCompactionIntercept, resolveContextHandoff, resolveContextProfile, resolveHandoffGatewayHost, HANDOFF_RC_KEY_ENV_NAME, HANDOFF_RC_MNEMOM_KEY_ENV_NAME, isProdGateway, launchPreferenceExplicit, launchPreflighted, remoteControlAllowed, applyToolSearchDefault, DISABLE_1M_ENV, readCcSettings, resolveWindowModel, resolveAnthropicDoor, resolveLaunchModel, resolveConversationId, resolveGatewayHost, singleCellError, resolveLaunchShape, resolveRemoteControlShape, passthroughName, sanitizeAgentName, sessionDisplayName, SESSION_NAME_ENV, SESSION_CONFIG_HEADER, } from "../lib/agent.js";
|
|
48
|
+
import { assembleContract, buildGoalModeHeader, buildCustomHeaders, buildHandoffMcpConfigJson, buildSessionConfig, buildSessionConfigB64, assertCompactAtCompatible, assertOffProfileCompatible, compactAtWindowWarning, describeCompactAt, launchWindow, resolveCompactAt, applyGatewayHintHeaders, resolveCompactionIntercept, resolveContextHandoff, resolveContextProfile, resolveHandoffGatewayHost, HANDOFF_RC_KEY_ENV_NAME, HANDOFF_RC_MNEMOM_KEY_ENV_NAME, isProdGateway, launchPreferenceExplicit, launchPreflighted, remoteControlAllowed, applyToolSearchDefault, DISABLE_1M_ENV, readCcSettings, resolveWindowModel, resolveAnthropicDoor, resolveLaunchModel, resolveConversationId, resolveGatewayHost, singleCellError, resolveLaunchShape, resolveRemoteControlShape, passthroughName, sanitizeAgentName, sessionDisplayName, SESSION_NAME_ENV, SESSION_CONFIG_HEADER, } from "../lib/agent.js";
|
|
49
49
|
import { LAUNCHER_STORE_PATH, mergeStore, readStore } from "../lib/launcher-store.js";
|
|
50
50
|
import { slackChannelArgs } from "../lib/slack-launch.js";
|
|
51
51
|
/** The CLI's own provider-key store (zero 1Password): ~/.mnemom/launcher.json, 0600. */
|
|
@@ -53,6 +53,20 @@ const CODE_STORE = LAUNCHER_STORE_PATH;
|
|
|
53
53
|
const say = (line = "") => console.error(line);
|
|
54
54
|
/** The one-line launch note when the compaction intercept is ON. */
|
|
55
55
|
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.";
|
|
56
|
+
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.";
|
|
57
|
+
/**
|
|
58
|
+
* The compaction notes for a resolved launch. Context profile `off` sends the intercept off and
|
|
59
|
+
* no target (`buildSessionConfig`), so a standing intercept or target is reported as dropped
|
|
60
|
+
* rather than as ON.
|
|
61
|
+
*/
|
|
62
|
+
function sayCompaction(profile, compactionIntercept, compactAt, window) {
|
|
63
|
+
const off = profile === "off";
|
|
64
|
+
sayCompactAt(off ? null : compactAt, window);
|
|
65
|
+
if (off && (compactionIntercept || compactAt !== null))
|
|
66
|
+
say(OFF_DROPS_COMPACTION_NOTE);
|
|
67
|
+
else if (compactionIntercept)
|
|
68
|
+
say(COMPACTION_INTERCEPT_NOTE);
|
|
69
|
+
}
|
|
56
70
|
/**
|
|
57
71
|
* The one-line launch note for the context profile: `null` (none chosen — nothing is sent) names
|
|
58
72
|
* the cell default. `off` keeps the wording `--no-context` has always printed.
|
|
@@ -209,6 +223,13 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
209
223
|
// cannot arm without the intercept it just turned off. Refuse rather than silently pick
|
|
210
224
|
// a side.
|
|
211
225
|
assertCompactAtCompatible({ compactionIntercept: options.compactionIntercept, compactAt });
|
|
226
|
+
// Context profile off sends the intercept off: an explicit --compaction-intercept or
|
|
227
|
+
// --compact-at <N> in the same launch contradicts it. A resume re-checks below.
|
|
228
|
+
assertOffProfileCompatible({
|
|
229
|
+
profile: contextProfile,
|
|
230
|
+
compactionIntercept: options.compactionIntercept,
|
|
231
|
+
compactAt: options.compactAt,
|
|
232
|
+
});
|
|
212
233
|
const experimental = options.experimental ?? [];
|
|
213
234
|
const sessionConfig = buildSessionConfig({
|
|
214
235
|
profile: contextProfile,
|
|
@@ -280,12 +301,10 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
280
301
|
say("mnemom agent: the plan shows Remote Control because this machine can run it; the real launch uses it only if your account is entitled (internal Mnemom accounts), else terminal-only.");
|
|
281
302
|
}
|
|
282
303
|
sayContextProfile(contextProfile);
|
|
283
|
-
|
|
304
|
+
sayCompaction(contextProfile, compactionIntercept, compactAt, launchWindow(windowModelFor(options, cli)));
|
|
284
305
|
if (contextHandoff) {
|
|
285
306
|
say("mnemom agent: context handoff ON (experimental) — the `handoff` MCP tool would be registered.");
|
|
286
307
|
}
|
|
287
|
-
if (compactionIntercept)
|
|
288
|
-
say(COMPACTION_INTERCEPT_NOTE);
|
|
289
308
|
return;
|
|
290
309
|
}
|
|
291
310
|
// Real launch: make sure we actually have a CLI to run. If we couldn't find it,
|
|
@@ -456,6 +475,11 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
456
475
|
}
|
|
457
476
|
if (resumed !== null && resumed !== contextProfile) {
|
|
458
477
|
contextProfile = resolveContextProfile({ context: options.context, resumed, env });
|
|
478
|
+
assertOffProfileCompatible({
|
|
479
|
+
profile: contextProfile,
|
|
480
|
+
compactionIntercept: options.compactionIntercept,
|
|
481
|
+
compactAt: options.compactAt,
|
|
482
|
+
});
|
|
459
483
|
sessionConfigB64 = buildSessionConfigB64({
|
|
460
484
|
profile: contextProfile,
|
|
461
485
|
contextHandoff,
|
|
@@ -496,16 +520,14 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
496
520
|
goalMode,
|
|
497
521
|
ccSessionId: cc.id,
|
|
498
522
|
contextProfile,
|
|
499
|
-
compactAt,
|
|
523
|
+
compactAt: contextProfile === "off" ? null : compactAt,
|
|
500
524
|
});
|
|
501
525
|
logLaunch({ shape, door, agent, conversationId, cellNote, envelope, goalMode, cli });
|
|
502
526
|
if (expNotice)
|
|
503
527
|
say(expNotice);
|
|
504
528
|
say(goalAlignmentLine(goalAlignmentMode(envelope, goalMode)));
|
|
505
529
|
sayContextProfile(contextProfile);
|
|
506
|
-
|
|
507
|
-
if (compactionIntercept)
|
|
508
|
-
say(COMPACTION_INTERCEPT_NOTE);
|
|
530
|
+
sayCompaction(contextProfile, compactionIntercept, compactAt, launchWindow(win));
|
|
509
531
|
// ── handoff MCP tool (MNE-7564) ── OFF by default: absent/false ⇒ handoffMcpConfigPath stays
|
|
510
532
|
// undefined and buildCliArgs/spawnRcCli are byte-identical to a build without this flag. ON:
|
|
511
533
|
// the config is written to a 0600 temp file and referenced by PATH only — never inlined into
|
package/dist/index.js
CHANGED
|
@@ -175,7 +175,7 @@ const agentCmd = program
|
|
|
175
175
|
.addOption(new Option("--slack", "EXPERIMENTAL (`mnemom experimental enable slack`): attach the Slack channel — messages addressed to this session arrive in it, and it can reply (see `mnemom agent slack`)").hideHelp(hiddenUnless("slack")))
|
|
176
176
|
.option("--context", "Force context folding ON for this launch even when launcher.toml (context = false) or MNEMOM_AGENT_CONTEXT turns it off")
|
|
177
177
|
.option("--no-context", "Disable context folding for this launch (folding is on by default; tells the gateway to skip it for this session)")
|
|
178
|
-
.addOption(new Option("--context-profile <profile>", 'How the gateway folds this session\'s context. Unset (the default): nothing is sent and the gateway cell\'s own default decides. "balanced" keeps more of the earlier work verbatim and folds later — for long sessions that revisit earlier files and decisions. "aggressive" folds earlier and keeps a tighter working set — for cost-sensitive sessions and short, focused tasks. "adaptive" sizes the fold to the conversation: no fold below 200k tokens, aggressive from 200k to 1M, balanced above. "off" leaves compaction to the coding agent. Applies to this launch only (a resumed session keeps its own); to change the default for every launch: config key context_profile, env MNEMOM_AGENT_CONTEXT_PROFILE.').argParser((v) => {
|
|
178
|
+
.addOption(new Option("--context-profile <profile>", 'How the gateway folds this session\'s context. Unset (the default): nothing is sent and the gateway cell\'s own default decides. "balanced" keeps more of the earlier work verbatim and folds later — for long sessions that revisit earlier files and decisions. "aggressive" folds earlier and keeps a tighter working set — for cost-sensitive sessions and short, focused tasks. "adaptive" sizes the fold to the conversation: no fold below 200k tokens, aggressive from 200k to 1M, balanced above. "off" leaves compaction to the coding agent and never intercepts it (fold, compaction intercept and real-size usage all off; refused with --compaction-intercept or --compact-at <n>). Applies to this launch only (a resumed session keeps its own); to change the default for every launch: config key context_profile, env MNEMOM_AGENT_CONTEXT_PROFILE.').argParser((v) => {
|
|
179
179
|
// One validator for all three surfaces (flag, MNEMOM_AGENT_CONTEXT_PROFILE,
|
|
180
180
|
// launcher.toml context_profile): trimmed, case-insensitive, same error wording.
|
|
181
181
|
try {
|
package/dist/lib/agent.d.ts
CHANGED
|
@@ -300,13 +300,31 @@ export declare const CONTEXT_HEAD_RECLAIM_KEY = "CONTEXT_RUNTIME_HEAD_BREAKPOINT
|
|
|
300
300
|
* gateway's own defaults.
|
|
301
301
|
*/
|
|
302
302
|
export declare const CONTEXT_SIZE_POLICY_KEY = "CONTEXT_RUNTIME_SIZE_POLICY";
|
|
303
|
+
/**
|
|
304
|
+
* The two gateway env keys the `compaction_intercept` setting turns on for a single session
|
|
305
|
+
* (payload-bound fix; both default OFF on the gateway, both read from the per-session overlay):
|
|
306
|
+
* - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
|
|
307
|
+
* REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
|
|
308
|
+
* auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
|
|
309
|
+
* `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
|
|
310
|
+
* - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
|
|
311
|
+
* gateway's own fold digest (no model call), so the compaction never blocks the user.
|
|
312
|
+
* Sent together, value `"on"`, when the `compaction_intercept` setting is on
|
|
313
|
+
* (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below) — a
|
|
314
|
+
* target cannot be honored without both. The `off` context profile sends both as `"off"`.
|
|
315
|
+
*/
|
|
316
|
+
export declare const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
|
|
317
|
+
export declare const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
|
|
303
318
|
/**
|
|
304
319
|
* The named presets for how the gateway folds a session's context (`--context-profile`,
|
|
305
320
|
* launcher.toml `context_profile`, `MNEMOM_AGENT_CONTEXT_PROFILE`). Choosing NONE sends no fold
|
|
306
321
|
* key at all and the cell's own default decides (see `resolveContextProfile`). A chosen profile
|
|
307
322
|
* is complete on its own, so a change to a cell's default can never change what it means:
|
|
308
|
-
* - `off` → `CONTEXT_RUNTIME_ENABLED: "false"`
|
|
309
|
-
*
|
|
323
|
+
* - `off` → `CONTEXT_RUNTIME_ENABLED: "false"` plus `GATEWAY_USAGE_REAL_SIZE: "off"` and
|
|
324
|
+
* `GATEWAY_COMPACTION_INTERCEPT: "off"` — compaction is left to the coding agent
|
|
325
|
+
* and never intercepted, even on a cell whose default turns the intercept on.
|
|
326
|
+
* The gateway already skips the intercept with the fold off, but the real-size
|
|
327
|
+
* usage rewrite is not gated on the fold, so `off` turns both off by name.
|
|
310
328
|
* - `balanced` → `CONTEXT_RUNTIME_SIZE_POLICY: "off"` — the cell's own fold budgets, never
|
|
311
329
|
* the size bands, even on a cell whose default is adaptive.
|
|
312
330
|
* - `aggressive` → a smaller tail budget + read cache and head-breakpoint reclaim on, size
|
|
@@ -326,21 +344,6 @@ export type ContextProfile = (typeof CONTEXT_PROFILES)[number];
|
|
|
326
344
|
* header without the tool.
|
|
327
345
|
*/
|
|
328
346
|
export declare const CONTEXT_HANDOFF_KEY = "CONTEXT_HANDOFF_ENABLED";
|
|
329
|
-
/**
|
|
330
|
-
* The two gateway env keys the `compaction_intercept` setting turns on for a single session
|
|
331
|
-
* (payload-bound fix; both default OFF on the gateway, both read from the per-session overlay):
|
|
332
|
-
* - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
|
|
333
|
-
* REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
|
|
334
|
-
* auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
|
|
335
|
-
* `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
|
|
336
|
-
* - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
|
|
337
|
-
* gateway's own fold digest (no model call), so the compaction never blocks the user.
|
|
338
|
-
* Sent together, value `"on"`, when the `compaction_intercept` setting is on
|
|
339
|
-
* (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below) — a
|
|
340
|
-
* target cannot be honored without both.
|
|
341
|
-
*/
|
|
342
|
-
export declare const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
|
|
343
|
-
export declare const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
|
|
344
347
|
export declare const GATEWAY_COMPACTION_UPLOAD_TARGET_KEY = "GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS";
|
|
345
348
|
/** The lowest token count `--compact-at` / `compact_at` / `MNEMOM_COMPACT_AT` will accept. */
|
|
346
349
|
export declare const COMPACT_AT_MIN_TOKENS = 50000;
|
|
@@ -416,6 +419,19 @@ export declare function assertCompactAtCompatible(opts: {
|
|
|
416
419
|
compactionIntercept?: boolean;
|
|
417
420
|
compactAt: number | null;
|
|
418
421
|
}): void;
|
|
422
|
+
/**
|
|
423
|
+
* The `off` context profile turns the fold off, and the compaction intercept answers a compaction
|
|
424
|
+
* from that fold, so `off` sends the intercept and real-size keys as `"off"`. An explicit
|
|
425
|
+
* `--compaction-intercept` or `--compact-at <N>` in the same launch asks for the opposite —
|
|
426
|
+
* refuse rather than silently drop the flag. A standing intercept or target (environment or
|
|
427
|
+
* launcher.toml) is not refused: the session's `off` wins and `buildSessionConfig` leaves it out.
|
|
428
|
+
* `compactionIntercept` / `compactAt` here are the raw flag values (`undefined` when not passed).
|
|
429
|
+
*/
|
|
430
|
+
export declare function assertOffProfileCompatible(opts: {
|
|
431
|
+
profile: ContextProfile | null;
|
|
432
|
+
compactionIntercept?: boolean;
|
|
433
|
+
compactAt?: number | null;
|
|
434
|
+
}): void;
|
|
419
435
|
/** The launch-banner line for the resolved compaction target (always printed). */
|
|
420
436
|
export declare function describeCompactAt(compactAt: number | null): string;
|
|
421
437
|
/**
|
|
@@ -584,13 +600,16 @@ export declare function resolveContextProfile(opts: {
|
|
|
584
600
|
/**
|
|
585
601
|
* The decoded per-session env overlay for this launch — the `config` object of the
|
|
586
602
|
* `x-mnemom-session-config` payload, in wire order: the profile's keys first
|
|
587
|
-
* (`CONTEXT_RUNTIME_ENABLED` for `off`; the three fold-tuning keys + size policy off for
|
|
603
|
+
* (`CONTEXT_RUNTIME_ENABLED: "false"` + real-size and intercept `"off"` for `off`; the three fold-tuning keys + size policy off for
|
|
588
604
|
* `aggressive`; size policy off for `balanced`; size policy banded for `adaptive`; nothing when
|
|
589
605
|
* no profile was chosen), then `CONTEXT_HANDOFF_ENABLED: "true"` when context handoff is ON, then
|
|
590
606
|
* `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` when EITHER the
|
|
591
607
|
* `compaction_intercept` setting is ON OR `--compact-at` arms a target below 1M (the target
|
|
592
608
|
* cannot be honored without the intercept), then `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"`
|
|
593
|
-
* when a target is set.
|
|
609
|
+
* when a target is set. The `off` profile wins over the intercept and the target: a session with
|
|
610
|
+
* no fold never has its compaction intercepted (`assertOffProfileCompatible` refuses the explicit
|
|
611
|
+
* flag pair; a standing intercept or target from the environment or launcher.toml is dropped).
|
|
612
|
+
* Empty with no profile chosen and everything off — the common case, where
|
|
594
613
|
* no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
|
|
595
614
|
*/
|
|
596
615
|
export declare function buildSessionConfig(opts: {
|
package/dist/lib/agent.js
CHANGED
|
@@ -458,13 +458,31 @@ export const CONTEXT_HEAD_RECLAIM_KEY = "CONTEXT_RUNTIME_HEAD_BREAKPOINT_RECLAIM
|
|
|
458
458
|
* gateway's own defaults.
|
|
459
459
|
*/
|
|
460
460
|
export const CONTEXT_SIZE_POLICY_KEY = "CONTEXT_RUNTIME_SIZE_POLICY";
|
|
461
|
+
/**
|
|
462
|
+
* The two gateway env keys the `compaction_intercept` setting turns on for a single session
|
|
463
|
+
* (payload-bound fix; both default OFF on the gateway, both read from the per-session overlay):
|
|
464
|
+
* - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
|
|
465
|
+
* REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
|
|
466
|
+
* auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
|
|
467
|
+
* `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
|
|
468
|
+
* - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
|
|
469
|
+
* gateway's own fold digest (no model call), so the compaction never blocks the user.
|
|
470
|
+
* Sent together, value `"on"`, when the `compaction_intercept` setting is on
|
|
471
|
+
* (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below) — a
|
|
472
|
+
* target cannot be honored without both. The `off` context profile sends both as `"off"`.
|
|
473
|
+
*/
|
|
474
|
+
export const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
|
|
475
|
+
export const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
|
|
461
476
|
/**
|
|
462
477
|
* The named presets for how the gateway folds a session's context (`--context-profile`,
|
|
463
478
|
* launcher.toml `context_profile`, `MNEMOM_AGENT_CONTEXT_PROFILE`). Choosing NONE sends no fold
|
|
464
479
|
* key at all and the cell's own default decides (see `resolveContextProfile`). A chosen profile
|
|
465
480
|
* is complete on its own, so a change to a cell's default can never change what it means:
|
|
466
|
-
* - `off` → `CONTEXT_RUNTIME_ENABLED: "false"`
|
|
467
|
-
*
|
|
481
|
+
* - `off` → `CONTEXT_RUNTIME_ENABLED: "false"` plus `GATEWAY_USAGE_REAL_SIZE: "off"` and
|
|
482
|
+
* `GATEWAY_COMPACTION_INTERCEPT: "off"` — compaction is left to the coding agent
|
|
483
|
+
* and never intercepted, even on a cell whose default turns the intercept on.
|
|
484
|
+
* The gateway already skips the intercept with the fold off, but the real-size
|
|
485
|
+
* usage rewrite is not gated on the fold, so `off` turns both off by name.
|
|
468
486
|
* - `balanced` → `CONTEXT_RUNTIME_SIZE_POLICY: "off"` — the cell's own fold budgets, never
|
|
469
487
|
* the size bands, even on a cell whose default is adaptive.
|
|
470
488
|
* - `aggressive` → a smaller tail budget + read cache and head-breakpoint reclaim on, size
|
|
@@ -476,7 +494,11 @@ export const CONTEXT_SIZE_POLICY_KEY = "CONTEXT_RUNTIME_SIZE_POLICY";
|
|
|
476
494
|
export const CONTEXT_PROFILES = ["off", "balanced", "aggressive", "adaptive"];
|
|
477
495
|
/** The per-session env overlay each profile expands to (key order is the wire order). */
|
|
478
496
|
const CONTEXT_PROFILE_CONFIG = {
|
|
479
|
-
off: [
|
|
497
|
+
off: [
|
|
498
|
+
[CONTEXT_RUNTIME_KEY, "false"],
|
|
499
|
+
[USAGE_REAL_SIZE_KEY, "off"],
|
|
500
|
+
[COMPACTION_INTERCEPT_KEY, "off"],
|
|
501
|
+
],
|
|
480
502
|
balanced: [[CONTEXT_SIZE_POLICY_KEY, "off"]],
|
|
481
503
|
aggressive: [
|
|
482
504
|
[CONTEXT_TAIL_BUDGET_KEY, "60000"],
|
|
@@ -495,21 +517,6 @@ const CONTEXT_PROFILE_CONFIG = {
|
|
|
495
517
|
* header without the tool.
|
|
496
518
|
*/
|
|
497
519
|
export const CONTEXT_HANDOFF_KEY = "CONTEXT_HANDOFF_ENABLED";
|
|
498
|
-
/**
|
|
499
|
-
* The two gateway env keys the `compaction_intercept` setting turns on for a single session
|
|
500
|
-
* (payload-bound fix; both default OFF on the gateway, both read from the per-session overlay):
|
|
501
|
-
* - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
|
|
502
|
-
* REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
|
|
503
|
-
* auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
|
|
504
|
-
* `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
|
|
505
|
-
* - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
|
|
506
|
-
* gateway's own fold digest (no model call), so the compaction never blocks the user.
|
|
507
|
-
* Sent together, value `"on"`, when the `compaction_intercept` setting is on
|
|
508
|
-
* (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below) — a
|
|
509
|
-
* target cannot be honored without both.
|
|
510
|
-
*/
|
|
511
|
-
export const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
|
|
512
|
-
export const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
|
|
513
520
|
// ---------------------------------------------------------------------------
|
|
514
521
|
// Compaction target (`--compact-at`, launcher.toml `compact_at`, MNEMOM_COMPACT_AT)
|
|
515
522
|
// ---------------------------------------------------------------------------
|
|
@@ -656,6 +663,28 @@ export function assertCompactAtCompatible(opts) {
|
|
|
656
663
|
"enable compaction-intercept`), or pass --compact-at off.");
|
|
657
664
|
}
|
|
658
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* The `off` context profile turns the fold off, and the compaction intercept answers a compaction
|
|
668
|
+
* from that fold, so `off` sends the intercept and real-size keys as `"off"`. An explicit
|
|
669
|
+
* `--compaction-intercept` or `--compact-at <N>` in the same launch asks for the opposite —
|
|
670
|
+
* refuse rather than silently drop the flag. A standing intercept or target (environment or
|
|
671
|
+
* launcher.toml) is not refused: the session's `off` wins and `buildSessionConfig` leaves it out.
|
|
672
|
+
* `compactionIntercept` / `compactAt` here are the raw flag values (`undefined` when not passed).
|
|
673
|
+
*/
|
|
674
|
+
export function assertOffProfileCompatible(opts) {
|
|
675
|
+
if (opts.profile !== "off")
|
|
676
|
+
return;
|
|
677
|
+
const flag = opts.compactionIntercept === true
|
|
678
|
+
? "--compaction-intercept"
|
|
679
|
+
: typeof opts.compactAt === "number"
|
|
680
|
+
? "--compact-at"
|
|
681
|
+
: null;
|
|
682
|
+
if (flag === null)
|
|
683
|
+
return;
|
|
684
|
+
throw new Error(`mnemom agent: context profile off and ${flag} disagree — with the fold off the gateway has ` +
|
|
685
|
+
`no fold to answer a compaction from, so off sends the compaction intercept off. Drop ` +
|
|
686
|
+
`${flag}, or choose another --context-profile.`);
|
|
687
|
+
}
|
|
659
688
|
/**
|
|
660
689
|
* `200000` → `"200k"`, anything not k-aligned → the bare digits. Every real caller only ever
|
|
661
690
|
* passes a `parseCompactAt`-validated value, which is bounded to
|
|
@@ -953,13 +982,16 @@ export function resolveContextProfile(opts) {
|
|
|
953
982
|
/**
|
|
954
983
|
* The decoded per-session env overlay for this launch — the `config` object of the
|
|
955
984
|
* `x-mnemom-session-config` payload, in wire order: the profile's keys first
|
|
956
|
-
* (`CONTEXT_RUNTIME_ENABLED` for `off`; the three fold-tuning keys + size policy off for
|
|
985
|
+
* (`CONTEXT_RUNTIME_ENABLED: "false"` + real-size and intercept `"off"` for `off`; the three fold-tuning keys + size policy off for
|
|
957
986
|
* `aggressive`; size policy off for `balanced`; size policy banded for `adaptive`; nothing when
|
|
958
987
|
* no profile was chosen), then `CONTEXT_HANDOFF_ENABLED: "true"` when context handoff is ON, then
|
|
959
988
|
* `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` when EITHER the
|
|
960
989
|
* `compaction_intercept` setting is ON OR `--compact-at` arms a target below 1M (the target
|
|
961
990
|
* cannot be honored without the intercept), then `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"`
|
|
962
|
-
* when a target is set.
|
|
991
|
+
* when a target is set. The `off` profile wins over the intercept and the target: a session with
|
|
992
|
+
* no fold never has its compaction intercepted (`assertOffProfileCompatible` refuses the explicit
|
|
993
|
+
* flag pair; a standing intercept or target from the environment or launcher.toml is dropped).
|
|
994
|
+
* Empty with no profile chosen and everything off — the common case, where
|
|
963
995
|
* no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
|
|
964
996
|
*/
|
|
965
997
|
export function buildSessionConfig(opts) {
|
|
@@ -974,6 +1006,8 @@ export function buildSessionConfig(opts) {
|
|
|
974
1006
|
// A target needs the compaction intercept + real-size rewrite to arm (#2216) — without them
|
|
975
1007
|
// the upload-target key is silently inert (compaction-align.ts: "armed only inside the
|
|
976
1008
|
// intercept"). Deliberately NOT GATEWAY_COMPACTION_REFOLD — a separate, costlier opt-in.
|
|
1009
|
+
if (opts.profile === "off")
|
|
1010
|
+
return config;
|
|
977
1011
|
if (opts.compactionIntercept || hasCompactionTarget) {
|
|
978
1012
|
config[USAGE_REAL_SIZE_KEY] = "on";
|
|
979
1013
|
config[COMPACTION_INTERCEPT_KEY] = "on";
|