dsh-mnemon 0.3.4 → 0.3.6
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 +3 -3
- package/README.zh-CN.md +3 -3
- package/lib/client.js +165 -62
- package/lib/index.js +387 -155
- package/lib/kernel.js +47 -0
- package/lib/types/packages/kernel/src/view.d.ts +11 -0
- package/lib/types/src/agent-memory-turn.d.ts +42 -0
- package/lib/types/src/client/MnemonTurnTail.d.ts +3 -2
- package/lib/types/src/client/MnemonView.d.ts +1 -1
- package/lib/types/src/client/dsh-compat.d.ts +34 -3
- package/lib/types/src/client/locales.d.ts +18 -0
- package/lib/types/src/client/subagent-token-usage.d.ts +3 -4
- package/lib/types/src/config-values.d.ts +1 -1
- package/lib/types/src/config.d.ts +1 -1
- package/lib/types/src/contracts.d.ts +28 -6
- package/lib/types/src/guidance.d.ts +1 -0
- package/lib/types/src/lifecycle.d.ts +4 -0
- package/lib/types/src/live-runtime.d.ts +1 -1
- package/lib/types/src/rpc.d.ts +7 -7
- package/lib/types/src/shared/contracts.d.ts +18 -1
- package/lib/types/src/subagent.d.ts +2 -2
- package/lib/types/src/tools.d.ts +1 -1
- package/package.json +16 -5
package/lib/index.js
CHANGED
|
@@ -23,6 +23,17 @@ const MNEMON_SETTINGS_CHANNEL = "/dsh-mnemon-settings";
|
|
|
23
23
|
const MNEMON_SETTINGS_NAMESPACE = "mnemon";
|
|
24
24
|
const DEFAULT_EMBEDDING_ENDPOINT = "http://localhost:11434";
|
|
25
25
|
const DEFAULT_EMBEDDING_MODEL = "nomic-embed-text";
|
|
26
|
+
const EMBEDDING_PROTOCOL_AUTO = "auto";
|
|
27
|
+
const EMBEDDING_PROTOCOL_OLLAMA = "ollama";
|
|
28
|
+
const EMBEDDING_PROTOCOL_OPENAI = "openai";
|
|
29
|
+
/** Default protocol defers to Mnemon's /v1 auto-detection. */
|
|
30
|
+
const DEFAULT_EMBEDDING_PROTOCOL = EMBEDDING_PROTOCOL_AUTO;
|
|
31
|
+
/** Wire protocols accepted by the embedding protocol override; single source for schema, resolver, and UI validation. */
|
|
32
|
+
const MNEMON_EMBEDDING_PROTOCOLS = [
|
|
33
|
+
EMBEDDING_PROTOCOL_AUTO,
|
|
34
|
+
EMBEDDING_PROTOCOL_OLLAMA,
|
|
35
|
+
EMBEDDING_PROTOCOL_OPENAI
|
|
36
|
+
];
|
|
26
37
|
const CATEGORIES = [
|
|
27
38
|
"preference",
|
|
28
39
|
"decision",
|
|
@@ -114,7 +125,9 @@ const TaskAgentModelSchema = z.object({
|
|
|
114
125
|
const MnemonEmbeddingSchema = z.object({
|
|
115
126
|
enabled: z.boolean().default(false),
|
|
116
127
|
endpoint: z.string().default(DEFAULT_EMBEDDING_ENDPOINT),
|
|
117
|
-
model: z.string().default(DEFAULT_EMBEDDING_MODEL)
|
|
128
|
+
model: z.string().default(DEFAULT_EMBEDDING_MODEL),
|
|
129
|
+
apiKey: z.string().default(""),
|
|
130
|
+
protocol: z.union(MNEMON_EMBEDDING_PROTOCOLS).default(DEFAULT_EMBEDDING_PROTOCOL)
|
|
118
131
|
});
|
|
119
132
|
const RecallQualitySchema = z.object({
|
|
120
133
|
policy: z.string().default(DEFAULT_RECALL_QUALITY_POLICY),
|
|
@@ -175,7 +188,9 @@ const Config = z.object({
|
|
|
175
188
|
embedding: MnemonEmbeddingSchema.default({
|
|
176
189
|
enabled: false,
|
|
177
190
|
endpoint: DEFAULT_EMBEDDING_ENDPOINT,
|
|
178
|
-
model: DEFAULT_EMBEDDING_MODEL
|
|
191
|
+
model: DEFAULT_EMBEDDING_MODEL,
|
|
192
|
+
apiKey: "",
|
|
193
|
+
protocol: DEFAULT_EMBEDDING_PROTOCOL
|
|
179
194
|
}),
|
|
180
195
|
memoryTopology: MemoryTopologySchema,
|
|
181
196
|
recallQuality: RecallQualitySchema.default({
|
|
@@ -325,10 +340,16 @@ function resolveEmbedding(value) {
|
|
|
325
340
|
const normalizedEndpoint = endpoint.replace(/\/+$/u, "");
|
|
326
341
|
const model = optionalText$1(value?.model) ?? "nomic-embed-text";
|
|
327
342
|
if (model.length > 200 || /[\u0000-\u001f\u007f]/u.test(model)) throw new Error("dsh-mnemon: embedding model must contain 1..200 characters without control characters");
|
|
343
|
+
const apiKey = optionalText$1(value?.apiKey) ?? "";
|
|
344
|
+
if (apiKey.length > 2048 || /[\u0000-\u001f\u007f]/u.test(apiKey)) throw new Error("dsh-mnemon: embedding API key must contain 0..2048 characters without control characters");
|
|
345
|
+
const protocol = value?.protocol ?? "auto";
|
|
346
|
+
if (!MNEMON_EMBEDDING_PROTOCOLS.includes(protocol)) throw new Error(`dsh-mnemon: unsupported embedding protocol: ${String(protocol)}`);
|
|
328
347
|
return {
|
|
329
348
|
enabled: value?.enabled === true,
|
|
330
349
|
endpoint: normalizedEndpoint,
|
|
331
|
-
model
|
|
350
|
+
model,
|
|
351
|
+
apiKey,
|
|
352
|
+
protocol
|
|
332
353
|
};
|
|
333
354
|
}
|
|
334
355
|
function resolveRecallQuality(value) {
|
|
@@ -1930,20 +1951,7 @@ function applyAgentMemoryViewWake(assembly, wake) {
|
|
|
1930
1951
|
name: RUNTIME_MEMORY_PROTOCOL_SECTION_NAME,
|
|
1931
1952
|
text: protocol
|
|
1932
1953
|
});
|
|
1933
|
-
const
|
|
1934
|
-
let found = false;
|
|
1935
|
-
const contexts = assembly.contexts.map((context) => {
|
|
1936
|
-
if (context.name !== "mnemon:runtime-memory") return context;
|
|
1937
|
-
found = true;
|
|
1938
|
-
return {
|
|
1939
|
-
...context,
|
|
1940
|
-
text: rendered
|
|
1941
|
-
};
|
|
1942
|
-
});
|
|
1943
|
-
if (!found) contexts.push({
|
|
1944
|
-
name: RUNTIME_MEMORY_CONTEXT_NAME,
|
|
1945
|
-
text: rendered
|
|
1946
|
-
});
|
|
1954
|
+
const contexts = assembly.contexts.filter((context) => context.name !== RUNTIME_MEMORY_CONTEXT_NAME);
|
|
1947
1955
|
return {
|
|
1948
1956
|
...assembly,
|
|
1949
1957
|
sections,
|
|
@@ -1963,21 +1971,12 @@ function registerGuidance(ctx, config) {
|
|
|
1963
1971
|
}
|
|
1964
1972
|
/** Project only the immutable Wake pinned by the root Agent lifecycle. */
|
|
1965
1973
|
function registerAgentMemoryViewContext(agent, wake) {
|
|
1966
|
-
const
|
|
1967
|
-
const stopProtocol = prompt?.section?.({
|
|
1974
|
+
const stopProtocol = scopedSystemPrompt(agent)?.section?.({
|
|
1968
1975
|
name: RUNTIME_MEMORY_PROTOCOL_SECTION_NAME,
|
|
1969
1976
|
order: 145,
|
|
1970
1977
|
text: () => wakeHasRuntimeMemory(wake()) ? RUNTIME_MEMORY_PROTOCOL : ""
|
|
1971
1978
|
});
|
|
1972
|
-
|
|
1973
|
-
name: RUNTIME_MEMORY_CONTEXT_NAME,
|
|
1974
|
-
order: 145,
|
|
1975
|
-
text: () => {
|
|
1976
|
-
const current = wake();
|
|
1977
|
-
return current === void 0 ? "" : memoryPromptText(current.text);
|
|
1978
|
-
}
|
|
1979
|
-
});
|
|
1980
|
-
return disposer(stopProtocol, stopContext);
|
|
1979
|
+
return disposer(stopProtocol);
|
|
1981
1980
|
}
|
|
1982
1981
|
//#endregion
|
|
1983
1982
|
//#region src/pack.ts
|
|
@@ -2820,20 +2819,25 @@ function findMnemonCommand(config, options = {}) {
|
|
|
2820
2819
|
const env = options.env ?? process.env;
|
|
2821
2820
|
const home = options.home ?? homedir();
|
|
2822
2821
|
const isExecutable = options.isExecutable ?? ((path) => executable$1(path, platform));
|
|
2823
|
-
if (config.cliPath !== void 0) return expandHome$1(config.cliPath, home, platform);
|
|
2824
|
-
const envPath = envValue(env, "MNEMON_CLI_PATH", platform)?.trim();
|
|
2825
|
-
if (envPath !== void 0 && envPath !== "") {
|
|
2826
|
-
const path = expandHome$1(envPath, home, platform);
|
|
2827
|
-
if (isExecutable(path)) return path;
|
|
2828
|
-
}
|
|
2829
2822
|
const paths = pathApi(platform);
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2823
|
+
const resolveCommand = (command) => {
|
|
2824
|
+
const expanded = expandHome$1(command, home, platform);
|
|
2825
|
+
if (expanded.includes("/") || expanded.includes("\\")) return expanded;
|
|
2826
|
+
const name = platform === "win32" && paths.extname(expanded) === "" ? `${expanded}.exe` : expanded;
|
|
2827
|
+
for (const directory of (envValue(env, "PATH", platform) ?? "").split(paths.delimiter)) {
|
|
2828
|
+
if (directory === "") continue;
|
|
2833
2829
|
const path = paths.join(directory, name);
|
|
2834
2830
|
if (isExecutable(path)) return path;
|
|
2835
2831
|
}
|
|
2832
|
+
};
|
|
2833
|
+
if (config.cliPath !== void 0) return resolveCommand(config.cliPath);
|
|
2834
|
+
const envPath = envValue(env, "MNEMON_CLI_PATH", platform)?.trim();
|
|
2835
|
+
if (envPath !== void 0 && envPath !== "") {
|
|
2836
|
+
const path = resolveCommand(envPath);
|
|
2837
|
+
if (path !== void 0 && isExecutable(path)) return path;
|
|
2836
2838
|
}
|
|
2839
|
+
const fromPath = resolveCommand("mnemon");
|
|
2840
|
+
if (fromPath !== void 0) return fromPath;
|
|
2837
2841
|
for (const path of commonCliPaths(platform, env, home)) if (isExecutable(path)) return path;
|
|
2838
2842
|
}
|
|
2839
2843
|
var MnemonCliError = class extends Error {
|
|
@@ -2846,19 +2850,25 @@ var MnemonCliError = class extends Error {
|
|
|
2846
2850
|
this.stderr = stderr;
|
|
2847
2851
|
}
|
|
2848
2852
|
};
|
|
2849
|
-
const EMBEDDING_ENVIRONMENT_KEYS = /* @__PURE__ */ new Set([
|
|
2853
|
+
const EMBEDDING_ENVIRONMENT_KEYS = /* @__PURE__ */ new Set([
|
|
2854
|
+
"MNEMON_EMBED_ENDPOINT",
|
|
2855
|
+
"MNEMON_EMBED_MODEL",
|
|
2856
|
+
"MNEMON_EMBED_API_KEY",
|
|
2857
|
+
"MNEMON_EMBED_PROTOCOL"
|
|
2858
|
+
]);
|
|
2850
2859
|
/** Preserve the Host environment while making saved embedding overrides authoritative. */
|
|
2851
2860
|
function processEnvironment(config) {
|
|
2852
2861
|
if (!config.embedding.enabled) return void 0;
|
|
2853
2862
|
return {
|
|
2854
2863
|
...Object.fromEntries(Object.entries(process.env).filter(([key]) => !EMBEDDING_ENVIRONMENT_KEYS.has(key.toUpperCase()))),
|
|
2855
2864
|
MNEMON_EMBED_ENDPOINT: config.embedding.endpoint,
|
|
2856
|
-
MNEMON_EMBED_MODEL: config.embedding.model
|
|
2865
|
+
MNEMON_EMBED_MODEL: config.embedding.model,
|
|
2866
|
+
MNEMON_EMBED_API_KEY: config.embedding.apiKey,
|
|
2867
|
+
...config.embedding.protocol === "auto" ? {} : { MNEMON_EMBED_PROTOCOL: config.embedding.protocol }
|
|
2857
2868
|
};
|
|
2858
2869
|
}
|
|
2859
2870
|
function createRunner(config, processRunner = runProcess, workspaceRoot) {
|
|
2860
|
-
const
|
|
2861
|
-
const command = found ?? config.cliPath ?? "mnemon";
|
|
2871
|
+
const currentCommand = () => findMnemonCommand(config) ?? config.cliPath ?? "mnemon";
|
|
2862
2872
|
let processQueue = Promise.resolve();
|
|
2863
2873
|
const globalArgs = (store) => {
|
|
2864
2874
|
const args = [];
|
|
@@ -2891,7 +2901,7 @@ function createRunner(config, processRunner = runProcess, workspaceRoot) {
|
|
|
2891
2901
|
};
|
|
2892
2902
|
let result;
|
|
2893
2903
|
try {
|
|
2894
|
-
result = await processRunner(
|
|
2904
|
+
result = await processRunner(currentCommand(), argv, processOptions);
|
|
2895
2905
|
} catch (error) {
|
|
2896
2906
|
throw new MnemonCliError(`${error instanceof Error ? error.message : String(error)}. ${process.platform === "win32" ? "Install the official Mnemon Windows release, ensure mnemon.exe is on PATH or under %LOCALAPPDATA%\\Programs\\mnemon, or set MNEMON_CLI_PATH or mnemon.cliPath to its absolute path." : "Install Mnemon and ensure \"mnemon\" is on PATH, or set MNEMON_CLI_PATH or mnemon.cliPath."}`);
|
|
2897
2907
|
}
|
|
@@ -2907,8 +2917,13 @@ function createRunner(config, processRunner = runProcess, workspaceRoot) {
|
|
|
2907
2917
|
return result;
|
|
2908
2918
|
};
|
|
2909
2919
|
return {
|
|
2910
|
-
command
|
|
2911
|
-
|
|
2920
|
+
get command() {
|
|
2921
|
+
return currentCommand();
|
|
2922
|
+
},
|
|
2923
|
+
get commandFound() {
|
|
2924
|
+
const found = findMnemonCommand(config);
|
|
2925
|
+
return found !== void 0 && executable$1(found);
|
|
2926
|
+
},
|
|
2912
2927
|
config,
|
|
2913
2928
|
async runJson(args, options) {
|
|
2914
2929
|
const stdout = await execute(args, options);
|
|
@@ -4318,8 +4333,9 @@ var MnemonService = class {
|
|
|
4318
4333
|
/** Probe the effective Mnemon embedding runtime and its default Store coverage. */
|
|
4319
4334
|
async embeddingStatus(signal) {
|
|
4320
4335
|
const output = record$1(await this.runner.runJson(["embed", "--status"], signal === void 0 ? {} : { signal }));
|
|
4321
|
-
const available = output?.ollama_available;
|
|
4336
|
+
const available = output?.embedding_available ?? output?.ollama_available;
|
|
4322
4337
|
const model = text$1(output?.model)?.trim();
|
|
4338
|
+
const protocol = text$1(output?.protocol)?.trim();
|
|
4323
4339
|
const totalInsights = number(output?.total_insights);
|
|
4324
4340
|
const embedded = number(output?.embedded);
|
|
4325
4341
|
const coverage = text$1(output?.coverage)?.trim();
|
|
@@ -4329,7 +4345,8 @@ var MnemonService = class {
|
|
|
4329
4345
|
model,
|
|
4330
4346
|
totalInsights,
|
|
4331
4347
|
embedded,
|
|
4332
|
-
coverage
|
|
4348
|
+
coverage,
|
|
4349
|
+
...protocol !== void 0 && protocol.length <= 32 && !/[\u0000-\u001f\u007f]/u.test(protocol) ? { protocol } : {}
|
|
4333
4350
|
};
|
|
4334
4351
|
}
|
|
4335
4352
|
async status(signal) {
|
|
@@ -6412,8 +6429,16 @@ function boundedModelText(value, maximum) {
|
|
|
6412
6429
|
function insightDigest(result) {
|
|
6413
6430
|
return sha256(result.content.trim().replace(/\s+/gu, " "));
|
|
6414
6431
|
}
|
|
6415
|
-
function recallQueryDigest(
|
|
6416
|
-
|
|
6432
|
+
function recallQueryDigest(request) {
|
|
6433
|
+
const lexical = (request.query.match(/[\p{L}\p{N}]+/gu) ?? []).join(" ").toLocaleLowerCase();
|
|
6434
|
+
return sha256(JSON.stringify({
|
|
6435
|
+
query: lexical,
|
|
6436
|
+
memoryBodyIds: [...request.memoryBodyIds ?? []].sort()
|
|
6437
|
+
}));
|
|
6438
|
+
}
|
|
6439
|
+
/** A replay must still respect the current call's selected Source subset. */
|
|
6440
|
+
function replayEvidence(results, memoryBodyIds) {
|
|
6441
|
+
return structuredClone(memoryBodyIds === void 0 ? results : results.filter((result) => result.memoryBodyId !== void 0 && memoryBodyIds.includes(result.memoryBodyId)));
|
|
6417
6442
|
}
|
|
6418
6443
|
/** Admit a small, deduplicated evidence envelope after Provider quality policy. */
|
|
6419
6444
|
function boundedModelInsights(results, admission = {}) {
|
|
@@ -6863,7 +6888,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
6863
6888
|
};
|
|
6864
6889
|
runtimeQueue = Promise.resolve();
|
|
6865
6890
|
documentQueue = Promise.resolve();
|
|
6866
|
-
retrievalTurns = /* @__PURE__ */ new
|
|
6891
|
+
retrievalTurns = /* @__PURE__ */ new WeakMap();
|
|
6867
6892
|
constructor(subagents, runtimeMemoryOrSource, documents, resultRuntime, taskAgentModelResolver, runtimeMaintenanceMaxTokensResolver) {
|
|
6868
6893
|
this.subagents = subagents;
|
|
6869
6894
|
this.runtimeMemoryOrSource = runtimeMemoryOrSource;
|
|
@@ -6887,17 +6912,19 @@ var MnemonSubagentCoordinator = class {
|
|
|
6887
6912
|
...limit === void 0 ? {} : { limit }
|
|
6888
6913
|
});
|
|
6889
6914
|
}
|
|
6890
|
-
/** Admit at most one model-facing Documents query for one
|
|
6915
|
+
/** Admit at most one model-facing Documents query for one executing turn. */
|
|
6891
6916
|
claimDocumentSearch(parent) {
|
|
6892
6917
|
const authority = this.turnAuthority(parent, false);
|
|
6893
6918
|
if (authority === void 0) return true;
|
|
6894
|
-
const retrieval = this.turnRetrievalState(authority.
|
|
6919
|
+
const retrieval = this.turnRetrievalState(authority.context);
|
|
6895
6920
|
if (retrieval.documentSearchClaimed === true) return false;
|
|
6896
6921
|
retrieval.documentSearchClaimed = true;
|
|
6897
6922
|
return true;
|
|
6898
6923
|
}
|
|
6899
6924
|
async recall(parent, request, signal, options = {}) {
|
|
6925
|
+
signal.throwIfAborted();
|
|
6900
6926
|
const authority = this.recallAuthority(parent, options.requirePinnedView === true);
|
|
6927
|
+
const service = authority?.service ?? this.serviceFor(parent);
|
|
6901
6928
|
const limited = {
|
|
6902
6929
|
query: request.query,
|
|
6903
6930
|
...request.mode === void 0 ? {} : { mode: request.mode },
|
|
@@ -6905,15 +6932,15 @@ var MnemonSubagentCoordinator = class {
|
|
|
6905
6932
|
...request.memoryBodyIds === void 0 ? {} : { memoryBodyIds: request.memoryBodyIds }
|
|
6906
6933
|
};
|
|
6907
6934
|
const scoped = this.scopeRecallWithAuthority(limited, authority);
|
|
6908
|
-
const digest = authority === void 0 ? void 0 : recallQueryDigest(scoped
|
|
6909
|
-
const retrieval = authority === void 0 ? void 0 : this.turnRetrievalState(authority.
|
|
6935
|
+
const digest = authority === void 0 ? void 0 : recallQueryDigest(scoped);
|
|
6936
|
+
const retrieval = authority === void 0 ? void 0 : this.turnRetrievalState(authority.context);
|
|
6910
6937
|
const repeated = digest === void 0 ? void 0 : retrieval?.recallAttempts.find((attempt) => attempt.queryDigest === digest);
|
|
6911
6938
|
if (repeated !== void 0) {
|
|
6912
6939
|
const previous = repeated.result ?? await repeated.pending;
|
|
6913
6940
|
return {
|
|
6914
6941
|
query: previous?.query ?? scoped.query,
|
|
6915
6942
|
mode: previous?.mode ?? scoped.mode ?? "smart",
|
|
6916
|
-
results:
|
|
6943
|
+
results: replayEvidence(previous?.results ?? [], scoped.memoryBodyIds),
|
|
6917
6944
|
hint: retrieval?.recallAttempts.length === MODEL_RECALL_ATTEMPT_LIMIT ? "This Recall query already ran. The Host replayed its admitted evidence without another Provider query. The turn Recall budget is closed; stop retrieval and answer from the evidence or state what remains unknown." : "This Recall query already ran. The Host replayed its admitted evidence without another Provider query. If this evidence is insufficient, use at most one materially different focused query; otherwise stop retrieval."
|
|
6918
6945
|
};
|
|
6919
6946
|
}
|
|
@@ -6923,7 +6950,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
6923
6950
|
return {
|
|
6924
6951
|
query: previous?.query ?? scoped.query,
|
|
6925
6952
|
mode: previous?.mode ?? scoped.mode ?? "smart",
|
|
6926
|
-
results:
|
|
6953
|
+
results: replayEvidence(previous?.results ?? [], scoped.memoryBodyIds),
|
|
6927
6954
|
hint: "The two-query turn Recall budget is exhausted. The Host replayed the latest admitted evidence without another Provider query; stop retrieval and answer from the evidence or state what remains unknown."
|
|
6928
6955
|
};
|
|
6929
6956
|
}
|
|
@@ -6933,7 +6960,8 @@ var MnemonSubagentCoordinator = class {
|
|
|
6933
6960
|
if (attempt !== void 0 && retrieval !== void 0) retrieval.recallAttempts.push(attempt);
|
|
6934
6961
|
const operation = (async () => {
|
|
6935
6962
|
if (predecessor !== void 0) await predecessor;
|
|
6936
|
-
|
|
6963
|
+
signal.throwIfAborted();
|
|
6964
|
+
const result = await service.search(scoped, signal);
|
|
6937
6965
|
const priorResults = (retrieval?.recallAttempts.slice(0, attemptIndex) ?? []).flatMap((entry) => entry.result?.results ?? []);
|
|
6938
6966
|
const priorContentCharacters = priorResults.reduce((total, insight) => total + insight.content.length, 0);
|
|
6939
6967
|
const requestedLimit = Math.min(limited.limit ?? MODEL_RECALL_RESULT_LIMIT, MODEL_RECALL_RESULT_LIMIT);
|
|
@@ -6974,7 +7002,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
6974
7002
|
if (attempt?.pending === operation) delete attempt.pending;
|
|
6975
7003
|
}
|
|
6976
7004
|
}
|
|
6977
|
-
/** Bind a model read to the Source state pinned by its
|
|
7005
|
+
/** Bind a model read to the Source state pinned by its own executing turn. */
|
|
6978
7006
|
scopeRecallRequest(agent, request, requirePinnedView = false) {
|
|
6979
7007
|
const authority = this.recallAuthority(agent, requirePinnedView);
|
|
6980
7008
|
return this.scopeRecallWithAuthority(request, authority);
|
|
@@ -7004,9 +7032,11 @@ var MnemonSubagentCoordinator = class {
|
|
|
7004
7032
|
return requested;
|
|
7005
7033
|
}
|
|
7006
7034
|
async related(parent, id, memoryBodyId, signal, options = {}) {
|
|
7035
|
+
signal.throwIfAborted();
|
|
7007
7036
|
const authority = this.recallAuthority(parent, options.requirePinnedView === true);
|
|
7037
|
+
const service = authority?.service ?? this.serviceFor(parent);
|
|
7008
7038
|
const selected = this.scopeRelatedWithAuthority(memoryBodyId, authority);
|
|
7009
|
-
const retrieval = authority === void 0 ? void 0 : this.turnRetrievalState(authority.
|
|
7039
|
+
const retrieval = authority === void 0 ? void 0 : this.turnRetrievalState(authority.context);
|
|
7010
7040
|
const reference = `${selected ?? ""}/${id}`;
|
|
7011
7041
|
if (retrieval !== void 0 && !retrieval.evidenceReferences.has(reference)) return {
|
|
7012
7042
|
query: `related:${id}`,
|
|
@@ -7025,13 +7055,13 @@ var MnemonSubagentCoordinator = class {
|
|
|
7025
7055
|
return {
|
|
7026
7056
|
query: previous?.query ?? `related:${id}`,
|
|
7027
7057
|
mode: previous?.mode ?? "related",
|
|
7028
|
-
results:
|
|
7058
|
+
results: replayEvidence(previous?.results ?? [], selected === void 0 ? void 0 : [selected]),
|
|
7029
7059
|
hint: retrieval.relatedDigest === digest ? "This exact Related traversal already ran. The Host replayed its admitted evidence without another Provider query; stop retrieval and answer from it." : "Related traversal is complete for this turn. The Host replayed the admitted evidence; stop retrieval and answer from it."
|
|
7030
7060
|
};
|
|
7031
7061
|
}
|
|
7032
7062
|
if (retrieval !== void 0 && digest !== void 0) retrieval.relatedDigest = digest;
|
|
7033
7063
|
const operation = (async () => {
|
|
7034
|
-
const admitted = boundedModelInsights(await
|
|
7064
|
+
const admitted = boundedModelInsights(await service.related(id, options.depth, options.edge, signal, selected), {
|
|
7035
7065
|
resultLimit: 4,
|
|
7036
7066
|
totalContentLimit: 4e3,
|
|
7037
7067
|
mediumLimit: 4,
|
|
@@ -7630,45 +7660,38 @@ Completion protocol: call \`${resultToolName}\` exactly once with the final resu
|
|
|
7630
7660
|
}
|
|
7631
7661
|
recallAuthority(agent, required) {
|
|
7632
7662
|
const authority = this.turnAuthority(agent, required);
|
|
7633
|
-
if (authority === void 0
|
|
7634
|
-
const
|
|
7635
|
-
|
|
7663
|
+
if (authority === void 0) return void 0;
|
|
7664
|
+
const { context, graph } = authority;
|
|
7665
|
+
const value = optionalObject(graph.memoryViews.sourceState(context.viewId, "memory-spaces"));
|
|
7666
|
+
if (value === void 0 || !Array.isArray(value.memoryBodyIds) || value.memoryBodyIds.some((id) => typeof id !== "string" || id.trim() === "")) throw new Error(`pinned MemorySource has invalid recall authority: ${context.viewId}`);
|
|
7636
7667
|
const memoryBodyIds = [...new Set(value.memoryBodyIds.map((id) => String(id).trim()))];
|
|
7637
|
-
if (memoryBodyIds.length === 0) throw new Error(`pinned MemorySource has no recall-authorized Memory Spaces: ${
|
|
7668
|
+
if (memoryBodyIds.length === 0) throw new Error(`pinned MemorySource has no recall-authorized Memory Spaces: ${context.viewId}`);
|
|
7638
7669
|
return {
|
|
7639
|
-
|
|
7640
|
-
|
|
7670
|
+
context,
|
|
7671
|
+
viewId: context.viewId,
|
|
7672
|
+
memoryBodyIds,
|
|
7673
|
+
service: graph.service
|
|
7641
7674
|
};
|
|
7642
7675
|
}
|
|
7643
7676
|
turnAuthority(agent, required) {
|
|
7644
7677
|
if (!isAgentRuntimeSource$1(this.runtimeMemoryOrSource)) return void 0;
|
|
7645
|
-
const
|
|
7646
|
-
const
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
if (required) throw new Error("Recall requires the MemorySource generation pinned to the current turn");
|
|
7651
|
-
return;
|
|
7652
|
-
}
|
|
7653
|
-
return {
|
|
7654
|
-
turnId: pinned.turnId,
|
|
7655
|
-
viewId: pinned.viewId
|
|
7678
|
+
const graph = this.runtimeMemoryOrSource.forAgent(agent);
|
|
7679
|
+
const context = graph.memoryViews.activeTurn(agent.id);
|
|
7680
|
+
if (context !== void 0) return {
|
|
7681
|
+
context,
|
|
7682
|
+
graph
|
|
7656
7683
|
};
|
|
7684
|
+
if (required) throw new Error("Recall requires the MemorySource generation pinned to the current turn");
|
|
7657
7685
|
}
|
|
7658
|
-
turnRetrievalState(
|
|
7659
|
-
const current = this.retrievalTurns.get(
|
|
7686
|
+
turnRetrievalState(context) {
|
|
7687
|
+
const current = this.retrievalTurns.get(context);
|
|
7660
7688
|
if (current !== void 0) return current;
|
|
7661
|
-
while (this.retrievalTurns.size >= 128) {
|
|
7662
|
-
const oldest = this.retrievalTurns.keys().next().value;
|
|
7663
|
-
if (oldest === void 0) break;
|
|
7664
|
-
this.retrievalTurns.delete(oldest);
|
|
7665
|
-
}
|
|
7666
7689
|
const created = {
|
|
7667
7690
|
recallAttempts: [],
|
|
7668
7691
|
evidenceDigests: /* @__PURE__ */ new Set(),
|
|
7669
7692
|
evidenceReferences: /* @__PURE__ */ new Set()
|
|
7670
7693
|
};
|
|
7671
|
-
this.retrievalTurns.set(
|
|
7694
|
+
this.retrievalTurns.set(context, created);
|
|
7672
7695
|
return created;
|
|
7673
7696
|
}
|
|
7674
7697
|
recordRecall() {
|
|
@@ -7829,6 +7852,148 @@ var TurnActivityProjection = class {
|
|
|
7829
7852
|
}
|
|
7830
7853
|
};
|
|
7831
7854
|
//#endregion
|
|
7855
|
+
//#region src/agent-memory-turn.ts
|
|
7856
|
+
function agentMemoryScope(agent, graph) {
|
|
7857
|
+
const cwd = agent.session.header?.cwd?.trim();
|
|
7858
|
+
return {
|
|
7859
|
+
storage: graph.config.storageScope,
|
|
7860
|
+
...cwd === void 0 || cwd === "" ? {} : { workspaceId: resolve(cwd) },
|
|
7861
|
+
sessionId: agent.id,
|
|
7862
|
+
agentId: agent.id
|
|
7863
|
+
};
|
|
7864
|
+
}
|
|
7865
|
+
/** The durable log, not a parent session id, identifies the executing turn. */
|
|
7866
|
+
function openAgentTurn(agent) {
|
|
7867
|
+
let open;
|
|
7868
|
+
for (const event of agent.session.events) {
|
|
7869
|
+
const turn = typeof event.data.turn === "number" ? event.data.turn : void 0;
|
|
7870
|
+
if (event.type === "turn/start" && turn !== void 0) open = turn;
|
|
7871
|
+
else if (event.type === "turn/end" && turn === open) open = void 0;
|
|
7872
|
+
}
|
|
7873
|
+
return open;
|
|
7874
|
+
}
|
|
7875
|
+
/**
|
|
7876
|
+
* One Agent owns each turn pin. A child additionally retains its delegation
|
|
7877
|
+
* across parent completion, collection, and runtime swaps until it is disposed.
|
|
7878
|
+
*/
|
|
7879
|
+
var AgentMemoryTurn = class {
|
|
7880
|
+
agent;
|
|
7881
|
+
runtime;
|
|
7882
|
+
delegation;
|
|
7883
|
+
pinned;
|
|
7884
|
+
pending;
|
|
7885
|
+
generation = 0;
|
|
7886
|
+
closed = false;
|
|
7887
|
+
releaseDelegation;
|
|
7888
|
+
constructor(agent, runtime, delegation) {
|
|
7889
|
+
this.agent = agent;
|
|
7890
|
+
this.runtime = runtime;
|
|
7891
|
+
this.delegation = delegation;
|
|
7892
|
+
if (delegation === void 0) return;
|
|
7893
|
+
const releaseView = delegation.viewId === void 0 ? void 0 : delegation.graph.memoryViews.retainView(delegation.viewId);
|
|
7894
|
+
try {
|
|
7895
|
+
const releaseRuntime = runtime.bindAgentRuntime(agent.id, delegation.graph);
|
|
7896
|
+
this.releaseDelegation = () => {
|
|
7897
|
+
try {
|
|
7898
|
+
releaseView?.();
|
|
7899
|
+
} finally {
|
|
7900
|
+
releaseRuntime();
|
|
7901
|
+
}
|
|
7902
|
+
};
|
|
7903
|
+
} catch (error) {
|
|
7904
|
+
releaseView?.();
|
|
7905
|
+
throw error;
|
|
7906
|
+
}
|
|
7907
|
+
}
|
|
7908
|
+
get current() {
|
|
7909
|
+
return this.pinned;
|
|
7910
|
+
}
|
|
7911
|
+
/** Capture now; descendants must not resolve a later parent turn on demand. */
|
|
7912
|
+
delegate() {
|
|
7913
|
+
if (this.closed) throw new Error("memory Agent lifetime has ended");
|
|
7914
|
+
if (this.pinned !== void 0) return {
|
|
7915
|
+
graph: this.pinned.graph,
|
|
7916
|
+
scope: this.pinned.context.scope,
|
|
7917
|
+
viewId: this.pinned.context.viewId
|
|
7918
|
+
};
|
|
7919
|
+
if (this.delegation !== void 0) return this.delegation;
|
|
7920
|
+
const graph = this.runtime.forAgent(this.agent);
|
|
7921
|
+
return {
|
|
7922
|
+
graph,
|
|
7923
|
+
scope: agentMemoryScope(this.agent, graph)
|
|
7924
|
+
};
|
|
7925
|
+
}
|
|
7926
|
+
async begin(turn, signal) {
|
|
7927
|
+
if (this.closed) throw new Error("memory Agent lifetime has ended");
|
|
7928
|
+
signal?.throwIfAborted();
|
|
7929
|
+
if (this.pinned?.turn === turn) return;
|
|
7930
|
+
if (this.pending?.turn === turn) return this.pending.result;
|
|
7931
|
+
this.end();
|
|
7932
|
+
const generation = this.generation;
|
|
7933
|
+
const result = this.pin(turn, generation, signal);
|
|
7934
|
+
this.pending = {
|
|
7935
|
+
turn,
|
|
7936
|
+
generation,
|
|
7937
|
+
result
|
|
7938
|
+
};
|
|
7939
|
+
try {
|
|
7940
|
+
await result;
|
|
7941
|
+
} finally {
|
|
7942
|
+
if (this.pending?.generation === generation) this.pending = void 0;
|
|
7943
|
+
}
|
|
7944
|
+
}
|
|
7945
|
+
end(turn) {
|
|
7946
|
+
if (turn !== void 0 && this.pinned?.turn !== turn && this.pending?.turn !== turn) return;
|
|
7947
|
+
this.generation += 1;
|
|
7948
|
+
this.pending = void 0;
|
|
7949
|
+
const pinned = this.pinned;
|
|
7950
|
+
this.pinned = void 0;
|
|
7951
|
+
if (pinned === void 0) return;
|
|
7952
|
+
try {
|
|
7953
|
+
if (pinned.manager.turn(pinned.context.turnId) === pinned.context) pinned.manager.endTurn(pinned.context.turnId);
|
|
7954
|
+
} finally {
|
|
7955
|
+
pinned.releaseRuntime?.();
|
|
7956
|
+
}
|
|
7957
|
+
}
|
|
7958
|
+
dispose() {
|
|
7959
|
+
if (this.closed) return;
|
|
7960
|
+
this.closed = true;
|
|
7961
|
+
try {
|
|
7962
|
+
this.end();
|
|
7963
|
+
} finally {
|
|
7964
|
+
this.releaseDelegation?.();
|
|
7965
|
+
}
|
|
7966
|
+
}
|
|
7967
|
+
async pin(turn, generation, signal) {
|
|
7968
|
+
const graph = this.delegation?.graph ?? this.runtime.forAgent(this.agent);
|
|
7969
|
+
const manager = graph.memoryViews;
|
|
7970
|
+
const scope = this.delegation === void 0 ? agentMemoryScope(this.agent, graph) : {
|
|
7971
|
+
...this.delegation.scope,
|
|
7972
|
+
sessionId: this.agent.id,
|
|
7973
|
+
agentId: this.agent.id
|
|
7974
|
+
};
|
|
7975
|
+
const turnId = `${this.agent.id}:${turn}`;
|
|
7976
|
+
const context = this.delegation?.viewId === void 0 ? await manager.beginTurn(turnId, scope) : manager.pinTurn(turnId, scope, this.delegation.viewId);
|
|
7977
|
+
let releaseRuntime;
|
|
7978
|
+
try {
|
|
7979
|
+
if (this.closed || this.generation !== generation) throw new Error("memory turn ended during View preparation");
|
|
7980
|
+
signal?.throwIfAborted();
|
|
7981
|
+
if (this.delegation === void 0) releaseRuntime = this.runtime.bindAgentRuntime(this.agent.id, graph);
|
|
7982
|
+
this.pinned = {
|
|
7983
|
+
turn,
|
|
7984
|
+
graph,
|
|
7985
|
+
manager,
|
|
7986
|
+
context,
|
|
7987
|
+
...releaseRuntime === void 0 ? {} : { releaseRuntime }
|
|
7988
|
+
};
|
|
7989
|
+
} catch (error) {
|
|
7990
|
+
if (manager.turn(context.turnId) === context) manager.endTurn(context.turnId);
|
|
7991
|
+
releaseRuntime?.();
|
|
7992
|
+
throw error;
|
|
7993
|
+
}
|
|
7994
|
+
}
|
|
7995
|
+
};
|
|
7996
|
+
//#endregion
|
|
7832
7997
|
//#region src/lifecycle.ts
|
|
7833
7998
|
function modelService(value) {
|
|
7834
7999
|
if (typeof value !== "object" || value === null || !("currentSelection" in value) || typeof value.currentSelection !== "function") return void 0;
|
|
@@ -7935,7 +8100,7 @@ var MnemonAgentLifecycle = class {
|
|
|
7935
8100
|
coordinator;
|
|
7936
8101
|
config;
|
|
7937
8102
|
counters;
|
|
7938
|
-
|
|
8103
|
+
memoryTurn;
|
|
7939
8104
|
primePending = true;
|
|
7940
8105
|
startSource;
|
|
7941
8106
|
guidedTurns = /* @__PURE__ */ new Set();
|
|
@@ -7947,6 +8112,14 @@ var MnemonAgentLifecycle = class {
|
|
|
7947
8112
|
* actually see, which is what makes a rewind self-correcting.
|
|
7948
8113
|
*/
|
|
7949
8114
|
cueInjected = false;
|
|
8115
|
+
/**
|
|
8116
|
+
* Text of the runtime memory snapshot most recently injected as this
|
|
8117
|
+
* plugin's own message. `.context()` used to get supersede-on-change for free
|
|
8118
|
+
* from the host's runtime-context projection; carrying the snapshot as an own
|
|
8119
|
+
* message means re-emitting on change is this plugin's responsibility, and
|
|
8120
|
+
* the rendered text (which carries the revision digest) is the key.
|
|
8121
|
+
*/
|
|
8122
|
+
injectedMemoryText;
|
|
7950
8123
|
idleReviewTimer;
|
|
7951
8124
|
reviewController;
|
|
7952
8125
|
reviewRunning = false;
|
|
@@ -7957,13 +8130,12 @@ var MnemonAgentLifecycle = class {
|
|
|
7957
8130
|
lastPhase = "idle";
|
|
7958
8131
|
lastAt;
|
|
7959
8132
|
lastError;
|
|
7960
|
-
|
|
7961
|
-
constructor(agent, coordinator, config, counters, source, runtimeSource) {
|
|
8133
|
+
constructor(agent, coordinator, config, counters, source, memoryTurn) {
|
|
7962
8134
|
this.agent = agent;
|
|
7963
8135
|
this.coordinator = coordinator;
|
|
7964
8136
|
this.config = config;
|
|
7965
8137
|
this.counters = counters;
|
|
7966
|
-
this.
|
|
8138
|
+
this.memoryTurn = memoryTurn;
|
|
7967
8139
|
this.startSource = source;
|
|
7968
8140
|
}
|
|
7969
8141
|
start() {
|
|
@@ -7981,7 +8153,7 @@ var MnemonAgentLifecycle = class {
|
|
|
7981
8153
|
})),
|
|
7982
8154
|
this.agent.ctx.on("session/event", ((session, event) => this.sessionEvent(session, event))),
|
|
7983
8155
|
this.agent.ctx.on("system-prompt/assemble", ((assembly, context, next) => this.assemblePrompt(assembly, context, next))),
|
|
7984
|
-
this.agent.ctx.on("agent/pre-step", ((payload, next) => this.preStep(payload, next))),
|
|
8156
|
+
this.agent.ctx.on("agent/pre-step", ((payload, next) => this.preStep(payload, next)), { prepend: true }),
|
|
7985
8157
|
this.agent.ctx.on("agent/turn-stopping", ((payload) => this.finishTurn(payload)))
|
|
7986
8158
|
];
|
|
7987
8159
|
return () => {
|
|
@@ -8023,7 +8195,7 @@ var MnemonAgentLifecycle = class {
|
|
|
8023
8195
|
return assistantMessageText(this.agent.session.events, messageId);
|
|
8024
8196
|
}
|
|
8025
8197
|
memoryWake() {
|
|
8026
|
-
const pinned = this.
|
|
8198
|
+
const pinned = this.memoryTurn?.current;
|
|
8027
8199
|
return pinned === void 0 ? void 0 : pinned.manager.wake(pinned.context.viewId);
|
|
8028
8200
|
}
|
|
8029
8201
|
/**
|
|
@@ -8044,6 +8216,23 @@ var MnemonAgentLifecycle = class {
|
|
|
8044
8216
|
for (const seq of nodes) if (isOwnUserMessageEvent(this.agent.session.events[seq])) return true;
|
|
8045
8217
|
return false;
|
|
8046
8218
|
}
|
|
8219
|
+
/**
|
|
8220
|
+
* The runtime memory snapshot, as this plugin's own message, when it changed.
|
|
8221
|
+
*
|
|
8222
|
+
* `.context()` used to carry this inside the host's shared runtime-context
|
|
8223
|
+
* projection. Carrying it here instead attributes it to dsh-mnemon and keeps
|
|
8224
|
+
* a memory write from re-emitting other contributors' sections; supersede
|
|
8225
|
+
* stays intact because the block is still a complete state replacing its
|
|
8226
|
+
* predecessor, keyed on the rendered text's revision digest.
|
|
8227
|
+
*/
|
|
8228
|
+
memorySnapshotMessage() {
|
|
8229
|
+
const wake = this.memoryWake();
|
|
8230
|
+
if (wake === void 0) return void 0;
|
|
8231
|
+
const text = memoryPromptText(wake.text);
|
|
8232
|
+
if (text.trim() === "" || text === this.injectedMemoryText) return void 0;
|
|
8233
|
+
this.injectedMemoryText = text;
|
|
8234
|
+
return createPluginMessage(text, "recall", "Runtime memory snapshot");
|
|
8235
|
+
}
|
|
8047
8236
|
async preStep(payload, next) {
|
|
8048
8237
|
if (payload.step === 1) this.cancelIdleReview(true);
|
|
8049
8238
|
const decision = await next();
|
|
@@ -8059,14 +8248,22 @@ var MnemonAgentLifecycle = class {
|
|
|
8059
8248
|
return source.kind === "plugin" && source.plugin === "dsh-mnemon";
|
|
8060
8249
|
})) return decision;
|
|
8061
8250
|
if (decision.messages.length === 0) return decision;
|
|
8251
|
+
const snapshot = this.memorySnapshotMessage();
|
|
8252
|
+
const withSnapshot = (messages) => snapshot === void 0 ? messages : [...messages, snapshot];
|
|
8062
8253
|
if (this.primePending) {
|
|
8063
8254
|
this.primePending = false;
|
|
8064
8255
|
this.counters.primes += 1;
|
|
8065
8256
|
this.mark("prime");
|
|
8066
8257
|
}
|
|
8067
|
-
if (this.cueAlreadyVisible()) return
|
|
8258
|
+
if (this.cueAlreadyVisible()) return {
|
|
8259
|
+
kind: "enter",
|
|
8260
|
+
messages: withSnapshot(decision.messages)
|
|
8261
|
+
};
|
|
8068
8262
|
const reminder = guidedReminder(this.config);
|
|
8069
|
-
if (reminder === void 0) return
|
|
8263
|
+
if (reminder === void 0) return {
|
|
8264
|
+
kind: "enter",
|
|
8265
|
+
messages: withSnapshot(decision.messages)
|
|
8266
|
+
};
|
|
8070
8267
|
this.cueInjected = true;
|
|
8071
8268
|
this.guidedTurns.add(payload.turn);
|
|
8072
8269
|
if (this.config.recallMode === "guided") this.counters.recallCues += 1;
|
|
@@ -8074,63 +8271,21 @@ var MnemonAgentLifecycle = class {
|
|
|
8074
8271
|
this.mark(this.config.recallMode === "guided" ? "recall" : "writeback");
|
|
8075
8272
|
return {
|
|
8076
8273
|
kind: "enter",
|
|
8077
|
-
messages: [...decision.messages, createPluginMessage(reminder, "instructions", "Optional memory recall and remember reminder")]
|
|
8274
|
+
messages: withSnapshot([...decision.messages, createPluginMessage(reminder, "instructions", "Optional memory recall and remember reminder")])
|
|
8078
8275
|
};
|
|
8079
8276
|
}
|
|
8080
8277
|
async assemblePrompt(assembly, context, next) {
|
|
8081
8278
|
if (context.agent !== void 0 && context.agent.id !== this.agent.id) return next();
|
|
8082
8279
|
const turn = this.openTurn();
|
|
8083
8280
|
if (turn === void 0 || context.signal?.aborted === true) return next();
|
|
8084
|
-
await this.
|
|
8281
|
+
await this.memoryTurn?.begin(turn, context.signal);
|
|
8085
8282
|
return applyAgentMemoryViewWake(await next(), this.memoryWake());
|
|
8086
8283
|
}
|
|
8087
8284
|
openTurn() {
|
|
8088
|
-
|
|
8089
|
-
for (const event of this.agent.session.events) {
|
|
8090
|
-
const turn = eventTurn(event);
|
|
8091
|
-
if (event.type === "turn/start" && turn !== void 0) open = turn;
|
|
8092
|
-
else if (event.type === "turn/end" && turn === open) open = void 0;
|
|
8093
|
-
}
|
|
8094
|
-
return open;
|
|
8095
|
-
}
|
|
8096
|
-
async pinView(turn) {
|
|
8097
|
-
if (this.pinnedView?.turn === turn) return;
|
|
8098
|
-
this.releaseView();
|
|
8099
|
-
const graph = this.runtimeSource?.forAgent(this.agent);
|
|
8100
|
-
const manager = graph?.memoryViews;
|
|
8101
|
-
if (manager === void 0 || graph === void 0 || this.runtimeSource === void 0) return;
|
|
8102
|
-
const cwd = this.agent.session.header?.cwd?.trim();
|
|
8103
|
-
const scope = {
|
|
8104
|
-
storage: this.config.storageScope,
|
|
8105
|
-
...cwd === void 0 || cwd === "" ? {} : { workspaceId: resolve(cwd) },
|
|
8106
|
-
sessionId: this.agent.id,
|
|
8107
|
-
agentId: this.agent.id
|
|
8108
|
-
};
|
|
8109
|
-
const context = await manager.beginTurn(`${this.agent.id}:${turn}`, scope);
|
|
8110
|
-
let releaseRuntime;
|
|
8111
|
-
try {
|
|
8112
|
-
releaseRuntime = this.runtimeSource.bindAgentRuntime(this.agent.id, graph);
|
|
8113
|
-
this.pinnedView = {
|
|
8114
|
-
turn,
|
|
8115
|
-
manager,
|
|
8116
|
-
context,
|
|
8117
|
-
releaseRuntime
|
|
8118
|
-
};
|
|
8119
|
-
} catch (error) {
|
|
8120
|
-
manager.endTurn(context.turnId);
|
|
8121
|
-
releaseRuntime?.();
|
|
8122
|
-
throw error;
|
|
8123
|
-
}
|
|
8285
|
+
return openAgentTurn(this.agent);
|
|
8124
8286
|
}
|
|
8125
8287
|
releaseView(turn) {
|
|
8126
|
-
|
|
8127
|
-
if (pinned === void 0 || turn !== void 0 && pinned.turn !== turn) return;
|
|
8128
|
-
this.pinnedView = void 0;
|
|
8129
|
-
try {
|
|
8130
|
-
pinned.manager.endTurn(pinned.context.turnId);
|
|
8131
|
-
} finally {
|
|
8132
|
-
pinned.releaseRuntime();
|
|
8133
|
-
}
|
|
8288
|
+
this.memoryTurn?.end(turn);
|
|
8134
8289
|
}
|
|
8135
8290
|
async finishTurn(payload) {
|
|
8136
8291
|
this.scheduleIdleReview(payload.turn);
|
|
@@ -8138,7 +8293,8 @@ var MnemonAgentLifecycle = class {
|
|
|
8138
8293
|
sessionEvent(session, event) {
|
|
8139
8294
|
if (session !== this.agent.session || event.type !== "turn/end") return;
|
|
8140
8295
|
const turn = eventTurn(event);
|
|
8141
|
-
const
|
|
8296
|
+
const current = this.memoryTurn?.current;
|
|
8297
|
+
const pinned = turn === void 0 || current?.turn !== turn ? void 0 : current;
|
|
8142
8298
|
if (pinned === void 0) return;
|
|
8143
8299
|
this.releaseView(turn);
|
|
8144
8300
|
pinned.manager.reconcile(pinned.context.scope).catch((error) => this.fail(error));
|
|
@@ -8267,6 +8423,8 @@ var MnemonLifecycle = class {
|
|
|
8267
8423
|
config;
|
|
8268
8424
|
runtimeSource;
|
|
8269
8425
|
owners = /* @__PURE__ */ new Map();
|
|
8426
|
+
children = /* @__PURE__ */ new Map();
|
|
8427
|
+
memoryTurns = /* @__PURE__ */ new Map();
|
|
8270
8428
|
counters = {
|
|
8271
8429
|
primes: 0,
|
|
8272
8430
|
recallCues: 0,
|
|
@@ -8291,8 +8449,11 @@ var MnemonLifecycle = class {
|
|
|
8291
8449
|
for (const agent of this.ctx.agents.roots()) this.install(agent, "adopted");
|
|
8292
8450
|
return () => {
|
|
8293
8451
|
stopCreated();
|
|
8452
|
+
for (const dispose of [...this.children.values()].reverse()) dispose();
|
|
8294
8453
|
for (const owner of [...this.owners.values()].reverse()) owner.dispose();
|
|
8454
|
+
this.children.clear();
|
|
8295
8455
|
this.owners.clear();
|
|
8456
|
+
this.memoryTurns.clear();
|
|
8296
8457
|
};
|
|
8297
8458
|
}
|
|
8298
8459
|
snapshot(sessionId, workspaceRoot) {
|
|
@@ -8634,22 +8795,93 @@ var MnemonLifecycle = class {
|
|
|
8634
8795
|
return this.taskAgentModelRoute(fallbackSessionId, workspaceRoot)?.options;
|
|
8635
8796
|
}
|
|
8636
8797
|
install(agent, source) {
|
|
8637
|
-
if (this.taskAgentIds.has(agent.id) || this.owners.has(agent) ||
|
|
8638
|
-
|
|
8798
|
+
if (this.taskAgentIds.has(agent.id) || this.owners.has(agent) || this.children.has(agent)) return;
|
|
8799
|
+
if (agent.session.header?.origin === "subagent") {
|
|
8800
|
+
this.installChild(agent);
|
|
8801
|
+
return;
|
|
8802
|
+
}
|
|
8803
|
+
if (!this.ctx.agents.roots().includes(agent)) return;
|
|
8804
|
+
const memoryTurn = this.runtimeSource === void 0 ? void 0 : new AgentMemoryTurn(agent, this.runtimeSource);
|
|
8805
|
+
const lifecycle = new MnemonAgentLifecycle(agent, this.coordinator, this.config, this.counters, source, memoryTurn);
|
|
8639
8806
|
let dispose;
|
|
8640
8807
|
dispose = agent.ctx.effect(() => {
|
|
8641
8808
|
const stop = lifecycle.start();
|
|
8642
8809
|
const stopRuntimeContext = this.runtimeSource === void 0 ? () => {} : registerAgentMemoryViewContext(agent, () => lifecycle.memoryWake());
|
|
8643
8810
|
return () => {
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8811
|
+
try {
|
|
8812
|
+
stopRuntimeContext();
|
|
8813
|
+
stop();
|
|
8814
|
+
} finally {
|
|
8815
|
+
memoryTurn?.dispose();
|
|
8816
|
+
if (this.owners.get(agent)?.dispose === dispose) this.owners.delete(agent);
|
|
8817
|
+
if (this.memoryTurns.get(agent) === memoryTurn) this.memoryTurns.delete(agent);
|
|
8818
|
+
}
|
|
8647
8819
|
};
|
|
8648
8820
|
}, "dsh-mnemon.lifecycle()");
|
|
8649
8821
|
this.owners.set(agent, {
|
|
8650
8822
|
lifecycle,
|
|
8651
8823
|
dispose
|
|
8652
8824
|
});
|
|
8825
|
+
if (memoryTurn !== void 0) this.memoryTurns.set(agent, memoryTurn);
|
|
8826
|
+
}
|
|
8827
|
+
/** Child memory ownership is independent of root-only reminders and idle review. */
|
|
8828
|
+
installChild(agent) {
|
|
8829
|
+
const runtime = this.runtimeSource;
|
|
8830
|
+
const parentId = agent.session.header?.parentSession?.trim();
|
|
8831
|
+
const parent = parentId === void 0 || parentId === "" ? void 0 : this.ctx.agents.get(parentId);
|
|
8832
|
+
if (runtime === void 0 || parent === void 0 || parent === agent) return;
|
|
8833
|
+
const parentMemory = this.memoryTurns.get(parent);
|
|
8834
|
+
let delegation;
|
|
8835
|
+
if (parentMemory !== void 0) delegation = parentMemory.delegate();
|
|
8836
|
+
else {
|
|
8837
|
+
const graph = runtime.forAgent(parent);
|
|
8838
|
+
const parentPin = graph.memoryViews.activeTurn(parent.id);
|
|
8839
|
+
delegation = {
|
|
8840
|
+
graph,
|
|
8841
|
+
scope: parentPin?.scope ?? agentMemoryScope(parent, graph),
|
|
8842
|
+
...parentPin === void 0 ? {} : { viewId: parentPin.viewId }
|
|
8843
|
+
};
|
|
8844
|
+
}
|
|
8845
|
+
let dispose;
|
|
8846
|
+
dispose = agent.ctx.effect(() => {
|
|
8847
|
+
const memory = new AgentMemoryTurn(agent, runtime, delegation);
|
|
8848
|
+
this.memoryTurns.set(agent, memory);
|
|
8849
|
+
const stops = [];
|
|
8850
|
+
const cleanup = () => {
|
|
8851
|
+
try {
|
|
8852
|
+
for (const stop of stops.reverse()) stop();
|
|
8853
|
+
} finally {
|
|
8854
|
+
try {
|
|
8855
|
+
memory.dispose();
|
|
8856
|
+
} finally {
|
|
8857
|
+
if (this.memoryTurns.get(agent) === memory) this.memoryTurns.delete(agent);
|
|
8858
|
+
if (this.children.get(agent) === dispose) this.children.delete(agent);
|
|
8859
|
+
}
|
|
8860
|
+
}
|
|
8861
|
+
};
|
|
8862
|
+
try {
|
|
8863
|
+
stops.push(agent.ctx.on("agent/session-start", (() => memory.end())));
|
|
8864
|
+
stops.push(agent.ctx.on("system-prompt/assemble", (async (_assembly, context, next) => {
|
|
8865
|
+
if (context.agent !== void 0 && context.agent !== agent) return next();
|
|
8866
|
+
const turn = openAgentTurn(agent);
|
|
8867
|
+
if (turn !== void 0) await memory.begin(turn, context.signal);
|
|
8868
|
+
return next();
|
|
8869
|
+
})));
|
|
8870
|
+
stops.push(agent.ctx.on("agent/pre-step", (async (payload, next) => {
|
|
8871
|
+
const decision = await next();
|
|
8872
|
+
if (decision.kind === "reject" || payload.signal.aborted) memory.end(payload.turn);
|
|
8873
|
+
return decision;
|
|
8874
|
+
})));
|
|
8875
|
+
stops.push(agent.ctx.on("session/event", ((session, event) => {
|
|
8876
|
+
if (session === agent.session && event.type === "turn/end") memory.end(eventTurn(event));
|
|
8877
|
+
})));
|
|
8878
|
+
} catch (error) {
|
|
8879
|
+
cleanup();
|
|
8880
|
+
throw error;
|
|
8881
|
+
}
|
|
8882
|
+
return cleanup;
|
|
8883
|
+
}, "dsh-mnemon.child-memory()");
|
|
8884
|
+
this.children.set(agent, dispose);
|
|
8653
8885
|
}
|
|
8654
8886
|
};
|
|
8655
8887
|
//#endregion
|
|
@@ -9324,11 +9556,7 @@ const ACTIVATION_PAYLOAD_FIELDS = /* @__PURE__ */ new Set([
|
|
|
9324
9556
|
"sessionId",
|
|
9325
9557
|
"workspaceId"
|
|
9326
9558
|
]);
|
|
9327
|
-
/**
|
|
9328
|
-
* Expose only DSH read-routing activation to trusted Web hosts. Metadata,
|
|
9329
|
-
* provider connections, credentials, and durable memory writes stay on the
|
|
9330
|
-
* loopback-only write channel.
|
|
9331
|
-
*/
|
|
9559
|
+
/** Keep activation on a narrow, independently validated control endpoint. */
|
|
9332
9560
|
function createActivationHandler(input) {
|
|
9333
9561
|
return async (endpoint, rawPayload) => {
|
|
9334
9562
|
try {
|
|
@@ -9566,7 +9794,7 @@ function createWriteHandler(input, lifecycle, runtimeMemory, versions) {
|
|
|
9566
9794
|
}
|
|
9567
9795
|
};
|
|
9568
9796
|
}
|
|
9569
|
-
/** Backup payloads contain private memory and
|
|
9797
|
+
/** Backup payloads contain private memory and stay behind DSH browser authentication. */
|
|
9570
9798
|
function createPackHandler(input, writeEnabled = true) {
|
|
9571
9799
|
return async (endpoint, rawPayload) => {
|
|
9572
9800
|
try {
|
|
@@ -9585,7 +9813,11 @@ function createPackHandler(input, writeEnabled = true) {
|
|
|
9585
9813
|
}
|
|
9586
9814
|
};
|
|
9587
9815
|
}
|
|
9588
|
-
/**
|
|
9816
|
+
/**
|
|
9817
|
+
* Register one call shape across DSH rc.2 and 0.1.2-alpha.1. The former
|
|
9818
|
+
* enforces channel authority; the latter ignores the trailing options object
|
|
9819
|
+
* after applying its uniform browser-session authentication boundary.
|
|
9820
|
+
*/
|
|
9589
9821
|
function registerRpc(connection, input, lifecycle, runtimeMemory, storage, packs, versions, managementAuthority = "loopback") {
|
|
9590
9822
|
const versionManager = versions ?? new VersionUpdateManager({ mnemonCliPath: () => findVersionCli(input) });
|
|
9591
9823
|
connection.rpc.handle(MNEMON_READ_CHANNEL, createReadHandler(input, lifecycle, runtimeMemory, storage, versionManager), { authority: "trusted-host" });
|
|
@@ -9850,7 +10082,7 @@ function requireAgent(exec) {
|
|
|
9850
10082
|
function isAgentRuntimeSource(value) {
|
|
9851
10083
|
return "forAgent" in value && typeof value.forAgent === "function";
|
|
9852
10084
|
}
|
|
9853
|
-
/**
|
|
10085
|
+
/** Model tools use the executing Agent's pinned runtime and deterministic service. */
|
|
9854
10086
|
function registerTools(ctx, serviceOrSource, coordinator, runtimeMemory, documents) {
|
|
9855
10087
|
const runtimeFor = (exec) => {
|
|
9856
10088
|
if (isAgentRuntimeSource(serviceOrSource)) return serviceOrSource.forAgent(requireAgent(exec));
|
|
@@ -10029,7 +10261,7 @@ function registerTools(ctx, serviceOrSource, coordinator, runtimeMemory, documen
|
|
|
10029
10261
|
}));
|
|
10030
10262
|
ctx.tools.register(definition({
|
|
10031
10263
|
name: "mnemon_document_search",
|
|
10032
|
-
description: "Run one focused search over project-scoped managed Documents before durable Recall. The Host admits only one Documents query
|
|
10264
|
+
description: "Run one focused search over project-scoped managed Documents before durable Recall. The Host admits only one Documents query per executing Agent turn; parallel calls share that slot, while child turns have independent budgets. Results contain bounded query-local evidence, not complete records. Cold archives are excluded unless a known archive reference requires them.",
|
|
10033
10265
|
parameters: {
|
|
10034
10266
|
type: "object",
|
|
10035
10267
|
properties: {
|
|
@@ -10060,7 +10292,7 @@ function registerTools(ctx, serviceOrSource, coordinator, runtimeMemory, documen
|
|
|
10060
10292
|
includeArchived: args.includeArchived === true,
|
|
10061
10293
|
notRun: true,
|
|
10062
10294
|
results: [],
|
|
10063
|
-
hint: "
|
|
10295
|
+
hint: "This Agent turn already used its Documents search slot, so no second disk query ran. Use the admitted evidence, make one focused mnemon_recall only if exact durable history is still missing, or answer with appropriate uncertainty."
|
|
10064
10296
|
};
|
|
10065
10297
|
const result = await controller.search(args.query, {
|
|
10066
10298
|
...args.includeArchived === void 0 ? {} : { includeArchived: args.includeArchived },
|