@mnemom/mnemom 0.17.2-next.1 → 0.17.2-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.
@@ -52,6 +52,12 @@ export interface AgentOptions {
52
52
  trimMcp?: boolean;
53
53
  /** yolo default: commander `--no-yolo` sets this false. */
54
54
  yolo?: boolean;
55
+ /**
56
+ * Context folding: undefined = default ON, false = `--no-context`, true =
57
+ * `--context`. When OFF the launch sends `x-mnemom-session-config` telling the
58
+ * gateway to skip folding for this session only.
59
+ */
60
+ context?: boolean;
55
61
  /** context-hint seed default: commander `--no-context-hint` sets this false. */
56
62
  contextHint?: boolean;
57
63
  /**
@@ -38,7 +38,7 @@ import { fmt } from "../lib/format.js";
38
38
  import { askInput, askSelect, askYesNo, isInteractive } from "../lib/prompt.js";
39
39
  import { goalAlignmentLine, resolveSessionSetup } from "./agent-session.js";
40
40
  import { defaultAgentSlug, ensureGovernedAgent, ensureSessionAndBalance, isQuietPreambleExit, resolveDefaultSlug, } from "./agent-setup.js";
41
- import { assembleContract, buildGoalModeHeader, buildCustomHeaders, isProdGateway, launchPreferenceExplicit, remoteControlAllowed, resolveAnthropicDoor, resolveConversationId, resolveGatewayHost, resolveLaunchShape, resolveRemoteControlShape, sanitizeAgentName, } from "../lib/agent.js";
41
+ import { assembleContract, buildGoalModeHeader, buildCustomHeaders, buildSessionConfigB64, resolveContextFold, isProdGateway, launchPreferenceExplicit, remoteControlAllowed, resolveAnthropicDoor, resolveConversationId, resolveGatewayHost, resolveLaunchShape, resolveRemoteControlShape, sanitizeAgentName, } from "../lib/agent.js";
42
42
  /** The CLI's own provider-key store (zero 1Password): ~/.mnemom/launcher.json, 0600. */
43
43
  const CODE_STORE = join(MNEMOM_DIR, "launcher.json");
44
44
  const say = (line = "") => console.error(line);
@@ -96,6 +96,11 @@ export async function agentCommand(scenarioArg, options = {}) {
96
96
  const cellNote = isProdGateway(env) ? "us-2/prod" : `custom (${gatewayHost})`;
97
97
  const yolo = options.yolo !== false; // default ON
98
98
  const contextHint = options.contextHint !== false; // default ON
99
+ // Context folding is ON by default; --no-context (or `context = false` in
100
+ // launcher.toml → MNEMOM_AGENT_CONTEXT) turns it off for this session via the
101
+ // per-session config header. `undefined` sessionConfigB64 ⇒ nothing sent.
102
+ const contextFold = resolveContextFold({ context: options.context, env });
103
+ const sessionConfigB64 = buildSessionConfigB64(contextFold);
99
104
  // ── which CLI executable (name or full path) ── resolve GRACEFULLY: if it's not
100
105
  // found we don't crash with a technical error — we ask for the path at launch.
101
106
  let cli;
@@ -138,6 +143,9 @@ export async function agentCommand(scenarioArg, options = {}) {
138
143
  if (previewShape === "remote-control") {
139
144
  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.");
140
145
  }
146
+ if (!contextFold) {
147
+ say("mnemom agent: context folding OFF for this session (--no-context or context = false).");
148
+ }
141
149
  return;
142
150
  }
143
151
  // Real launch: make sure we actually have a CLI to run. If we couldn't find it,
@@ -235,6 +243,9 @@ export async function agentCommand(scenarioArg, options = {}) {
235
243
  });
236
244
  logLaunch({ shape, door, agent, conversationId, cellNote, envelope, goalMode, cli });
237
245
  say(goalAlignmentLine(goalAlignmentMode(envelope, goalMode)));
246
+ if (!contextFold) {
247
+ say("mnemom agent: context folding OFF for this session (--no-context or context = false).");
248
+ }
238
249
  if (shape === "terminal") {
239
250
  launchTerminal({
240
251
  cli,
@@ -244,6 +255,7 @@ export async function agentCommand(scenarioArg, options = {}) {
244
255
  conversationId,
245
256
  envelope,
246
257
  goalMode,
258
+ sessionConfigB64,
247
259
  options,
248
260
  yolo,
249
261
  contextHint,
@@ -260,6 +272,7 @@ export async function agentCommand(scenarioArg, options = {}) {
260
272
  scenario,
261
273
  envelope,
262
274
  goalMode,
275
+ sessionConfigB64,
263
276
  options,
264
277
  yolo,
265
278
  });
@@ -544,6 +557,7 @@ function launchTerminal(ctx) {
544
557
  conversationId: ctx.conversationId,
545
558
  contractB64: ctx.envelope?.base64,
546
559
  goalMode: ctx.goalMode ?? undefined,
560
+ sessionConfigB64: ctx.sessionConfigB64,
547
561
  });
548
562
  const args = buildCliArgs(ctx.options, { yolo: ctx.yolo, allowCliFlags: true });
549
563
  // Claude Code logged in via claude.ai (OAuth) PREEMPTS ANTHROPIC_API_KEY, so
@@ -592,6 +606,7 @@ function launchRemoteControl(ctx) {
592
606
  MNEMOM_AGENT_RC_CONVERSATION_ID: ctx.conversationId,
593
607
  MNEMOM_AGENT_RC_CONTRACT_B64: ctx.envelope?.base64 ?? "",
594
608
  MNEMOM_AGENT_RC_GOAL_MODE: ctx.goalMode ?? "",
609
+ MNEMOM_AGENT_RC_SESSION_CONFIG: ctx.sessionConfigB64 ?? "",
595
610
  MNEMOM_AGENT_RC_PROXY_LOG: proxyLog,
596
611
  MNEMOM_AGENT_RC_PARENT_PID: String(process.pid),
597
612
  },
package/dist/index.js CHANGED
@@ -134,6 +134,8 @@ const agentCmd = program
134
134
  .option("--no-setup", "Skip governed-agent provisioning entirely for this launch")
135
135
  .option("--no-yolo", "Do NOT pass --dangerously-skip-permissions (yolo is on by default)")
136
136
  .option("--no-context-hint", "Do NOT seed Claude Code's context-hint feature flag before launch")
137
+ .option("--context", "Force context folding ON for this launch even when launcher.toml (context = false) or MNEMOM_AGENT_CONTEXT turns it off")
138
+ .option("--no-context", "Disable context folding for this launch (folding is on by default; tells the gateway to skip it for this session)")
137
139
  .option("--dry-run", "Print the resolved launch plan and exit — no key read, no spawn")
138
140
  .action(async (scenario, passthrough, opts) => {
139
141
  try {
@@ -215,6 +217,7 @@ const agentCmd = program
215
217
  trimMcp: opts.trimMcp,
216
218
  yolo: opts.yolo,
217
219
  contextHint: opts.contextHint,
220
+ context: opts.context,
218
221
  setup: opts.setup,
219
222
  keySource: cfg.keySource,
220
223
  passthrough,
@@ -126,6 +126,15 @@ export interface SealedContractEnvelope {
126
126
  export declare function assembleContract(flags: ContractFlags): SealedContractEnvelope | null;
127
127
  /** The request header that opts a conversation into implicit goal mode. */
128
128
  export declare const GOAL_MODE_HEADER = "x-mnemom-goal-mode";
129
+ /**
130
+ * Per-session env overlay the gateway honours (`session-config.ts`
131
+ * SESSION_CONFIG_HEADER). base64url(JSON) of `{ v, config: { KEY: "value" } }`,
132
+ * keys drawn from the gateway's allow-list. Today the CLI uses it for exactly
133
+ * one thing: turning context folding off for a single launch.
134
+ */
135
+ export declare const SESSION_CONFIG_HEADER = "x-mnemom-session-config";
136
+ /** The gateway env key that gates context folding (allow-listed for per-session overlay). */
137
+ export declare const CONTEXT_RUNTIME_KEY = "CONTEXT_RUNTIME_ENABLED";
129
138
  /**
130
139
  * The `x-mnemom-goal-mode` header value for `--implicit`, or null when the flag
131
140
  * is absent: `implicit[; max_turns=N][; budget_usd=X][; stall_turns=N]` — the
@@ -204,7 +213,26 @@ export declare function buildCustomHeaders(opts: {
204
213
  contractB64?: string;
205
214
  /** `buildGoalModeHeader` output for an `--implicit` launch. */
206
215
  goalMode?: string;
216
+ /** `buildSessionConfigB64` output — the per-session env overlay (e.g. fold off). */
217
+ sessionConfigB64?: string;
207
218
  }): string;
219
+ /**
220
+ * Whether context folding is ON for this launch. Folding is a gateway feature
221
+ * that summarises older turns to fit the window; it is ON by default. Precedence:
222
+ * an explicit `--context`/`--no-context` flag wins, else `MNEMOM_AGENT_CONTEXT`
223
+ * (which `applyConfigToEnv` sets from the `context` config key), else ON.
224
+ * Recognised OFF values for the env var: `0`, `false`, `off`, `no` (case-insensitive).
225
+ */
226
+ export declare function resolveContextFold(opts: {
227
+ context?: boolean;
228
+ env?: NodeJS.ProcessEnv;
229
+ }): boolean;
230
+ /**
231
+ * The `x-mnemom-session-config` value that turns context folding OFF, or
232
+ * `undefined` when folding is ON (the default — nothing is sent, the gateway's
233
+ * own default stands). base64url so it survives the gateway's inbound strip.
234
+ */
235
+ export declare function buildSessionConfigB64(fold: boolean): string | undefined;
208
236
  /**
209
237
  * The persistable goal-alignment default (`launcher.toml` `goal_mode`). Only the
210
238
  * two statement-free modes can be a standing default: a SEALED contract needs a
package/dist/lib/agent.js CHANGED
@@ -186,6 +186,15 @@ export function assembleContract(flags) {
186
186
  }
187
187
  /** The request header that opts a conversation into implicit goal mode. */
188
188
  export const GOAL_MODE_HEADER = "x-mnemom-goal-mode";
189
+ /**
190
+ * Per-session env overlay the gateway honours (`session-config.ts`
191
+ * SESSION_CONFIG_HEADER). base64url(JSON) of `{ v, config: { KEY: "value" } }`,
192
+ * keys drawn from the gateway's allow-list. Today the CLI uses it for exactly
193
+ * one thing: turning context folding off for a single launch.
194
+ */
195
+ export const SESSION_CONFIG_HEADER = "x-mnemom-session-config";
196
+ /** The gateway env key that gates context folding (allow-listed for per-session overlay). */
197
+ export const CONTEXT_RUNTIME_KEY = "CONTEXT_RUNTIME_ENABLED";
189
198
  const SEALED_ONLY_FLAGS = "--goal/--requirement/--allow/--forbid/--goal-id";
190
199
  /**
191
200
  * `--implicit` and a sealed contract are mutually exclusive: on the gateway a
@@ -352,8 +361,36 @@ export function buildCustomHeaders(opts) {
352
361
  lines.push(`x-mnemom-contract: ${opts.contractB64}`);
353
362
  if (opts.goalMode)
354
363
  lines.push(`${GOAL_MODE_HEADER}: ${opts.goalMode}`);
364
+ if (opts.sessionConfigB64)
365
+ lines.push(`${SESSION_CONFIG_HEADER}: ${opts.sessionConfigB64}`);
355
366
  return lines.join("\n");
356
367
  }
368
+ /**
369
+ * Whether context folding is ON for this launch. Folding is a gateway feature
370
+ * that summarises older turns to fit the window; it is ON by default. Precedence:
371
+ * an explicit `--context`/`--no-context` flag wins, else `MNEMOM_AGENT_CONTEXT`
372
+ * (which `applyConfigToEnv` sets from the `context` config key), else ON.
373
+ * Recognised OFF values for the env var: `0`, `false`, `off`, `no` (case-insensitive).
374
+ */
375
+ export function resolveContextFold(opts) {
376
+ if (opts.context !== undefined)
377
+ return opts.context;
378
+ const raw = (opts.env?.MNEMOM_AGENT_CONTEXT ?? "").trim().toLowerCase();
379
+ if (raw === "")
380
+ return true;
381
+ return !(raw === "0" || raw === "false" || raw === "off" || raw === "no");
382
+ }
383
+ /**
384
+ * The `x-mnemom-session-config` value that turns context folding OFF, or
385
+ * `undefined` when folding is ON (the default — nothing is sent, the gateway's
386
+ * own default stands). base64url so it survives the gateway's inbound strip.
387
+ */
388
+ export function buildSessionConfigB64(fold) {
389
+ if (fold)
390
+ return undefined;
391
+ const payload = JSON.stringify({ v: 1, config: { [CONTEXT_RUNTIME_KEY]: "false" } });
392
+ return Buffer.from(payload, "utf8").toString("base64url");
393
+ }
357
394
  /**
358
395
  * Is this launch implicit-mode? Precedence, highest wins:
359
396
  * 1. an explicit flag — `--implicit` (true) or `--no-implicit` (false);
@@ -31,6 +31,8 @@ export interface LauncherConfig {
31
31
  keySource?: KeySource;
32
32
  /** Standing goal-alignment default when neither --goal nor --implicit is given. */
33
33
  goalMode?: GoalModeDefault;
34
+ /** Context folding default (on when unset; `false` disables it for every launch). */
35
+ context?: boolean;
34
36
  guardrails?: {
35
37
  maxTurns?: number;
36
38
  budgetUsd?: number;
@@ -45,7 +47,7 @@ export interface LauncherConfig {
45
47
  export interface ConfigKeySpec {
46
48
  key: string;
47
49
  describe: string;
48
- get(cfg: LauncherConfig): string | number | undefined;
50
+ get(cfg: LauncherConfig): string | number | boolean | undefined;
49
51
  set(cfg: LauncherConfig, raw: string): void;
50
52
  }
51
53
  /** The full set of settable keys — drives get/set/unset/list and validation. */
@@ -38,6 +38,16 @@ function coerceEffort(raw) {
38
38
  return v;
39
39
  throw new Error(`effort must be one of ${EFFORTS.join(", ")} (got '${raw}').`);
40
40
  }
41
+ const TRUE_WORDS = ["true", "1", "on", "yes"];
42
+ const FALSE_WORDS = ["false", "0", "off", "no"];
43
+ function coerceBool(name, raw) {
44
+ const s = raw.trim().toLowerCase();
45
+ if (TRUE_WORDS.includes(s))
46
+ return true;
47
+ if (FALSE_WORDS.includes(s))
48
+ return false;
49
+ throw new Error(`${name} must be a boolean (${[...TRUE_WORDS, ...FALSE_WORDS].join("|")}); got '${raw}'.`);
50
+ }
41
51
  function coerceKeySource(raw) {
42
52
  const v = raw.trim();
43
53
  if (KEY_SOURCES.includes(v))
@@ -127,6 +137,14 @@ export const CONFIG_KEYS = [
127
137
  c.goalMode = coerceGoalMode(v);
128
138
  },
129
139
  },
140
+ {
141
+ key: "context",
142
+ describe: "Context folding (on by default; false disables it for every launch)",
143
+ get: (c) => c.context,
144
+ set: (c, v) => {
145
+ c.context = coerceBool("context", v);
146
+ },
147
+ },
130
148
  {
131
149
  key: "guardrails.max_turns",
132
150
  describe: "Contract guardrail: turn ceiling (positive integer)",
@@ -193,6 +211,8 @@ export function parseLauncherConfig(text) {
193
211
  cfg.keySource = coerceKeySource(str(raw.key_source) ?? "");
194
212
  if (raw.goal_mode !== undefined)
195
213
  cfg.goalMode = coerceGoalMode(str(raw.goal_mode) ?? "");
214
+ if (raw.context !== undefined)
215
+ cfg.context = coerceBool("context", str(raw.context) ?? "");
196
216
  const g = raw.guardrails;
197
217
  if (g !== undefined) {
198
218
  if (typeof g !== "object" || g === null || Array.isArray(g)) {
@@ -251,6 +271,8 @@ export function serializeLauncherConfig(cfg) {
251
271
  doc.key_source = cfg.keySource;
252
272
  if (cfg.goalMode !== undefined)
253
273
  doc.goal_mode = cfg.goalMode;
274
+ if (cfg.context !== undefined)
275
+ doc.context = cfg.context;
254
276
  const g = cfg.guardrails;
255
277
  if (g && (g.maxTurns !== undefined || g.budgetUsd !== undefined || g.stallTurns !== undefined)) {
256
278
  const gr = {};
@@ -297,4 +319,7 @@ export function applyConfigToEnv(cfg, env = process.env) {
297
319
  env.MNEMOM_AGENT_REMOTE_CONTROL =
298
320
  cfg.launch === "server" ? "server" : cfg.launch === "remote-control" ? "1" : "0";
299
321
  }
322
+ if (cfg.context !== undefined && !(env.MNEMOM_AGENT_CONTEXT ?? "").trim()) {
323
+ env.MNEMOM_AGENT_CONTEXT = cfg.context ? "1" : "0";
324
+ }
300
325
  }
package/dist/rc-proxy.mjs CHANGED
@@ -64,6 +64,7 @@
64
64
  // MNEMOM_AGENT_RC_CONTRACT_B64 base64 contract for x-mnemom-contract (optional)
65
65
  // MNEMOM_AGENT_RC_GOAL_MODE x-mnemom-goal-mode value (optional; `--implicit` — no contract,
66
66
  // the gateway infers the goal from the user's messages)
67
+ // MNEMOM_AGENT_RC_SESSION_CONFIG x-mnemom-session-config value (optional; per-session env overlay, e.g. context folding off)
67
68
  // MNEMOM_AGENT_RC_PROVIDER x-mnemom-provider directive JSON (optional; router door)
68
69
  // MNEMOM_AGENT_RC_THREAD_MODE `reject` (default: answer thread-bearing requests locally,
69
70
  // see above) | `strip` (legacy: delete `thread`, forward)
@@ -101,6 +102,7 @@ const CONV =
101
102
  env.MNEMOM_AGENT_RC_CONVERSATION_ID || die("MNEMOM_AGENT_RC_CONVERSATION_ID is required");
102
103
  const CONTRACT_B64 = env.MNEMOM_AGENT_RC_CONTRACT_B64 || "";
103
104
  const GOAL_MODE = env.MNEMOM_AGENT_RC_GOAL_MODE || "";
105
+ const SESSION_CONFIG = env.MNEMOM_AGENT_RC_SESSION_CONFIG || "";
104
106
  const PROVIDER = env.MNEMOM_AGENT_RC_PROVIDER || "";
105
107
  const THREAD_MODE = env.MNEMOM_AGENT_RC_THREAD_MODE || "reject";
106
108
  if (THREAD_MODE !== "reject" && THREAD_MODE !== "strip")
@@ -351,6 +353,7 @@ function handle(req, res, viaPlain) {
351
353
  if (secrets.openai) headers["x-mnemom-egress-key"] = secrets.openai;
352
354
  if (CONTRACT_B64) headers["x-mnemom-contract"] = CONTRACT_B64;
353
355
  if (GOAL_MODE) headers["x-mnemom-goal-mode"] = GOAL_MODE;
356
+ if (SESSION_CONFIG) headers["x-mnemom-session-config"] = SESSION_CONFIG;
354
357
  if (headers["anthropic-beta"]) {
355
358
  // drop the OAuth-only beta tokens
356
359
  const b = String(headers["anthropic-beta"])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemom/mnemom",
3
- "version": "0.17.2-next.1",
3
+ "version": "0.17.2-next.2",
4
4
  "description": "Transparent AI agent tracing",
5
5
  "type": "module",
6
6
  "bin": {