@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.
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/agent.js +16 -1
- package/dist/index.js +3 -0
- package/dist/lib/agent.d.ts +28 -0
- package/dist/lib/agent.js +37 -0
- package/dist/lib/launcher-config.d.ts +3 -1
- package/dist/lib/launcher-config.js +25 -0
- package/dist/rc-proxy.mjs +3 -0
- package/package.json +1 -1
package/dist/commands/agent.d.ts
CHANGED
|
@@ -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
|
/**
|
package/dist/commands/agent.js
CHANGED
|
@@ -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,
|
package/dist/lib/agent.d.ts
CHANGED
|
@@ -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"])
|