@mnemom/mnemom 0.17.2-next.1 → 0.17.2-next.3
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 +13 -0
- package/dist/commands/agent-session.d.ts +10 -22
- package/dist/commands/agent-session.js +17 -54
- package/dist/commands/agent-setup.d.ts +13 -0
- package/dist/commands/agent-setup.js +14 -0
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/agent.js +31 -8
- package/dist/index.js +5 -2
- package/dist/lib/agent.d.ts +44 -2
- package/dist/lib/agent.js +56 -3
- 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/README.md
CHANGED
|
@@ -71,6 +71,19 @@ Make one mode the standing default with `mnemom agent config set goal_mode impli
|
|
|
71
71
|
(or `off`); `--goal` still seals for that launch and `--no-implicit` turns it off for one
|
|
72
72
|
launch. A sealed contract needs a per-launch statement, so it cannot be the default.
|
|
73
73
|
|
|
74
|
+
#### Orchestrated launches: `MNEMOM_AGENT_PREFLIGHTED=1`
|
|
75
|
+
|
|
76
|
+
An orchestrator (the ADW fleet) that already checked sign-in and the µ balance before
|
|
77
|
+
spawning many launches can set `MNEMOM_AGENT_PREFLIGHTED=1`. Each launch then skips its
|
|
78
|
+
own session, personal-org and µ-balance requests. The Mnemom Agent entitlement is still
|
|
79
|
+
fetched, because it gates access and Remote Control. Only the exact value `1` counts.
|
|
80
|
+
This is not for interactive use: a launch with no session or no µ will fail at the
|
|
81
|
+
gateway instead of printing the sign-in or top-up guidance.
|
|
82
|
+
|
|
83
|
+
An explicit launch shape (`--remote-control`, `--server`, `MNEMOM_AGENT_REMOTE_CONTROL`
|
|
84
|
+
or `launch` in `launcher.toml`) also skips the Remote Control capability probe
|
|
85
|
+
(`claude --help`), which only feeds the automatic upgrade to Remote Control.
|
|
86
|
+
|
|
74
87
|
## How It Works
|
|
75
88
|
|
|
76
89
|
```
|
|
@@ -6,28 +6,22 @@
|
|
|
6
6
|
* a terminal we ask two things, explaining each in a sentence:
|
|
7
7
|
*
|
|
8
8
|
* 1. a SESSION NAME — labels the session in traces and the claude.ai session
|
|
9
|
-
* list (defaults to the current folder's name)
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - OFF: the session runs governed with goal alignment off — neither header
|
|
18
|
-
* is sent, so the gateway's goal hooks are simply not engaged.
|
|
9
|
+
* list (defaults to the current folder's name).
|
|
10
|
+
*
|
|
11
|
+
* GOAL ALIGNMENT is not prompted for: it defaults to IMPLICIT. A bare launch
|
|
12
|
+
* runs governed with the goal inferred from your own messages
|
|
13
|
+
* (`x-mnemom-goal-mode: implicit`, no contract). `--goal` seals a one-line
|
|
14
|
+
* contract instead (`x-mnemom-contract`); `--no-implicit` (or launcher.toml
|
|
15
|
+
* `goal_mode = "off"`) turns alignment off — neither header is sent. The mode is
|
|
16
|
+
* resolved upstream (`resolveImplicit`) and announced on the launch line.
|
|
19
17
|
*
|
|
20
18
|
* Non-interactive runs (pipes, CI) never prompt — they get a clear error asking
|
|
21
|
-
* for a name.
|
|
22
|
-
*
|
|
23
|
-
* "implicit"` with no `--no-implicit`) skips it too. Pure apart from the
|
|
24
|
-
* injected `ask` functions, so every arm is unit-tested.
|
|
19
|
+
* for a name. Pure apart from the injected `ask` functions, so every arm is
|
|
20
|
+
* unit-tested.
|
|
25
21
|
*/
|
|
26
22
|
export interface SessionAsk {
|
|
27
23
|
askInput(question: string): Promise<string>;
|
|
28
24
|
askYesNo(question: string, defaultYes: boolean): Promise<boolean>;
|
|
29
|
-
/** Numbered single-select; resolves the chosen label, or null on no/invalid choice. */
|
|
30
|
-
askSelect(question: string, options: string[]): Promise<string | null>;
|
|
31
25
|
}
|
|
32
26
|
export interface SessionSetupInput {
|
|
33
27
|
/** The positional `[scenario]` (session name), if given. */
|
|
@@ -51,12 +45,6 @@ export interface SessionSetup {
|
|
|
51
45
|
prompted: boolean;
|
|
52
46
|
}
|
|
53
47
|
export declare const NO_SESSION_NAME_MESSAGE: string;
|
|
54
|
-
/** The three goal-alignment choices offered by the interactive prompt (labels are the select options). */
|
|
55
|
-
export declare const GOAL_CHOICE_IMPLICIT = "Infer my goal from my messages \u2014 nothing to type; revised as I steer (implicit mode)";
|
|
56
|
-
export declare const GOAL_CHOICE_TYPED = "Type a one-line goal \u2014 sealed as a contract for this session";
|
|
57
|
-
export declare const GOAL_CHOICE_OFF = "Off \u2014 run governed with goal alignment off (Enter)";
|
|
58
|
-
export declare const GOAL_CHOICES: readonly string[];
|
|
59
|
-
export declare const GOAL_CHOICE_QUESTION = "Goal alignment for this session?";
|
|
60
48
|
/** Current folder name, sanitised like an agent slug; "session" when that is empty. */
|
|
61
49
|
export declare function defaultSessionName(cwd?: string): string;
|
|
62
50
|
/** The one-line status printed at launch so the customer always knows the mode. */
|
|
@@ -6,37 +6,23 @@
|
|
|
6
6
|
* a terminal we ask two things, explaining each in a sentence:
|
|
7
7
|
*
|
|
8
8
|
* 1. a SESSION NAME — labels the session in traces and the claude.ai session
|
|
9
|
-
* list (defaults to the current folder's name)
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - OFF: the session runs governed with goal alignment off — neither header
|
|
18
|
-
* is sent, so the gateway's goal hooks are simply not engaged.
|
|
9
|
+
* list (defaults to the current folder's name).
|
|
10
|
+
*
|
|
11
|
+
* GOAL ALIGNMENT is not prompted for: it defaults to IMPLICIT. A bare launch
|
|
12
|
+
* runs governed with the goal inferred from your own messages
|
|
13
|
+
* (`x-mnemom-goal-mode: implicit`, no contract). `--goal` seals a one-line
|
|
14
|
+
* contract instead (`x-mnemom-contract`); `--no-implicit` (or launcher.toml
|
|
15
|
+
* `goal_mode = "off"`) turns alignment off — neither header is sent. The mode is
|
|
16
|
+
* resolved upstream (`resolveImplicit`) and announced on the launch line.
|
|
19
17
|
*
|
|
20
18
|
* Non-interactive runs (pipes, CI) never prompt — they get a clear error asking
|
|
21
|
-
* for a name.
|
|
22
|
-
*
|
|
23
|
-
* "implicit"` with no `--no-implicit`) skips it too. Pure apart from the
|
|
24
|
-
* injected `ask` functions, so every arm is unit-tested.
|
|
19
|
+
* for a name. Pure apart from the injected `ask` functions, so every arm is
|
|
20
|
+
* unit-tested.
|
|
25
21
|
*/
|
|
26
22
|
import { basename } from "node:path";
|
|
27
23
|
import { sanitizeAgentName } from "../lib/agent.js";
|
|
28
24
|
export const NO_SESSION_NAME_MESSAGE = "mnemom agent: a session name is required here (e.g. `mnemom agent onboarding`). " +
|
|
29
25
|
"In a terminal, plain `mnemom agent` asks for one.";
|
|
30
|
-
/** The three goal-alignment choices offered by the interactive prompt (labels are the select options). */
|
|
31
|
-
export const GOAL_CHOICE_IMPLICIT = "Infer my goal from my messages — nothing to type; revised as I steer (implicit mode)";
|
|
32
|
-
export const GOAL_CHOICE_TYPED = "Type a one-line goal — sealed as a contract for this session";
|
|
33
|
-
export const GOAL_CHOICE_OFF = "Off — run governed with goal alignment off (Enter)";
|
|
34
|
-
export const GOAL_CHOICES = [
|
|
35
|
-
GOAL_CHOICE_IMPLICIT,
|
|
36
|
-
GOAL_CHOICE_TYPED,
|
|
37
|
-
GOAL_CHOICE_OFF,
|
|
38
|
-
];
|
|
39
|
-
export const GOAL_CHOICE_QUESTION = "Goal alignment for this session?";
|
|
40
26
|
/** Current folder name, sanitised like an agent slug; "session" when that is empty. */
|
|
41
27
|
export function defaultSessionName(cwd = process.cwd()) {
|
|
42
28
|
return sanitizeAgentName(basename(cwd)) || "session";
|
|
@@ -50,7 +36,7 @@ export function goalAlignmentLine(mode) {
|
|
|
50
36
|
}
|
|
51
37
|
return m === "on"
|
|
52
38
|
? "mnemom agent: goal alignment: on (the judge nudges the agent back when it drifts from your goal)"
|
|
53
|
-
: "mnemom agent: goal alignment: off (no
|
|
39
|
+
: "mnemom agent: goal alignment: off (--no-implicit or goal_mode = off — pass --goal or drop --no-implicit to turn it back on)";
|
|
54
40
|
}
|
|
55
41
|
const defaultSay = (line = "") => console.error(line);
|
|
56
42
|
/**
|
|
@@ -79,36 +65,13 @@ export async function resolveSessionSetup(input, ask) {
|
|
|
79
65
|
say(` (Next time you can pass it directly: mnemom agent <name>.)`);
|
|
80
66
|
const typed = await ask.askInput(`Session name [${fallback}]:`);
|
|
81
67
|
const scenario = sanitizeAgentName(typed.trim()) || fallback;
|
|
82
|
-
// ── 2. goal alignment
|
|
68
|
+
// ── 2. goal alignment — resolved upstream, no prompt. Implicit is the DEFAULT
|
|
69
|
+
// (a bare launch runs governed with the goal inferred from your messages), so
|
|
70
|
+
// there is nothing to pick here: `--goal` seals a contract, the default (and
|
|
71
|
+
// `--implicit` / `goal_mode = "implicit"`) is implicit, and `--no-implicit` /
|
|
72
|
+
// `goal_mode = "off"` turns it off. The launch line announces the mode.
|
|
83
73
|
if (flagGoal) {
|
|
84
74
|
return { scenario, goal: flagGoal, goalAlignment: "on", prompted: true };
|
|
85
75
|
}
|
|
86
|
-
|
|
87
|
-
return { scenario, goalAlignment: "implicit", prompted: true };
|
|
88
|
-
}
|
|
89
|
-
say();
|
|
90
|
-
say("Goal alignment — how Mnemom keeps this session on track. Three choices:");
|
|
91
|
-
say(" Infer: nothing to type — the gateway reads your own messages, revises the goal as you");
|
|
92
|
-
say(" steer, and the judge nudges the agent back when it drifts (a little µ per message + turn).");
|
|
93
|
-
say(" Type a goal: one line, sealed as a contract; the judge nudges against it (a little µ per turn).");
|
|
94
|
-
say(" Off: the session runs governed with goal alignment off (the default — just press Enter).");
|
|
95
|
-
say(" (Make one the default: mnemom agent config set goal_mode implicit|off.)");
|
|
96
|
-
const choice = await ask.askSelect(GOAL_CHOICE_QUESTION, [...GOAL_CHOICES]);
|
|
97
|
-
if (choice === GOAL_CHOICE_IMPLICIT) {
|
|
98
|
-
return { scenario, goalAlignment: "implicit", prompted: true };
|
|
99
|
-
}
|
|
100
|
-
if (choice === GOAL_CHOICE_TYPED) {
|
|
101
|
-
const goal = (await ask.askInput("Goal (one line):")).trim();
|
|
102
|
-
if (!goal) {
|
|
103
|
-
say(" No goal entered — continuing with goal alignment off.");
|
|
104
|
-
return { scenario, goalAlignment: "off", prompted: true };
|
|
105
|
-
}
|
|
106
|
-
return { scenario, goal, goalAlignment: "on", prompted: true };
|
|
107
|
-
}
|
|
108
|
-
// Enter (no pick) and any invalid pick both resolve to null → off. Off is the
|
|
109
|
-
// deliberate default for now: a µ-costing mode is never picked by a bare Enter.
|
|
110
|
-
if (choice !== GOAL_CHOICE_OFF) {
|
|
111
|
-
say(" Goal alignment off (press 1 or 2 next time to turn it on).");
|
|
112
|
-
}
|
|
113
|
-
return { scenario, goalAlignment: "off", prompted: true };
|
|
76
|
+
return { scenario, goalAlignment: implicit ? "implicit" : "off", prompted: true };
|
|
114
77
|
}
|
|
@@ -115,3 +115,16 @@ export declare function ensureSessionAndBalance(opts: {
|
|
|
115
115
|
orgLabel: string;
|
|
116
116
|
entitlement: CodeEntitlement | null;
|
|
117
117
|
}>;
|
|
118
|
+
/**
|
|
119
|
+
* The account for a launch an orchestrator already preflighted
|
|
120
|
+
* (`MNEMOM_AGENT_PREFLIGHTED=1`, see launchPreflighted): no session prompt, no
|
|
121
|
+
* personal-org lookup, no µ-balance read. The entitlement is still fetched — it
|
|
122
|
+
* is the access gate and decides Remote Control fail-closed, which a caller's
|
|
123
|
+
* preflight can't vouch for. With no active org the api resolves the caller's
|
|
124
|
+
* primary org, and the ledger records the org id the entitlement names.
|
|
125
|
+
*/
|
|
126
|
+
export declare function resolvePreflightedAccount(): Promise<{
|
|
127
|
+
orgId: string;
|
|
128
|
+
orgLabel: string;
|
|
129
|
+
entitlement: CodeEntitlement | null;
|
|
130
|
+
}>;
|
|
@@ -383,6 +383,20 @@ export async function ensureSessionAndBalance(opts) {
|
|
|
383
383
|
await assertMuBalance(orgId, orgLabel);
|
|
384
384
|
return { orgId, orgLabel, entitlement };
|
|
385
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* The account for a launch an orchestrator already preflighted
|
|
388
|
+
* (`MNEMOM_AGENT_PREFLIGHTED=1`, see launchPreflighted): no session prompt, no
|
|
389
|
+
* personal-org lookup, no µ-balance read. The entitlement is still fetched — it
|
|
390
|
+
* is the access gate and decides Remote Control fail-closed, which a caller's
|
|
391
|
+
* preflight can't vouch for. With no active org the api resolves the caller's
|
|
392
|
+
* primary org, and the ledger records the org id the entitlement names.
|
|
393
|
+
*/
|
|
394
|
+
export async function resolvePreflightedAccount() {
|
|
395
|
+
const active = getActiveOrg();
|
|
396
|
+
const orgLabel = active ? `${active.name} (${active.slug})` : "your primary org";
|
|
397
|
+
const entitlement = await assertCodeEnabled(active?.org_id ?? "", orgLabel);
|
|
398
|
+
return { orgId: active?.org_id ?? entitlement?.org_id ?? "", orgLabel, entitlement };
|
|
399
|
+
}
|
|
386
400
|
// ── The default coding posture (cards observe-only; goal contracts nudge) ────
|
|
387
401
|
function buildCodeAlignmentCard(agentId) {
|
|
388
402
|
return {
|
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
|
@@ -35,18 +35,18 @@ import { getAgentByName } from "../lib/api.js";
|
|
|
35
35
|
import { LEDGER_FILE, appendSessionRecord, toLedgerContract } from "../lib/agent-ledger.js";
|
|
36
36
|
import { configKeySpec, loadLauncherConfig, writeLauncherConfig } from "../lib/launcher-config.js";
|
|
37
37
|
import { fmt } from "../lib/format.js";
|
|
38
|
-
import { askInput,
|
|
38
|
+
import { askInput, askYesNo, isInteractive } from "../lib/prompt.js";
|
|
39
39
|
import { goalAlignmentLine, resolveSessionSetup } from "./agent-session.js";
|
|
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";
|
|
40
|
+
import { defaultAgentSlug, ensureGovernedAgent, ensureSessionAndBalance, isQuietPreambleExit, resolveDefaultSlug, resolvePreflightedAccount, } from "./agent-setup.js";
|
|
41
|
+
import { assembleContract, buildGoalModeHeader, buildCustomHeaders, buildSessionConfigB64, resolveContextFold, isProdGateway, launchPreferenceExplicit, launchPreflighted, 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);
|
|
45
45
|
/** Entry point for `mnemom agent [scenario]`. Throws on fatal misconfig. */
|
|
46
46
|
export async function agentCommand(scenarioArg, options = {}) {
|
|
47
47
|
// ── session name + goal ── (a bare `mnemom agent` in a terminal asks for both,
|
|
48
|
-
//
|
|
49
|
-
//
|
|
48
|
+
// goal alignment is implicit by default (inferred from your messages); --goal
|
|
49
|
+
// seals a contract and --no-implicit turns it off — all resolved upstream.
|
|
50
50
|
const session = await resolveSessionSetup({
|
|
51
51
|
scenario: scenarioArg,
|
|
52
52
|
goal: options.goal,
|
|
@@ -55,7 +55,6 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
55
55
|
}, {
|
|
56
56
|
askInput: (q) => askInput(q),
|
|
57
57
|
askYesNo: (q, d) => askYesNo(q, d),
|
|
58
|
-
askSelect: (q, o) => askSelect(q, o),
|
|
59
58
|
});
|
|
60
59
|
const scenario = session.scenario;
|
|
61
60
|
const env = process.env;
|
|
@@ -96,6 +95,11 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
96
95
|
const cellNote = isProdGateway(env) ? "us-2/prod" : `custom (${gatewayHost})`;
|
|
97
96
|
const yolo = options.yolo !== false; // default ON
|
|
98
97
|
const contextHint = options.contextHint !== false; // default ON
|
|
98
|
+
// Context folding is ON by default; --no-context (or `context = false` in
|
|
99
|
+
// launcher.toml → MNEMOM_AGENT_CONTEXT) turns it off for this session via the
|
|
100
|
+
// per-session config header. `undefined` sessionConfigB64 ⇒ nothing sent.
|
|
101
|
+
const contextFold = resolveContextFold({ context: options.context, env });
|
|
102
|
+
const sessionConfigB64 = buildSessionConfigB64(contextFold);
|
|
99
103
|
// ── which CLI executable (name or full path) ── resolve GRACEFULLY: if it's not
|
|
100
104
|
// found we don't crash with a technical error — we ask for the path at launch.
|
|
101
105
|
let cli;
|
|
@@ -138,6 +142,9 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
138
142
|
if (previewShape === "remote-control") {
|
|
139
143
|
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
144
|
}
|
|
145
|
+
if (!contextFold) {
|
|
146
|
+
say("mnemom agent: context folding OFF for this session (--no-context or context = false).");
|
|
147
|
+
}
|
|
141
148
|
return;
|
|
142
149
|
}
|
|
143
150
|
// Real launch: make sure we actually have a CLI to run. If we couldn't find it,
|
|
@@ -157,9 +164,14 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
157
164
|
// there isn't one — and (2) enforce a positive µ balance on the org the agent
|
|
158
165
|
// lives in (default: the user's personal org). No µ ⇒ blocked with a
|
|
159
166
|
// portal-style top-up message. Skipped only on --dry-run (handled above).
|
|
167
|
+
// MNEMOM_AGENT_PREFLIGHTED=1 (orchestrators such as the ADW fleet that already
|
|
168
|
+
// ran their own session + balance preflight) skips those round trips; the
|
|
169
|
+
// entitlement is still fetched — see resolvePreflightedAccount.
|
|
160
170
|
let account;
|
|
161
171
|
try {
|
|
162
|
-
account =
|
|
172
|
+
account = launchPreflighted(env)
|
|
173
|
+
? await resolvePreflightedAccount()
|
|
174
|
+
: await ensureSessionAndBalance({ interactive: isInteractive() });
|
|
163
175
|
}
|
|
164
176
|
catch (err) {
|
|
165
177
|
if (isQuietPreambleExit(err))
|
|
@@ -174,7 +186,11 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
174
186
|
// terminal-only with a notice. FAIL-CLOSED — a null entitlement (gate failed
|
|
175
187
|
// open) or an api without the field yields no Remote Control.
|
|
176
188
|
const rcAllowed = remoteControlAllowed(account.entitlement);
|
|
177
|
-
|
|
189
|
+
// The capability probe (`claude --help`, up to 10s, plus `command -v` for node
|
|
190
|
+
// and openssl) only feeds the auto-upgrade. An explicit shape never auto-upgrades
|
|
191
|
+
// and a non-allowed account never gets Remote Control, so both skip it; an
|
|
192
|
+
// explicit RC launch still refuses a missing node/openssl in launchRemoteControl.
|
|
193
|
+
const rc = shapeExplicit || !rcAllowed ? { ok: false, missing: [] } : checkRcCapability(cli);
|
|
178
194
|
// Preserve the "how to turn Remote Control on" guidance for an allowed account
|
|
179
195
|
// whose machine can't do it yet and who didn't pin a shape (the old
|
|
180
196
|
// applyAutoShape behaviour). Non-allowed accounts never see it — RC isn't
|
|
@@ -235,6 +251,9 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
235
251
|
});
|
|
236
252
|
logLaunch({ shape, door, agent, conversationId, cellNote, envelope, goalMode, cli });
|
|
237
253
|
say(goalAlignmentLine(goalAlignmentMode(envelope, goalMode)));
|
|
254
|
+
if (!contextFold) {
|
|
255
|
+
say("mnemom agent: context folding OFF for this session (--no-context or context = false).");
|
|
256
|
+
}
|
|
238
257
|
if (shape === "terminal") {
|
|
239
258
|
launchTerminal({
|
|
240
259
|
cli,
|
|
@@ -244,6 +263,7 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
244
263
|
conversationId,
|
|
245
264
|
envelope,
|
|
246
265
|
goalMode,
|
|
266
|
+
sessionConfigB64,
|
|
247
267
|
options,
|
|
248
268
|
yolo,
|
|
249
269
|
contextHint,
|
|
@@ -260,6 +280,7 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
260
280
|
scenario,
|
|
261
281
|
envelope,
|
|
262
282
|
goalMode,
|
|
283
|
+
sessionConfigB64,
|
|
263
284
|
options,
|
|
264
285
|
yolo,
|
|
265
286
|
});
|
|
@@ -544,6 +565,7 @@ function launchTerminal(ctx) {
|
|
|
544
565
|
conversationId: ctx.conversationId,
|
|
545
566
|
contractB64: ctx.envelope?.base64,
|
|
546
567
|
goalMode: ctx.goalMode ?? undefined,
|
|
568
|
+
sessionConfigB64: ctx.sessionConfigB64,
|
|
547
569
|
});
|
|
548
570
|
const args = buildCliArgs(ctx.options, { yolo: ctx.yolo, allowCliFlags: true });
|
|
549
571
|
// Claude Code logged in via claude.ai (OAuth) PREEMPTS ANTHROPIC_API_KEY, so
|
|
@@ -592,6 +614,7 @@ function launchRemoteControl(ctx) {
|
|
|
592
614
|
MNEMOM_AGENT_RC_CONVERSATION_ID: ctx.conversationId,
|
|
593
615
|
MNEMOM_AGENT_RC_CONTRACT_B64: ctx.envelope?.base64 ?? "",
|
|
594
616
|
MNEMOM_AGENT_RC_GOAL_MODE: ctx.goalMode ?? "",
|
|
617
|
+
MNEMOM_AGENT_RC_SESSION_CONFIG: ctx.sessionConfigB64 ?? "",
|
|
595
618
|
MNEMOM_AGENT_RC_PROXY_LOG: proxyLog,
|
|
596
619
|
MNEMOM_AGENT_RC_PARENT_PID: String(process.pid),
|
|
597
620
|
},
|
package/dist/index.js
CHANGED
|
@@ -113,8 +113,8 @@ const agentCmd = program
|
|
|
113
113
|
.option("--budget <usd>", "Guardrail: spend ceiling in USD (positive number)")
|
|
114
114
|
.option("--max-turns <n>", "Guardrail: turn ceiling (positive integer)")
|
|
115
115
|
.option("--stall <n>", "Guardrail: consecutive no-write turns (positive integer)")
|
|
116
|
-
.option("--implicit", "
|
|
117
|
-
.option("--no-implicit", "
|
|
116
|
+
.option("--implicit", "Implicit goal alignment (the default): the gateway infers the goal from your messages and revises it as you steer (not combinable with --goal/--requirement/--allow/--forbid/--goal-id; the guardrail ceilings still apply)")
|
|
117
|
+
.option("--no-implicit", "Turn goal alignment OFF for this launch (implicit alignment is on by default; also overrides launcher.toml goal_mode = implicit)")
|
|
118
118
|
.option("--conversation-id <id>", "x-mnemom-conversation-id (default: auto-generated)")
|
|
119
119
|
.option("--cli <name|path>", "Coding-agent CLI to launch: a name or full path (default: claude)")
|
|
120
120
|
.option("--gateway <url>", "Gateway host override (default: https://gateway.mnemom.ai; or MNEMOM_AGENT_GATEWAY)")
|
|
@@ -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
|
|
@@ -156,6 +165,16 @@ export declare function launchPreferenceExplicit(opts: {
|
|
|
156
165
|
remoteControl?: boolean;
|
|
157
166
|
server?: boolean;
|
|
158
167
|
}, env?: NodeJS.ProcessEnv): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Has an orchestrator already run the session + µ-balance preflight for this
|
|
170
|
+
* launch? `MNEMOM_AGENT_PREFLIGHTED=1` is for orchestrators (the ADW fleet) that
|
|
171
|
+
* checked sign-in and balance themselves before spawning many launches; it skips
|
|
172
|
+
* the per-launch session/personal-org/balance round trips. The Mnemom Agent
|
|
173
|
+
* entitlement (which also gates Remote Control, fail-closed) is still fetched.
|
|
174
|
+
* Only the exact value `1` counts — anything else, including `true` or ` 1`, is
|
|
175
|
+
* a normal launch.
|
|
176
|
+
*/
|
|
177
|
+
export declare function launchPreflighted(env?: NodeJS.ProcessEnv): boolean;
|
|
159
178
|
/**
|
|
160
179
|
* Is this account allowed to use Remote Control (a session steerable from
|
|
161
180
|
* claude.ai and the Claude app)? Remote Control is an INTERNAL Mnemom capability
|
|
@@ -204,7 +223,26 @@ export declare function buildCustomHeaders(opts: {
|
|
|
204
223
|
contractB64?: string;
|
|
205
224
|
/** `buildGoalModeHeader` output for an `--implicit` launch. */
|
|
206
225
|
goalMode?: string;
|
|
226
|
+
/** `buildSessionConfigB64` output — the per-session env overlay (e.g. fold off). */
|
|
227
|
+
sessionConfigB64?: string;
|
|
207
228
|
}): string;
|
|
229
|
+
/**
|
|
230
|
+
* Whether context folding is ON for this launch. Folding is a gateway feature
|
|
231
|
+
* that summarises older turns to fit the window; it is ON by default. Precedence:
|
|
232
|
+
* an explicit `--context`/`--no-context` flag wins, else `MNEMOM_AGENT_CONTEXT`
|
|
233
|
+
* (which `applyConfigToEnv` sets from the `context` config key), else ON.
|
|
234
|
+
* Recognised OFF values for the env var: `0`, `false`, `off`, `no` (case-insensitive).
|
|
235
|
+
*/
|
|
236
|
+
export declare function resolveContextFold(opts: {
|
|
237
|
+
context?: boolean;
|
|
238
|
+
env?: NodeJS.ProcessEnv;
|
|
239
|
+
}): boolean;
|
|
240
|
+
/**
|
|
241
|
+
* The `x-mnemom-session-config` value that turns context folding OFF, or
|
|
242
|
+
* `undefined` when folding is ON (the default — nothing is sent, the gateway's
|
|
243
|
+
* own default stands). base64url so it survives the gateway's inbound strip.
|
|
244
|
+
*/
|
|
245
|
+
export declare function buildSessionConfigB64(fold: boolean): string | undefined;
|
|
208
246
|
/**
|
|
209
247
|
* The persistable goal-alignment default (`launcher.toml` `goal_mode`). Only the
|
|
210
248
|
* two statement-free modes can be a standing default: a SEALED contract needs a
|
|
@@ -216,8 +254,12 @@ export type GoalModeDefault = "implicit" | "off";
|
|
|
216
254
|
* 1. an explicit flag — `--implicit` (true) or `--no-implicit` (false);
|
|
217
255
|
* 2. a `--goal` statement — a sealed contract is a per-launch choice that the
|
|
218
256
|
* standing config default must never silently override;
|
|
219
|
-
* 3. the config default `goal_mode
|
|
220
|
-
*
|
|
257
|
+
* 3. the config default `goal_mode` — `"off"` turns alignment off, `"implicit"`
|
|
258
|
+
* keeps it implicit;
|
|
259
|
+
* 4. IMPLICIT (the default). A bare `mnemom agent` runs with implicit goal
|
|
260
|
+
* alignment on: the gateway infers the goal from the user's own messages.
|
|
261
|
+
* Turn it off for a launch with `--no-implicit`, or standing with
|
|
262
|
+
* `goal_mode = "off"`.
|
|
221
263
|
* Pure so every arm is unit-tested; the caller passes the resolved value on to
|
|
222
264
|
* `assembleContract` / `buildGoalModeHeader` (which still refuse `--implicit`
|
|
223
265
|
* combined with a contract flag — that conflict is EXPLICIT and is reported).
|
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
|
|
@@ -291,6 +300,18 @@ export function launchPreferenceExplicit(opts, env = process.env) {
|
|
|
291
300
|
return true;
|
|
292
301
|
return (env.MNEMOM_AGENT_REMOTE_CONTROL ?? "").trim() !== "";
|
|
293
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Has an orchestrator already run the session + µ-balance preflight for this
|
|
305
|
+
* launch? `MNEMOM_AGENT_PREFLIGHTED=1` is for orchestrators (the ADW fleet) that
|
|
306
|
+
* checked sign-in and balance themselves before spawning many launches; it skips
|
|
307
|
+
* the per-launch session/personal-org/balance round trips. The Mnemom Agent
|
|
308
|
+
* entitlement (which also gates Remote Control, fail-closed) is still fetched.
|
|
309
|
+
* Only the exact value `1` counts — anything else, including `true` or ` 1`, is
|
|
310
|
+
* a normal launch.
|
|
311
|
+
*/
|
|
312
|
+
export function launchPreflighted(env = process.env) {
|
|
313
|
+
return env.MNEMOM_AGENT_PREFLIGHTED === "1";
|
|
314
|
+
}
|
|
294
315
|
/**
|
|
295
316
|
* Is this account allowed to use Remote Control (a session steerable from
|
|
296
317
|
* claude.ai and the Claude app)? Remote Control is an INTERNAL Mnemom capability
|
|
@@ -352,15 +373,47 @@ export function buildCustomHeaders(opts) {
|
|
|
352
373
|
lines.push(`x-mnemom-contract: ${opts.contractB64}`);
|
|
353
374
|
if (opts.goalMode)
|
|
354
375
|
lines.push(`${GOAL_MODE_HEADER}: ${opts.goalMode}`);
|
|
376
|
+
if (opts.sessionConfigB64)
|
|
377
|
+
lines.push(`${SESSION_CONFIG_HEADER}: ${opts.sessionConfigB64}`);
|
|
355
378
|
return lines.join("\n");
|
|
356
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Whether context folding is ON for this launch. Folding is a gateway feature
|
|
382
|
+
* that summarises older turns to fit the window; it is ON by default. Precedence:
|
|
383
|
+
* an explicit `--context`/`--no-context` flag wins, else `MNEMOM_AGENT_CONTEXT`
|
|
384
|
+
* (which `applyConfigToEnv` sets from the `context` config key), else ON.
|
|
385
|
+
* Recognised OFF values for the env var: `0`, `false`, `off`, `no` (case-insensitive).
|
|
386
|
+
*/
|
|
387
|
+
export function resolveContextFold(opts) {
|
|
388
|
+
if (opts.context !== undefined)
|
|
389
|
+
return opts.context;
|
|
390
|
+
const raw = (opts.env?.MNEMOM_AGENT_CONTEXT ?? "").trim().toLowerCase();
|
|
391
|
+
if (raw === "")
|
|
392
|
+
return true;
|
|
393
|
+
return !(raw === "0" || raw === "false" || raw === "off" || raw === "no");
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* The `x-mnemom-session-config` value that turns context folding OFF, or
|
|
397
|
+
* `undefined` when folding is ON (the default — nothing is sent, the gateway's
|
|
398
|
+
* own default stands). base64url so it survives the gateway's inbound strip.
|
|
399
|
+
*/
|
|
400
|
+
export function buildSessionConfigB64(fold) {
|
|
401
|
+
if (fold)
|
|
402
|
+
return undefined;
|
|
403
|
+
const payload = JSON.stringify({ v: 1, config: { [CONTEXT_RUNTIME_KEY]: "false" } });
|
|
404
|
+
return Buffer.from(payload, "utf8").toString("base64url");
|
|
405
|
+
}
|
|
357
406
|
/**
|
|
358
407
|
* Is this launch implicit-mode? Precedence, highest wins:
|
|
359
408
|
* 1. an explicit flag — `--implicit` (true) or `--no-implicit` (false);
|
|
360
409
|
* 2. a `--goal` statement — a sealed contract is a per-launch choice that the
|
|
361
410
|
* standing config default must never silently override;
|
|
362
|
-
* 3. the config default `goal_mode
|
|
363
|
-
*
|
|
411
|
+
* 3. the config default `goal_mode` — `"off"` turns alignment off, `"implicit"`
|
|
412
|
+
* keeps it implicit;
|
|
413
|
+
* 4. IMPLICIT (the default). A bare `mnemom agent` runs with implicit goal
|
|
414
|
+
* alignment on: the gateway infers the goal from the user's own messages.
|
|
415
|
+
* Turn it off for a launch with `--no-implicit`, or standing with
|
|
416
|
+
* `goal_mode = "off"`.
|
|
364
417
|
* Pure so every arm is unit-tested; the caller passes the resolved value on to
|
|
365
418
|
* `assembleContract` / `buildGoalModeHeader` (which still refuse `--implicit`
|
|
366
419
|
* combined with a contract flag — that conflict is EXPLICIT and is reported).
|
|
@@ -370,5 +423,5 @@ export function resolveImplicit(opts) {
|
|
|
370
423
|
return opts.implicit;
|
|
371
424
|
if (hasText(opts.goal))
|
|
372
425
|
return false;
|
|
373
|
-
return opts.configGoalMode
|
|
426
|
+
return opts.configGoalMode !== "off";
|
|
374
427
|
}
|
|
@@ -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"])
|