@mnemom/mnemom 0.17.2-next.0 → 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.
@@ -13,7 +13,7 @@
13
13
  * local sha is never printed as "the sealed hash" and no mismatch is flagged —
14
14
  * only the server's hash is shown, labelled "sealed hash".
15
15
  */
16
- import { type SessionRecord } from "../lib/agent-ledger.js";
16
+ import { type GoalMode, type SessionRecord } from "../lib/agent-ledger.js";
17
17
  import { type AgentSessionResponse } from "../lib/api.js";
18
18
  export interface SessionCommandDeps {
19
19
  /** The ledger, newest first. */
@@ -47,8 +47,19 @@ export interface SessionRefAmbiguous {
47
47
  * - nothing matches (or the ledger is empty) → null.
48
48
  */
49
49
  export declare function resolveSessionRef(records: SessionRecord[], ref?: string): SessionRefMatch | SessionRefAmbiguous | null;
50
- /** Goal alignment as the ledger recorded it: a contract at launch ⇒ on. */
51
- export declare function localGoalFlag(record: SessionRecord): "on" | "off";
50
+ /**
51
+ * Goal-alignment mode as the ledger recorded it. Prefers the explicit
52
+ * `goal_mode` (which alone distinguishes `implicit` from `off`); records
53
+ * written before that field existed fall back to `contract ? "on" : "off"`.
54
+ */
55
+ export declare function localGoalFlag(record: SessionRecord): GoalMode;
56
+ /**
57
+ * Goal-alignment mode for the `show` view: the live gateway state wins when it
58
+ * is present (a sealed contract ⇒ `on`), otherwise the locally recorded mode.
59
+ * A gateway with no sealed contract can still be an `implicit` session, so the
60
+ * local `goal_mode` fills that in.
61
+ */
62
+ export declare function resolveGoalMode(local: SessionRecord, remote: AgentSessionResponse | null): GoalMode;
52
63
  /**
53
64
  * Render the ledger as a table, newest first — the newest
54
65
  * `DEFAULT_SESSIONS_LIMIT` rows unless `all`, with a footer naming the rest.
@@ -69,7 +80,7 @@ export interface ShowJson {
69
80
  session: SessionRecord & {
70
81
  source: "local";
71
82
  };
72
- goal_alignment: "on" | "off";
83
+ goal_alignment: GoalMode;
73
84
  live: {
74
85
  source: "gateway";
75
86
  available: true;
@@ -55,15 +55,46 @@ export function resolveSessionRef(records, ref) {
55
55
  return null;
56
56
  }
57
57
  // ─── sessions table ───────────────────────────────────────────────────────────
58
- const COL = { session: 26, started: 16, agent: 22, goal: 6, conv: 8 };
58
+ const COL = { session: 26, started: 16, agent: 22, goal: 10, conv: 8 };
59
59
  function cell(text, width) {
60
60
  const max = width - 2;
61
61
  const shown = text.length > max ? `${text.slice(0, max - 1)}…` : text;
62
62
  return shown.padEnd(width);
63
63
  }
64
- /** Goal alignment as the ledger recorded it: a contract at launch ⇒ on. */
64
+ /**
65
+ * Goal-alignment mode as the ledger recorded it. Prefers the explicit
66
+ * `goal_mode` (which alone distinguishes `implicit` from `off`); records
67
+ * written before that field existed fall back to `contract ? "on" : "off"`.
68
+ */
65
69
  export function localGoalFlag(record) {
66
- return record.contract ? "on" : "off";
70
+ return record.goal_mode ?? (record.contract ? "on" : "off");
71
+ }
72
+ /**
73
+ * Goal-alignment mode for the `show` view: the live gateway state wins when it
74
+ * is present (a sealed contract ⇒ `on`), otherwise the locally recorded mode.
75
+ * A gateway with no sealed contract can still be an `implicit` session, so the
76
+ * local `goal_mode` fills that in.
77
+ */
78
+ export function resolveGoalMode(local, remote) {
79
+ if (remote) {
80
+ // Live truth wins: a sealed contract ⇒ on. When the gateway has NO sealed
81
+ // contract, the session is either implicit or off — and only the local
82
+ // `goal_mode` distinguishes those. A stale local "on" (a contract that has
83
+ // since cleared/expired/been revoked on the gateway) must NOT resurrect an
84
+ // "on" the live state contradicts, so only "implicit" is recovered here.
85
+ if (remote.sealed !== null)
86
+ return "on";
87
+ return local.goal_mode === "implicit" ? "implicit" : "off";
88
+ }
89
+ return localGoalFlag(local);
90
+ }
91
+ /** The badge for a goal mode: on → green, implicit → cyan, off → yellow. */
92
+ function goalBadge(mode) {
93
+ if (mode === "on")
94
+ return fmt.badge("ON", "green");
95
+ if (mode === "implicit")
96
+ return fmt.badge("IMPLICIT", "cyan");
97
+ return fmt.badge("OFF", "yellow");
67
98
  }
68
99
  /**
69
100
  * Render the ledger as a table, newest first — the newest
@@ -123,8 +154,8 @@ export function buildShowView(local, remote, reason) {
123
154
  launchBits.push(`effort ${local.effort}`);
124
155
  L.push(fmt.label("launch: ", launchBits.join(" · ")));
125
156
  L.push(fmt.label("conversation: ", local.conversation_id));
126
- const goalOn = remote ? remote.sealed !== null : local.contract !== null;
127
- L.push(fmt.label("goal alignment:", goalOn ? fmt.badge("ON", "green") : fmt.badge("OFF", "yellow")));
157
+ const goalMode = resolveGoalMode(local, remote);
158
+ L.push(fmt.label("goal alignment:", goalBadge(goalMode)));
128
159
  if (local.contract) {
129
160
  L.push(fmt.label("goal (at launch):", local.contract.statement));
130
161
  }
@@ -176,10 +207,9 @@ export function buildShowView(local, remote, reason) {
176
207
  return L;
177
208
  }
178
209
  export function buildShowJson(local, remote, reason) {
179
- const goalOn = remote ? remote.sealed !== null : local.contract !== null;
180
210
  return {
181
211
  session: { ...local, source: "local" },
182
- goal_alignment: goalOn ? "on" : "off",
212
+ goal_alignment: resolveGoalMode(local, remote),
183
213
  live: remote
184
214
  ? {
185
215
  source: "gateway",
@@ -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
  /**
@@ -91,6 +97,7 @@ export declare function recordSessionLaunch(ctx: {
91
97
  options: AgentOptions;
92
98
  cli: ResolvedCli;
93
99
  envelope: SealedContractEnvelope | null;
100
+ goalMode: string | null;
94
101
  }): Promise<void>;
95
102
  /**
96
103
  * Resolve the Anthropic key with NO 1Password dependency (built for external
@@ -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,
@@ -231,9 +239,13 @@ export async function agentCommand(scenarioArg, options = {}) {
231
239
  options,
232
240
  cli,
233
241
  envelope,
242
+ goalMode,
234
243
  });
235
244
  logLaunch({ shape, door, agent, conversationId, cellNote, envelope, goalMode, cli });
236
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
+ }
237
249
  if (shape === "terminal") {
238
250
  launchTerminal({
239
251
  cli,
@@ -243,6 +255,7 @@ export async function agentCommand(scenarioArg, options = {}) {
243
255
  conversationId,
244
256
  envelope,
245
257
  goalMode,
258
+ sessionConfigB64,
246
259
  options,
247
260
  yolo,
248
261
  contextHint,
@@ -259,6 +272,7 @@ export async function agentCommand(scenarioArg, options = {}) {
259
272
  scenario,
260
273
  envelope,
261
274
  goalMode,
275
+ sessionConfigB64,
262
276
  options,
263
277
  yolo,
264
278
  });
@@ -292,6 +306,7 @@ export async function recordSessionLaunch(ctx) {
292
306
  effort: ctx.options.effort?.trim() || null,
293
307
  cli: ctx.cli.name,
294
308
  contract: toLedgerContract(ctx.envelope?.contract ?? null),
309
+ goal_mode: goalAlignmentMode(ctx.envelope, ctx.goalMode),
295
310
  }, { dir: MNEMOM_DIR, now: () => new Date(), pid: process.pid });
296
311
  if (!result.ok) {
297
312
  say(fmt.warn(`mnemom agent: could not record this session in ~/.mnemom/${LEDGER_FILE} (${result.error}) — launching anyway.`));
@@ -542,6 +557,7 @@ function launchTerminal(ctx) {
542
557
  conversationId: ctx.conversationId,
543
558
  contractB64: ctx.envelope?.base64,
544
559
  goalMode: ctx.goalMode ?? undefined,
560
+ sessionConfigB64: ctx.sessionConfigB64,
545
561
  });
546
562
  const args = buildCliArgs(ctx.options, { yolo: ctx.yolo, allowCliFlags: true });
547
563
  // Claude Code logged in via claude.ai (OAuth) PREEMPTS ANTHROPIC_API_KEY, so
@@ -590,6 +606,7 @@ function launchRemoteControl(ctx) {
590
606
  MNEMOM_AGENT_RC_CONVERSATION_ID: ctx.conversationId,
591
607
  MNEMOM_AGENT_RC_CONTRACT_B64: ctx.envelope?.base64 ?? "",
592
608
  MNEMOM_AGENT_RC_GOAL_MODE: ctx.goalMode ?? "",
609
+ MNEMOM_AGENT_RC_SESSION_CONFIG: ctx.sessionConfigB64 ?? "",
593
610
  MNEMOM_AGENT_RC_PROXY_LOG: proxyLog,
594
611
  MNEMOM_AGENT_RC_PARENT_PID: String(process.pid),
595
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,
@@ -46,7 +46,18 @@ export interface SessionRecord {
46
46
  /** The coding-agent CLI's basename, e.g. "claude". */
47
47
  cli: string;
48
48
  contract: SessionRecordContract | null;
49
+ /**
50
+ * The goal-alignment mode the launch ran under: `"on"` (a sealed contract),
51
+ * `"implicit"` (`--implicit` — the gateway infers the goal, no sealed
52
+ * contract), or `"off"`. Optional: records written before this field existed
53
+ * omit it, and readers fall back to `contract ? "on" : "off"` (an old
54
+ * `--implicit` launch is indistinguishable from `off` — its mode was never
55
+ * captured).
56
+ */
57
+ goal_mode?: GoalMode;
49
58
  }
59
+ /** Goal-alignment mode as recorded at launch. */
60
+ export type GoalMode = "off" | "on" | "implicit";
50
61
  /** What the call site supplies — the ledger stamps `v` and `started_at`. */
51
62
  export type SessionRecordInput = Omit<SessionRecord, "v" | "started_at">;
52
63
  /** The injected environment of the ledger. */
@@ -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.0",
3
+ "version": "0.17.2-next.2",
4
4
  "description": "Transparent AI agent tracing",
5
5
  "type": "module",
6
6
  "bin": {