@remnic/core 9.3.743 → 9.3.744
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/access-boundary.d.ts +3 -3
- package/dist/access-cli.js +1 -1
- package/dist/access-http.d.ts +3 -3
- package/dist/access-mcp.d.ts +3 -3
- package/dist/access-operations.d.ts +3 -3
- package/dist/{access-service-BeW5GOg1.d.ts → access-service-OT3Gk79W.d.ts} +1 -1
- package/dist/access-service.d.ts +3 -3
- package/dist/access-surface-catalog.d.ts +3 -3
- package/dist/bootstrap.d.ts +2 -1
- package/dist/{chunk-VO4VARZL.js → chunk-SODQQCAZ.js} +400 -352
- package/dist/chunk-SODQQCAZ.js.map +1 -0
- package/dist/{cli-BYad9YYY.d.ts → cli-BQiTZ7Zs.d.ts} +2 -2
- package/dist/cli.d.ts +3 -3
- package/dist/explicit-capture.d.ts +2 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +1 -1
- package/dist/mcp-memory-inspector-app.d.ts +3 -3
- package/dist/{orchestrator-CupigmWu.d.ts → orchestrator-BPQGHpJz.d.ts} +102 -26
- package/dist/orchestrator.d.ts +2 -1
- package/dist/orchestrator.js +1 -1
- package/package.json +2 -2
- package/src/orchestration/graph-recall-coordinator.ts +471 -0
- package/src/orchestrator.ts +31 -342
- package/dist/chunk-VO4VARZL.js.map +0 -1
|
@@ -512,19 +512,19 @@ import {
|
|
|
512
512
|
} from "./chunk-PVGDJXVK.js";
|
|
513
513
|
|
|
514
514
|
// src/orchestrator.ts
|
|
515
|
-
import
|
|
515
|
+
import path7 from "path";
|
|
516
516
|
import os2 from "os";
|
|
517
|
-
import { createHash as
|
|
517
|
+
import { createHash as createHash3, randomBytes } from "crypto";
|
|
518
518
|
import { existsSync, readFileSync } from "fs";
|
|
519
519
|
import {
|
|
520
520
|
lstat,
|
|
521
|
-
mkdir as
|
|
521
|
+
mkdir as mkdir4,
|
|
522
522
|
readdir as readdir2,
|
|
523
523
|
readFile as readFile2,
|
|
524
524
|
realpath,
|
|
525
525
|
stat,
|
|
526
526
|
unlink,
|
|
527
|
-
writeFile as
|
|
527
|
+
writeFile as writeFile4
|
|
528
528
|
} from "fs/promises";
|
|
529
529
|
|
|
530
530
|
// src/procedural/procedure-recall.ts
|
|
@@ -2196,7 +2196,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2196
2196
|
nsMap = buildMemoryWorthCounterMap(memories);
|
|
2197
2197
|
this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
|
|
2198
2198
|
}
|
|
2199
|
-
for (const [
|
|
2199
|
+
for (const [path8, c] of nsMap) counters.set(path8, c);
|
|
2200
2200
|
} catch (err) {
|
|
2201
2201
|
log.debug("memory-worth: failed to read namespace, skipping", {
|
|
2202
2202
|
namespace: ns,
|
|
@@ -2281,7 +2281,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2281
2281
|
namespaces,
|
|
2282
2282
|
{
|
|
2283
2283
|
readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
|
|
2284
|
-
readMemoryFrontmatter: async (
|
|
2284
|
+
readMemoryFrontmatter: async (path8) => {
|
|
2285
2285
|
if (!fallbackReader) {
|
|
2286
2286
|
for (const ns of namespaces) {
|
|
2287
2287
|
try {
|
|
@@ -2292,7 +2292,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2292
2292
|
}
|
|
2293
2293
|
}
|
|
2294
2294
|
if (!fallbackReader) return null;
|
|
2295
|
-
const memory = await this.readQmdResultMemory(
|
|
2295
|
+
const memory = await this.readQmdResultMemory(path8, fallbackReader, namespaces);
|
|
2296
2296
|
return memory ? memory.frontmatter : null;
|
|
2297
2297
|
}
|
|
2298
2298
|
},
|
|
@@ -3016,6 +3016,295 @@ var ContradictionLinkingCoordinator = class {
|
|
|
3016
3016
|
}
|
|
3017
3017
|
};
|
|
3018
3018
|
|
|
3019
|
+
// src/orchestration/graph-recall-coordinator.ts
|
|
3020
|
+
import { createHash as createHash2 } from "crypto";
|
|
3021
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
3022
|
+
import path5 from "path";
|
|
3023
|
+
function mergeGraphExpandedResults(primary, expanded) {
|
|
3024
|
+
const mergedByPath = /* @__PURE__ */ new Map();
|
|
3025
|
+
for (const item of [...primary, ...expanded]) {
|
|
3026
|
+
const prev = mergedByPath.get(item.path);
|
|
3027
|
+
if (!prev) {
|
|
3028
|
+
mergedByPath.set(item.path, item);
|
|
3029
|
+
continue;
|
|
3030
|
+
}
|
|
3031
|
+
const better = item.score > prev.score ? item : prev;
|
|
3032
|
+
const snippet = prev.snippet || item.snippet;
|
|
3033
|
+
mergedByPath.set(item.path, { ...better, snippet });
|
|
3034
|
+
}
|
|
3035
|
+
return Array.from(mergedByPath.values());
|
|
3036
|
+
}
|
|
3037
|
+
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
3038
|
+
const absolutePath = path5.isAbsolute(candidatePath) ? candidatePath : path5.resolve(storageDir, candidatePath);
|
|
3039
|
+
const rel = path5.relative(storageDir, absolutePath);
|
|
3040
|
+
if (!rel || rel === ".") return null;
|
|
3041
|
+
if (rel.startsWith("..")) return null;
|
|
3042
|
+
return rel.split(path5.sep).join("/");
|
|
3043
|
+
}
|
|
3044
|
+
function normalizeGraphActivationScore(score) {
|
|
3045
|
+
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
3046
|
+
return bounded / (1 + bounded);
|
|
3047
|
+
}
|
|
3048
|
+
function blendGraphExpandedRecallScore(options) {
|
|
3049
|
+
const graphNorm = normalizeGraphActivationScore(options.graphActivationScore);
|
|
3050
|
+
const seedScore = Number.isFinite(options.seedRecallScore) ? Math.min(1, Math.max(0, options.seedRecallScore)) : 0;
|
|
3051
|
+
const weight = Math.min(1, Math.max(0, options.activationWeight));
|
|
3052
|
+
const rawMin = Math.min(1, Math.max(0, options.blendMin));
|
|
3053
|
+
const rawMax = Math.min(1, Math.max(0, options.blendMax));
|
|
3054
|
+
const minBound = Math.min(rawMin, rawMax);
|
|
3055
|
+
const maxBound = Math.max(rawMin, rawMax);
|
|
3056
|
+
const blended = graphNorm * weight + seedScore * (1 - weight);
|
|
3057
|
+
return Math.max(minBound, Math.min(maxBound, blended));
|
|
3058
|
+
}
|
|
3059
|
+
var GraphRecallCoordinator = class {
|
|
3060
|
+
getConfig;
|
|
3061
|
+
getStorage;
|
|
3062
|
+
storageFor;
|
|
3063
|
+
graphIndexFor;
|
|
3064
|
+
namespaceFromPath;
|
|
3065
|
+
resolveColdQmdResultForRecall;
|
|
3066
|
+
storageForAbsoluteQmdResultPath;
|
|
3067
|
+
readQmdResultMemory;
|
|
3068
|
+
constructor(options) {
|
|
3069
|
+
this.getConfig = options.getConfig;
|
|
3070
|
+
this.getStorage = options.getStorage;
|
|
3071
|
+
this.storageFor = options.storageFor;
|
|
3072
|
+
this.graphIndexFor = options.graphIndexFor;
|
|
3073
|
+
this.namespaceFromPath = options.namespaceFromPath;
|
|
3074
|
+
this.resolveColdQmdResultForRecall = options.resolveColdQmdResultForRecall;
|
|
3075
|
+
this.storageForAbsoluteQmdResultPath = options.storageForAbsoluteQmdResultPath;
|
|
3076
|
+
this.readQmdResultMemory = options.readQmdResultMemory;
|
|
3077
|
+
}
|
|
3078
|
+
async expandResultsViaGraph(options) {
|
|
3079
|
+
const config = this.getConfig();
|
|
3080
|
+
const deadlineExpired = () => typeof options.deadlineAtMs === "number" && Date.now() >= options.deadlineAtMs;
|
|
3081
|
+
const byNamespace = /* @__PURE__ */ new Map();
|
|
3082
|
+
const addResultForNamespace = (namespace, result) => {
|
|
3083
|
+
const existing = byNamespace.get(namespace);
|
|
3084
|
+
if (existing) {
|
|
3085
|
+
existing.push(result);
|
|
3086
|
+
} else {
|
|
3087
|
+
byNamespace.set(namespace, [result]);
|
|
3088
|
+
}
|
|
3089
|
+
};
|
|
3090
|
+
const resolvedAmbiguousSeeds = /* @__PURE__ */ new Map();
|
|
3091
|
+
const resolveAmbiguousSeedOwner = async (result, parts) => {
|
|
3092
|
+
const cached = resolvedAmbiguousSeeds.get(result.path);
|
|
3093
|
+
if (cached !== void 0) return cached;
|
|
3094
|
+
if (deadlineExpired()) {
|
|
3095
|
+
resolvedAmbiguousSeeds.set(result.path, null);
|
|
3096
|
+
return null;
|
|
3097
|
+
}
|
|
3098
|
+
let resolvedPath = result.path;
|
|
3099
|
+
let resolvedResult = result;
|
|
3100
|
+
if (parts) {
|
|
3101
|
+
const resolvedCold = await this.resolveColdQmdResultForRecall(
|
|
3102
|
+
result,
|
|
3103
|
+
this.getStorage(),
|
|
3104
|
+
options.recallNamespaces
|
|
3105
|
+
);
|
|
3106
|
+
if (!resolvedCold || deadlineExpired()) {
|
|
3107
|
+
resolvedAmbiguousSeeds.set(result.path, null);
|
|
3108
|
+
return null;
|
|
3109
|
+
}
|
|
3110
|
+
resolvedPath = resolvedCold.result.path;
|
|
3111
|
+
resolvedResult = resolvedCold.result;
|
|
3112
|
+
}
|
|
3113
|
+
if (!path5.isAbsolute(resolvedPath)) {
|
|
3114
|
+
resolvedAmbiguousSeeds.set(result.path, null);
|
|
3115
|
+
return null;
|
|
3116
|
+
}
|
|
3117
|
+
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
3118
|
+
resolvedPath,
|
|
3119
|
+
this.getStorage(),
|
|
3120
|
+
options.recallNamespaces
|
|
3121
|
+
);
|
|
3122
|
+
const ownerNamespace = ownerStorage?.namespace ?? null;
|
|
3123
|
+
const resolved = ownerNamespace && options.recallNamespaces.includes(ownerNamespace) ? { namespace: ownerNamespace, result: resolvedResult } : null;
|
|
3124
|
+
resolvedAmbiguousSeeds.set(result.path, resolved);
|
|
3125
|
+
return resolved;
|
|
3126
|
+
};
|
|
3127
|
+
const coldCollection = config.qmdColdCollection ?? "openclaw-engram-cold";
|
|
3128
|
+
for (const result of options.memoryResults) {
|
|
3129
|
+
if (deadlineExpired()) break;
|
|
3130
|
+
const parts = qmdCollectionPathParts(result.path);
|
|
3131
|
+
if (parts?.collection === coldCollection) {
|
|
3132
|
+
const resolved = await resolveAmbiguousSeedOwner(result, parts);
|
|
3133
|
+
if (resolved) {
|
|
3134
|
+
addResultForNamespace(resolved.namespace, resolved.result);
|
|
3135
|
+
}
|
|
3136
|
+
continue;
|
|
3137
|
+
}
|
|
3138
|
+
if (path5.isAbsolute(result.path)) {
|
|
3139
|
+
const resolved = await resolveAmbiguousSeedOwner(result, null);
|
|
3140
|
+
if (resolved) {
|
|
3141
|
+
addResultForNamespace(resolved.namespace, resolved.result);
|
|
3142
|
+
}
|
|
3143
|
+
continue;
|
|
3144
|
+
}
|
|
3145
|
+
const ns = this.namespaceFromPath(result.path);
|
|
3146
|
+
if (!options.recallNamespaces.includes(ns)) continue;
|
|
3147
|
+
addResultForNamespace(ns, result);
|
|
3148
|
+
}
|
|
3149
|
+
const perNamespaceSeedCap = Math.max(3, options.recallResultLimit);
|
|
3150
|
+
const perNamespaceExpandedCap = Math.max(8, options.recallResultLimit * 2);
|
|
3151
|
+
const seedPaths = [];
|
|
3152
|
+
const seedResults = [];
|
|
3153
|
+
const expandedPaths = [];
|
|
3154
|
+
const expandedResults = [];
|
|
3155
|
+
for (const [namespace, nsResults] of byNamespace.entries()) {
|
|
3156
|
+
if (deadlineExpired()) break;
|
|
3157
|
+
const storage = await this.storageFor(namespace);
|
|
3158
|
+
const seedCandidates = nsResults.slice(0, perNamespaceSeedCap);
|
|
3159
|
+
seedResults.push(...seedCandidates);
|
|
3160
|
+
const seedRelativePaths = typeof options.deadlineAtMs === "number" ? await this.graphSeedPathsWithinDeadline(
|
|
3161
|
+
storage,
|
|
3162
|
+
seedCandidates,
|
|
3163
|
+
options.deadlineAtMs,
|
|
3164
|
+
[namespace]
|
|
3165
|
+
) : (await Promise.all(
|
|
3166
|
+
seedCandidates.map(
|
|
3167
|
+
(result) => this.graphSeedPathRelativeToStorage(storage, result, [
|
|
3168
|
+
namespace
|
|
3169
|
+
])
|
|
3170
|
+
)
|
|
3171
|
+
)).filter(
|
|
3172
|
+
(value) => typeof value === "string" && value.length > 0
|
|
3173
|
+
);
|
|
3174
|
+
if (deadlineExpired()) break;
|
|
3175
|
+
if (seedRelativePaths.length === 0) continue;
|
|
3176
|
+
const seedRecallScore = seedCandidates.reduce(
|
|
3177
|
+
(max, item) => Math.max(max, item.score),
|
|
3178
|
+
0
|
|
3179
|
+
);
|
|
3180
|
+
seedPaths.push(
|
|
3181
|
+
...seedRelativePaths.map((rel) => path5.join(storage.dir, rel))
|
|
3182
|
+
);
|
|
3183
|
+
const seedSet = new Set(seedRelativePaths);
|
|
3184
|
+
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
3185
|
+
seedRelativePaths,
|
|
3186
|
+
config.maxGraphTraversalSteps,
|
|
3187
|
+
{
|
|
3188
|
+
...options.includeLowConfidence === true ? { includeLowConfidence: true } : {},
|
|
3189
|
+
...typeof options.deadlineAtMs === "number" ? { deadlineAtMs: options.deadlineAtMs } : {}
|
|
3190
|
+
}
|
|
3191
|
+
);
|
|
3192
|
+
if (expanded.length === 0) continue;
|
|
3193
|
+
if (deadlineExpired()) break;
|
|
3194
|
+
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
3195
|
+
if (deadlineExpired()) break;
|
|
3196
|
+
if (seedSet.has(candidate.path)) continue;
|
|
3197
|
+
const memoryPath = path5.resolve(storage.dir, candidate.path);
|
|
3198
|
+
const memory = await storage.readMemoryByPath(memoryPath);
|
|
3199
|
+
if (deadlineExpired()) break;
|
|
3200
|
+
if (!memory) continue;
|
|
3201
|
+
if (/(?:^|[\\/])artifacts(?:[\\/]|$)/i.test(memory.path)) continue;
|
|
3202
|
+
if (memory.frontmatter.status && memory.frontmatter.status !== "active")
|
|
3203
|
+
continue;
|
|
3204
|
+
const snippet = memory.content.slice(0, 400);
|
|
3205
|
+
const score = blendGraphExpandedRecallScore({
|
|
3206
|
+
graphActivationScore: candidate.score,
|
|
3207
|
+
seedRecallScore,
|
|
3208
|
+
activationWeight: config.graphExpansionActivationWeight,
|
|
3209
|
+
blendMin: config.graphExpansionBlendMin,
|
|
3210
|
+
blendMax: config.graphExpansionBlendMax
|
|
3211
|
+
});
|
|
3212
|
+
expandedResults.push({
|
|
3213
|
+
docid: memory.frontmatter.id,
|
|
3214
|
+
path: memory.path,
|
|
3215
|
+
snippet,
|
|
3216
|
+
score
|
|
3217
|
+
});
|
|
3218
|
+
expandedPaths.push({
|
|
3219
|
+
path: memory.path,
|
|
3220
|
+
score,
|
|
3221
|
+
namespace,
|
|
3222
|
+
seed: path5.resolve(storage.dir, candidate.seed),
|
|
3223
|
+
hopDepth: candidate.hopDepth,
|
|
3224
|
+
decayedWeight: candidate.decayedWeight,
|
|
3225
|
+
graphType: candidate.graphType,
|
|
3226
|
+
// Issue #681 PR 3/3 — surface the per-edge confidence used for
|
|
3227
|
+
// PageRank weighting / floor pruning so downstream observability
|
|
3228
|
+
// (recall_xray, memory_graph_explain) can attribute ranking and
|
|
3229
|
+
// pruning decisions to specific edges.
|
|
3230
|
+
edgeConfidence: candidate.edgeConfidence
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
return {
|
|
3235
|
+
merged: mergeGraphExpandedResults(options.memoryResults, expandedResults),
|
|
3236
|
+
seedPaths,
|
|
3237
|
+
expandedPaths,
|
|
3238
|
+
seedResults
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
async recordLastGraphRecallSnapshot(options) {
|
|
3242
|
+
try {
|
|
3243
|
+
const snapshotPath = path5.join(
|
|
3244
|
+
options.storage.dir,
|
|
3245
|
+
"state",
|
|
3246
|
+
"last_graph_recall.json"
|
|
3247
|
+
);
|
|
3248
|
+
await mkdir2(path5.dirname(snapshotPath), { recursive: true });
|
|
3249
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3250
|
+
const totalSeedCount = options.seedPaths.length;
|
|
3251
|
+
const totalExpandedCount = options.expandedPaths.length;
|
|
3252
|
+
const seeds = options.seedPaths.slice(0, 64);
|
|
3253
|
+
const expanded = clampGraphRecallExpandedEntries(
|
|
3254
|
+
options.expandedPaths,
|
|
3255
|
+
64
|
|
3256
|
+
);
|
|
3257
|
+
const payload = {
|
|
3258
|
+
recordedAt: now,
|
|
3259
|
+
mode: options.recallMode,
|
|
3260
|
+
queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
|
|
3261
|
+
queryLength: options.prompt.length,
|
|
3262
|
+
namespaces: options.recallNamespaces,
|
|
3263
|
+
seedCount: totalSeedCount,
|
|
3264
|
+
expandedCount: totalExpandedCount,
|
|
3265
|
+
seeds,
|
|
3266
|
+
expanded,
|
|
3267
|
+
status: options.status,
|
|
3268
|
+
reason: options.reason,
|
|
3269
|
+
shadowMode: options.shadowMode === true,
|
|
3270
|
+
queryIntent: options.queryIntent,
|
|
3271
|
+
seedResults: (options.seedResults ?? []).slice(0, 64),
|
|
3272
|
+
finalResults: (options.finalResults ?? []).slice(0, 64),
|
|
3273
|
+
shadowComparison: options.shadowComparison
|
|
3274
|
+
};
|
|
3275
|
+
await writeFile2(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
3276
|
+
} catch (err) {
|
|
3277
|
+
log.debug(`last graph recall write failed: ${err}`);
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
|
|
3281
|
+
const parts = qmdCollectionPathParts(result.path);
|
|
3282
|
+
if (parts) {
|
|
3283
|
+
const memory = await this.readQmdResultMemory(
|
|
3284
|
+
result.path,
|
|
3285
|
+
storage,
|
|
3286
|
+
recallNamespaces
|
|
3287
|
+
);
|
|
3288
|
+
return memory ? graphPathRelativeToStorage(storage.dir, memory.path) : null;
|
|
3289
|
+
}
|
|
3290
|
+
return graphPathRelativeToStorage(storage.dir, result.path);
|
|
3291
|
+
}
|
|
3292
|
+
async graphSeedPathsWithinDeadline(storage, results, deadlineAtMs, recallNamespaces = []) {
|
|
3293
|
+
const resolved = [];
|
|
3294
|
+
for (const result of results) {
|
|
3295
|
+
if (Date.now() >= deadlineAtMs) break;
|
|
3296
|
+
const seedPath = await this.graphSeedPathRelativeToStorage(
|
|
3297
|
+
storage,
|
|
3298
|
+
result,
|
|
3299
|
+
recallNamespaces
|
|
3300
|
+
);
|
|
3301
|
+
if (Date.now() >= deadlineAtMs) break;
|
|
3302
|
+
if (seedPath) resolved.push(seedPath);
|
|
3303
|
+
}
|
|
3304
|
+
return resolved;
|
|
3305
|
+
}
|
|
3306
|
+
};
|
|
3307
|
+
|
|
3019
3308
|
// src/maintenance/pattern-reinforcement.ts
|
|
3020
3309
|
function patternReinforcementKey(content) {
|
|
3021
3310
|
return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
|
|
@@ -3348,8 +3637,8 @@ function generateResolverDocument(taxonomy) {
|
|
|
3348
3637
|
}
|
|
3349
3638
|
|
|
3350
3639
|
// src/taxonomy/taxonomy-loader.ts
|
|
3351
|
-
import { readFile, mkdir as
|
|
3352
|
-
import
|
|
3640
|
+
import { readFile, mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
3641
|
+
import path6 from "path";
|
|
3353
3642
|
var TAXONOMY_DIR = ".taxonomy";
|
|
3354
3643
|
var TAXONOMY_FILE = "taxonomy.json";
|
|
3355
3644
|
var MAX_SLUG_LENGTH = 32;
|
|
@@ -3447,7 +3736,7 @@ function validateTaxonomy(taxonomy) {
|
|
|
3447
3736
|
}
|
|
3448
3737
|
}
|
|
3449
3738
|
async function loadTaxonomy(memoryDir) {
|
|
3450
|
-
const taxonomyPath =
|
|
3739
|
+
const taxonomyPath = path6.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
3451
3740
|
let raw;
|
|
3452
3741
|
try {
|
|
3453
3742
|
raw = await readFile(taxonomyPath, "utf-8");
|
|
@@ -3497,16 +3786,16 @@ async function loadTaxonomy(memoryDir) {
|
|
|
3497
3786
|
}
|
|
3498
3787
|
async function saveTaxonomy(memoryDir, taxonomy) {
|
|
3499
3788
|
validateTaxonomy(taxonomy);
|
|
3500
|
-
const dir =
|
|
3501
|
-
await
|
|
3502
|
-
const filePath =
|
|
3503
|
-
await
|
|
3789
|
+
const dir = path6.join(memoryDir, TAXONOMY_DIR);
|
|
3790
|
+
await mkdir3(dir, { recursive: true });
|
|
3791
|
+
const filePath = path6.join(dir, TAXONOMY_FILE);
|
|
3792
|
+
await writeFile3(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
|
|
3504
3793
|
}
|
|
3505
3794
|
function getTaxonomyDir(memoryDir) {
|
|
3506
|
-
return
|
|
3795
|
+
return path6.join(memoryDir, TAXONOMY_DIR);
|
|
3507
3796
|
}
|
|
3508
3797
|
function getTaxonomyFilePath(memoryDir) {
|
|
3509
|
-
return
|
|
3798
|
+
return path6.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
3510
3799
|
}
|
|
3511
3800
|
|
|
3512
3801
|
// src/wearables/registry.ts
|
|
@@ -4516,11 +4805,11 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
|
|
|
4516
4805
|
return await Promise.race([checkedPromise, timeoutPromise]);
|
|
4517
4806
|
}
|
|
4518
4807
|
function defaultWorkspaceDir() {
|
|
4519
|
-
return
|
|
4808
|
+
return path7.join(os2.homedir(), ".openclaw", "workspace");
|
|
4520
4809
|
}
|
|
4521
4810
|
function sanitizeSessionKeyForFilename(sessionKey) {
|
|
4522
4811
|
const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4523
|
-
const hash =
|
|
4812
|
+
const hash = createHash3("sha256").update(sessionKey).digest("hex").slice(0, 12);
|
|
4524
4813
|
return `${readable}-${hash}`;
|
|
4525
4814
|
}
|
|
4526
4815
|
function latestSourceValidAtFromTurns(turns) {
|
|
@@ -4778,42 +5067,6 @@ function computeQmdHybridFetchLimit(recallFetchLimit, artifactsEnabled, maxArtif
|
|
|
4778
5067
|
const artifactHeadroom = Math.max(20, Math.max(0, maxArtifactRecall) * 8);
|
|
4779
5068
|
return Math.min(400, cappedRecallLimit + artifactHeadroom);
|
|
4780
5069
|
}
|
|
4781
|
-
function mergeGraphExpandedResults(primary, expanded) {
|
|
4782
|
-
const mergedByPath = /* @__PURE__ */ new Map();
|
|
4783
|
-
for (const item of [...primary, ...expanded]) {
|
|
4784
|
-
const prev = mergedByPath.get(item.path);
|
|
4785
|
-
if (!prev) {
|
|
4786
|
-
mergedByPath.set(item.path, item);
|
|
4787
|
-
continue;
|
|
4788
|
-
}
|
|
4789
|
-
const better = item.score > prev.score ? item : prev;
|
|
4790
|
-
const snippet = prev.snippet || item.snippet;
|
|
4791
|
-
mergedByPath.set(item.path, { ...better, snippet });
|
|
4792
|
-
}
|
|
4793
|
-
return Array.from(mergedByPath.values());
|
|
4794
|
-
}
|
|
4795
|
-
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
4796
|
-
const absolutePath = path6.isAbsolute(candidatePath) ? candidatePath : path6.resolve(storageDir, candidatePath);
|
|
4797
|
-
const rel = path6.relative(storageDir, absolutePath);
|
|
4798
|
-
if (!rel || rel === ".") return null;
|
|
4799
|
-
if (rel.startsWith("..")) return null;
|
|
4800
|
-
return rel.split(path6.sep).join("/");
|
|
4801
|
-
}
|
|
4802
|
-
function normalizeGraphActivationScore(score) {
|
|
4803
|
-
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
4804
|
-
return bounded / (1 + bounded);
|
|
4805
|
-
}
|
|
4806
|
-
function blendGraphExpandedRecallScore(options) {
|
|
4807
|
-
const graphNorm = normalizeGraphActivationScore(options.graphActivationScore);
|
|
4808
|
-
const seedScore = Number.isFinite(options.seedRecallScore) ? Math.min(1, Math.max(0, options.seedRecallScore)) : 0;
|
|
4809
|
-
const weight = Math.min(1, Math.max(0, options.activationWeight));
|
|
4810
|
-
const rawMin = Math.min(1, Math.max(0, options.blendMin));
|
|
4811
|
-
const rawMax = Math.min(1, Math.max(0, options.blendMax));
|
|
4812
|
-
const minBound = Math.min(rawMin, rawMax);
|
|
4813
|
-
const maxBound = Math.max(rawMin, rawMax);
|
|
4814
|
-
const blended = graphNorm * weight + seedScore * (1 - weight);
|
|
4815
|
-
return Math.max(minBound, Math.min(maxBound, blended));
|
|
4816
|
-
}
|
|
4817
5070
|
function summarizeGraphShadowComparison(baseline, merged, topN) {
|
|
4818
5071
|
const limit = Math.max(0, Math.floor(topN));
|
|
4819
5072
|
const baselineTop = limit > 0 ? baseline.slice(0, limit) : [];
|
|
@@ -4942,7 +5195,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
|
|
|
4942
5195
|
for (const mem of allMemsForGraph ?? []) {
|
|
4943
5196
|
const id = mem.frontmatter.id;
|
|
4944
5197
|
if (!id) continue;
|
|
4945
|
-
pathById.set(id,
|
|
5198
|
+
pathById.set(id, path7.relative(storageDir, mem.path));
|
|
4946
5199
|
}
|
|
4947
5200
|
return pathById;
|
|
4948
5201
|
}
|
|
@@ -4950,7 +5203,7 @@ function appendMemoryToGraphContext(options) {
|
|
|
4950
5203
|
if (!Array.isArray(options.allMemsForGraph)) return;
|
|
4951
5204
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
4952
5205
|
options.allMemsForGraph.push({
|
|
4953
|
-
path:
|
|
5206
|
+
path: path7.join(options.storageDir, options.memoryRelPath),
|
|
4954
5207
|
content: options.content,
|
|
4955
5208
|
frontmatter: {
|
|
4956
5209
|
id: options.memoryId,
|
|
@@ -4970,16 +5223,16 @@ function resolvePersistedMemoryRelativePath(options) {
|
|
|
4970
5223
|
const persisted = options.pathById.get(options.memoryId);
|
|
4971
5224
|
if (persisted) return persisted;
|
|
4972
5225
|
if (options.category === "correction") {
|
|
4973
|
-
return
|
|
5226
|
+
return path7.join("corrections", `${options.memoryId}.md`);
|
|
4974
5227
|
}
|
|
4975
5228
|
const subtree = categoryDirName(options.category);
|
|
4976
5229
|
const idParts = options.memoryId.split("-");
|
|
4977
5230
|
const maybeTimestamp = Number(idParts[1]);
|
|
4978
5231
|
if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
|
|
4979
5232
|
const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
|
|
4980
|
-
return
|
|
5233
|
+
return path7.join(subtree, day, `${options.memoryId}.md`);
|
|
4981
5234
|
}
|
|
4982
|
-
return
|
|
5235
|
+
return path7.join(subtree, `${options.memoryId}.md`);
|
|
4983
5236
|
}
|
|
4984
5237
|
var Orchestrator = class _Orchestrator {
|
|
4985
5238
|
storage;
|
|
@@ -5144,6 +5397,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5144
5397
|
recallSectionCoordinator;
|
|
5145
5398
|
qmdResultResolver;
|
|
5146
5399
|
contradictionLinkingCoordinator;
|
|
5400
|
+
graphRecallCoordinator;
|
|
5147
5401
|
heartbeatObserverChains = /* @__PURE__ */ new Map();
|
|
5148
5402
|
recentExtractionFingerprints = /* @__PURE__ */ new Map();
|
|
5149
5403
|
consolidationObservers = /* @__PURE__ */ new Set();
|
|
@@ -5436,7 +5690,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5436
5690
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
5437
5691
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
5438
5692
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
5439
|
-
const resolvedStorageDir =
|
|
5693
|
+
const resolvedStorageDir = path7.resolve(storageDir);
|
|
5440
5694
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
5441
5695
|
if (!hints) {
|
|
5442
5696
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -5447,21 +5701,21 @@ var Orchestrator = class _Orchestrator {
|
|
|
5447
5701
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
5448
5702
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
5449
5703
|
if (!ns) return false;
|
|
5450
|
-
const resolvedStorageDir =
|
|
5451
|
-
const resolvedMemoryDir =
|
|
5704
|
+
const resolvedStorageDir = path7.resolve(storageDir);
|
|
5705
|
+
const resolvedMemoryDir = path7.resolve(this.config.memoryDir);
|
|
5452
5706
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
5453
5707
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
5454
|
-
const resolvedNamespacesDir =
|
|
5708
|
+
const resolvedNamespacesDir = path7.join(resolvedMemoryDir, "namespaces");
|
|
5455
5709
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
5456
|
-
const rawRoot =
|
|
5457
|
-
const tokenRoot =
|
|
5710
|
+
const rawRoot = path7.resolve(resolvedNamespacesDir, ns);
|
|
5711
|
+
const tokenRoot = path7.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
5458
5712
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
5459
5713
|
}
|
|
5460
5714
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
5461
|
-
if (resolvedStorageDir ===
|
|
5715
|
+
if (resolvedStorageDir === path7.resolve(this.config.memoryDir)) {
|
|
5462
5716
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
5463
5717
|
}
|
|
5464
|
-
const leaf =
|
|
5718
|
+
const leaf = path7.basename(resolvedStorageDir);
|
|
5465
5719
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
5466
5720
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
5467
5721
|
if (record.namespace === leaf) return 1;
|
|
@@ -5489,7 +5743,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5489
5743
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
5490
5744
|
if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
|
|
5491
5745
|
this.namespaceStorageDirHintsLoaded = true;
|
|
5492
|
-
const catalogPath =
|
|
5746
|
+
const catalogPath = path7.join(this.config.memoryDir, "state", "namespaces.jsonl");
|
|
5493
5747
|
if (!existsSync(catalogPath)) return;
|
|
5494
5748
|
let body;
|
|
5495
5749
|
try {
|
|
@@ -5526,7 +5780,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5526
5780
|
if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
5527
5781
|
continue;
|
|
5528
5782
|
}
|
|
5529
|
-
const resolvedStorageDir =
|
|
5783
|
+
const resolvedStorageDir = path7.resolve(record.storageDir);
|
|
5530
5784
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
5531
5785
|
preferredByStorageDir.set(
|
|
5532
5786
|
resolvedStorageDir,
|
|
@@ -5790,7 +6044,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5790
6044
|
this.config = config;
|
|
5791
6045
|
this.profiler = new ProfilingCollector({
|
|
5792
6046
|
enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
|
|
5793
|
-
storageDir: config.profilingStorageDir ||
|
|
6047
|
+
storageDir: config.profilingStorageDir || path7.join(config.memoryDir, "profiling"),
|
|
5794
6048
|
maxTraces: config.profilingMaxTraces
|
|
5795
6049
|
});
|
|
5796
6050
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -5860,7 +6114,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5860
6114
|
this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
|
|
5861
6115
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
5862
6116
|
this.transcript = new TranscriptManager(config);
|
|
5863
|
-
this.conversationIndexDir =
|
|
6117
|
+
this.conversationIndexDir = path7.join(
|
|
5864
6118
|
config.memoryDir,
|
|
5865
6119
|
"conversation-index",
|
|
5866
6120
|
"chunks"
|
|
@@ -5890,6 +6144,16 @@ var Orchestrator = class _Orchestrator {
|
|
|
5890
6144
|
getExtraction: () => this.extraction
|
|
5891
6145
|
});
|
|
5892
6146
|
this.modelRegistry = new ModelRegistry(config.memoryDir);
|
|
6147
|
+
this.graphRecallCoordinator = new GraphRecallCoordinator({
|
|
6148
|
+
getConfig: () => this.config,
|
|
6149
|
+
getStorage: () => this.storage,
|
|
6150
|
+
storageFor: (namespace) => this.storageRouter.storageFor(namespace),
|
|
6151
|
+
graphIndexFor: (storage) => this.graphIndexFor(storage),
|
|
6152
|
+
namespaceFromPath: (p) => this.namespaceFromPath(p),
|
|
6153
|
+
resolveColdQmdResultForRecall: (result, fallbackStorage, recallNamespaces) => this.resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces),
|
|
6154
|
+
storageForAbsoluteQmdResultPath: (resultPath, fallbackStorage, recallNamespaces) => this.storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces),
|
|
6155
|
+
readQmdResultMemory: (resultPath, fallbackStorage, recallNamespaces) => this.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces)
|
|
6156
|
+
});
|
|
5893
6157
|
this.relevance = new RelevanceStore(config.memoryDir);
|
|
5894
6158
|
this.negatives = new NegativeExampleStore(config.memoryDir);
|
|
5895
6159
|
this.lastRecall = new LastRecallStore(config.memoryDir);
|
|
@@ -5986,7 +6250,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5986
6250
|
saveContentHashIndexes: () => this.saveContentHashIndexes()
|
|
5987
6251
|
});
|
|
5988
6252
|
this.threading = new ThreadingManager(
|
|
5989
|
-
|
|
6253
|
+
path7.join(config.memoryDir, "threads"),
|
|
5990
6254
|
config.threadingGapMinutes
|
|
5991
6255
|
);
|
|
5992
6256
|
const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
|
|
@@ -6066,7 +6330,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
6066
6330
|
utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
|
|
6067
6331
|
utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
|
|
6068
6332
|
};
|
|
6069
|
-
return
|
|
6333
|
+
return createHash3("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
|
|
6070
6334
|
}
|
|
6071
6335
|
effectiveLifecycleThresholds() {
|
|
6072
6336
|
const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
|
|
@@ -6309,7 +6573,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
6309
6573
|
const files = await readdir2(wsDir).catch(() => []);
|
|
6310
6574
|
for (const f of files) {
|
|
6311
6575
|
if (!f.startsWith(".compaction-reset-signal-")) continue;
|
|
6312
|
-
const fp =
|
|
6576
|
+
const fp = path7.join(wsDir, f);
|
|
6313
6577
|
const s = await stat(fp).catch(() => null);
|
|
6314
6578
|
if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
|
|
6315
6579
|
await unlink(fp).catch(() => {
|
|
@@ -6818,15 +7082,15 @@ ${doc.content}` : doc.content,
|
|
|
6818
7082
|
this.lastFileHygieneRunAtMs = now;
|
|
6819
7083
|
if (hygiene.rotateEnabled) {
|
|
6820
7084
|
for (const rel of hygiene.rotatePaths) {
|
|
6821
|
-
const abs =
|
|
7085
|
+
const abs = path7.isAbsolute(rel) ? rel : path7.join(this.config.workspaceDir, rel);
|
|
6822
7086
|
try {
|
|
6823
7087
|
const raw = await readFile2(abs, "utf-8");
|
|
6824
7088
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
6825
|
-
const archiveDir =
|
|
7089
|
+
const archiveDir = path7.join(
|
|
6826
7090
|
this.config.workspaceDir,
|
|
6827
7091
|
hygiene.archiveDir
|
|
6828
7092
|
);
|
|
6829
|
-
const base =
|
|
7093
|
+
const base = path7.basename(abs);
|
|
6830
7094
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
6831
7095
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
6832
7096
|
filePath: abs,
|
|
@@ -6834,7 +7098,7 @@ ${doc.content}` : doc.content,
|
|
|
6834
7098
|
archivePrefix: prefix,
|
|
6835
7099
|
keepTailChars: hygiene.rotateKeepTailChars
|
|
6836
7100
|
});
|
|
6837
|
-
await
|
|
7101
|
+
await writeFile4(abs, newContent, "utf-8");
|
|
6838
7102
|
}
|
|
6839
7103
|
} catch {
|
|
6840
7104
|
}
|
|
@@ -6851,8 +7115,8 @@ ${doc.content}` : doc.content,
|
|
|
6851
7115
|
log.warn(w.message);
|
|
6852
7116
|
}
|
|
6853
7117
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
6854
|
-
const fp =
|
|
6855
|
-
await
|
|
7118
|
+
const fp = path7.join(this.config.memoryDir, hygiene.warningsLogPath);
|
|
7119
|
+
await mkdir4(path7.dirname(fp), { recursive: true });
|
|
6856
7120
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
6857
7121
|
const block = `
|
|
6858
7122
|
|
|
@@ -6865,7 +7129,7 @@ ${doc.content}` : doc.content,
|
|
|
6865
7129
|
} catch {
|
|
6866
7130
|
existing = "# Engram File Hygiene Warnings\n";
|
|
6867
7131
|
}
|
|
6868
|
-
await
|
|
7132
|
+
await writeFile4(fp, existing + block, "utf-8");
|
|
6869
7133
|
}
|
|
6870
7134
|
}
|
|
6871
7135
|
}
|
|
@@ -6991,7 +7255,7 @@ ${doc.content}` : doc.content,
|
|
|
6991
7255
|
for (const categoryDir of RECALL_FALLBACK_DIRS) {
|
|
6992
7256
|
if (memoryRootReal === null) break;
|
|
6993
7257
|
for (const date of datesToScan) {
|
|
6994
|
-
const dateDir =
|
|
7258
|
+
const dateDir = path7.join(storage.dir, categoryDir, date);
|
|
6995
7259
|
try {
|
|
6996
7260
|
const dirStat = await lstat(dateDir);
|
|
6997
7261
|
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
|
|
@@ -7000,7 +7264,7 @@ ${doc.content}` : doc.content,
|
|
|
7000
7264
|
for (const entry of entries) {
|
|
7001
7265
|
if (entry.isSymbolicLink()) continue;
|
|
7002
7266
|
if (!entry.name.endsWith(".md")) continue;
|
|
7003
|
-
const fullPath =
|
|
7267
|
+
const fullPath = path7.join(dateDir, entry.name);
|
|
7004
7268
|
try {
|
|
7005
7269
|
assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
|
|
7006
7270
|
const raw = await readFile2(fullPath, "utf-8");
|
|
@@ -7022,7 +7286,7 @@ ${doc.content}` : doc.content,
|
|
|
7022
7286
|
facts.push({
|
|
7023
7287
|
path: fullPath,
|
|
7024
7288
|
frontmatter: {
|
|
7025
|
-
id: fm.id ||
|
|
7289
|
+
id: fm.id || path7.basename(entry.name, ".md"),
|
|
7026
7290
|
category: fm.category || "fact",
|
|
7027
7291
|
created,
|
|
7028
7292
|
updated: fm.updated || created,
|
|
@@ -7045,13 +7309,13 @@ ${doc.content}` : doc.content,
|
|
|
7045
7309
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
7046
7310
|
});
|
|
7047
7311
|
const hourlySummaries = [];
|
|
7048
|
-
const hourlyBaseDir =
|
|
7312
|
+
const hourlyBaseDir = path7.join(storage.dir, "summaries", "hourly");
|
|
7049
7313
|
try {
|
|
7050
7314
|
const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
|
|
7051
7315
|
for (const sk of sessionKeys) {
|
|
7052
7316
|
if (!sk.isDirectory()) continue;
|
|
7053
7317
|
for (const date of datesToScan) {
|
|
7054
|
-
const summaryFile =
|
|
7318
|
+
const summaryFile = path7.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
7055
7319
|
try {
|
|
7056
7320
|
const raw = await readFile2(summaryFile, "utf-8");
|
|
7057
7321
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
@@ -7155,7 +7419,7 @@ ${doc.content}` : doc.content,
|
|
|
7155
7419
|
}
|
|
7156
7420
|
async getLastGraphRecallSnapshot(namespace) {
|
|
7157
7421
|
const storage = await this.getStorage(namespace);
|
|
7158
|
-
const snapshotPath =
|
|
7422
|
+
const snapshotPath = path7.join(
|
|
7159
7423
|
storage.dir,
|
|
7160
7424
|
"state",
|
|
7161
7425
|
"last_graph_recall.json"
|
|
@@ -7194,7 +7458,7 @@ ${doc.content}` : doc.content,
|
|
|
7194
7458
|
}
|
|
7195
7459
|
async getLastIntentSnapshot(namespace) {
|
|
7196
7460
|
const storage = await this.getStorage(namespace);
|
|
7197
|
-
const snapshotPath =
|
|
7461
|
+
const snapshotPath = path7.join(storage.dir, "state", "last_intent.json");
|
|
7198
7462
|
try {
|
|
7199
7463
|
const raw = await readFile2(snapshotPath, "utf-8");
|
|
7200
7464
|
const parsed = JSON.parse(raw);
|
|
@@ -7227,7 +7491,7 @@ ${doc.content}` : doc.content,
|
|
|
7227
7491
|
}
|
|
7228
7492
|
async getLastQmdRecallSnapshot(namespace) {
|
|
7229
7493
|
const storage = await this.getStorage(namespace);
|
|
7230
|
-
const snapshotPath =
|
|
7494
|
+
const snapshotPath = path7.join(
|
|
7231
7495
|
storage.dir,
|
|
7232
7496
|
"state",
|
|
7233
7497
|
"last_qmd_recall.json"
|
|
@@ -7929,7 +8193,7 @@ ${doc.content}` : doc.content,
|
|
|
7929
8193
|
if (!options.onDebugSnapshot) return;
|
|
7930
8194
|
await options.onDebugSnapshot({
|
|
7931
8195
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7932
|
-
queryHash:
|
|
8196
|
+
queryHash: createHash3("sha256").update(prompt).digest("hex"),
|
|
7933
8197
|
queryLength: prompt.length,
|
|
7934
8198
|
collection: options.collection,
|
|
7935
8199
|
namespaces: options.recallNamespaces,
|
|
@@ -8077,216 +8341,26 @@ ${doc.content}` : doc.content,
|
|
|
8077
8341
|
await emitDebugSnapshot(capped, fetchLimit);
|
|
8078
8342
|
return capped;
|
|
8079
8343
|
}
|
|
8344
|
+
// Issue #1526 (seam 14): graph-recall expansion moved to
|
|
8345
|
+
// GraphRecallCoordinator. Thin delegation keeps the private API stable
|
|
8346
|
+
// for callers (recallInternal, cold-fallback pipeline) + tests.
|
|
8080
8347
|
async expandResultsViaGraph(options) {
|
|
8081
|
-
|
|
8082
|
-
const byNamespace = /* @__PURE__ */ new Map();
|
|
8083
|
-
const addResultForNamespace = (namespace, result) => {
|
|
8084
|
-
const existing = byNamespace.get(namespace);
|
|
8085
|
-
if (existing) {
|
|
8086
|
-
existing.push(result);
|
|
8087
|
-
} else {
|
|
8088
|
-
byNamespace.set(namespace, [result]);
|
|
8089
|
-
}
|
|
8090
|
-
};
|
|
8091
|
-
const resolvedAmbiguousSeeds = /* @__PURE__ */ new Map();
|
|
8092
|
-
const resolveAmbiguousSeedOwner = async (result, parts) => {
|
|
8093
|
-
const cached = resolvedAmbiguousSeeds.get(result.path);
|
|
8094
|
-
if (cached !== void 0) return cached;
|
|
8095
|
-
if (deadlineExpired()) {
|
|
8096
|
-
resolvedAmbiguousSeeds.set(result.path, null);
|
|
8097
|
-
return null;
|
|
8098
|
-
}
|
|
8099
|
-
let resolvedPath = result.path;
|
|
8100
|
-
let resolvedResult = result;
|
|
8101
|
-
if (parts) {
|
|
8102
|
-
const resolvedCold = await this.resolveColdQmdResultForRecall(
|
|
8103
|
-
result,
|
|
8104
|
-
this.storage,
|
|
8105
|
-
options.recallNamespaces
|
|
8106
|
-
);
|
|
8107
|
-
if (!resolvedCold || deadlineExpired()) {
|
|
8108
|
-
resolvedAmbiguousSeeds.set(result.path, null);
|
|
8109
|
-
return null;
|
|
8110
|
-
}
|
|
8111
|
-
resolvedPath = resolvedCold.result.path;
|
|
8112
|
-
resolvedResult = resolvedCold.result;
|
|
8113
|
-
}
|
|
8114
|
-
if (!path6.isAbsolute(resolvedPath)) {
|
|
8115
|
-
resolvedAmbiguousSeeds.set(result.path, null);
|
|
8116
|
-
return null;
|
|
8117
|
-
}
|
|
8118
|
-
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
8119
|
-
resolvedPath,
|
|
8120
|
-
this.storage,
|
|
8121
|
-
options.recallNamespaces
|
|
8122
|
-
);
|
|
8123
|
-
const ownerNamespace = ownerStorage?.namespace ?? null;
|
|
8124
|
-
const resolved = ownerNamespace && options.recallNamespaces.includes(ownerNamespace) ? { namespace: ownerNamespace, result: resolvedResult } : null;
|
|
8125
|
-
resolvedAmbiguousSeeds.set(result.path, resolved);
|
|
8126
|
-
return resolved;
|
|
8127
|
-
};
|
|
8128
|
-
const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
|
|
8129
|
-
for (const result of options.memoryResults) {
|
|
8130
|
-
if (deadlineExpired()) break;
|
|
8131
|
-
const parts = qmdCollectionPathParts(result.path);
|
|
8132
|
-
if (parts?.collection === coldCollection) {
|
|
8133
|
-
const resolved = await resolveAmbiguousSeedOwner(result, parts);
|
|
8134
|
-
if (resolved) {
|
|
8135
|
-
addResultForNamespace(resolved.namespace, resolved.result);
|
|
8136
|
-
}
|
|
8137
|
-
continue;
|
|
8138
|
-
}
|
|
8139
|
-
if (path6.isAbsolute(result.path)) {
|
|
8140
|
-
const resolved = await resolveAmbiguousSeedOwner(result, null);
|
|
8141
|
-
if (resolved) {
|
|
8142
|
-
addResultForNamespace(resolved.namespace, resolved.result);
|
|
8143
|
-
}
|
|
8144
|
-
continue;
|
|
8145
|
-
}
|
|
8146
|
-
const ns = this.namespaceFromPath(result.path);
|
|
8147
|
-
if (!options.recallNamespaces.includes(ns)) continue;
|
|
8148
|
-
addResultForNamespace(ns, result);
|
|
8149
|
-
}
|
|
8150
|
-
const perNamespaceSeedCap = Math.max(3, options.recallResultLimit);
|
|
8151
|
-
const perNamespaceExpandedCap = Math.max(8, options.recallResultLimit * 2);
|
|
8152
|
-
const seedPaths = [];
|
|
8153
|
-
const seedResults = [];
|
|
8154
|
-
const expandedPaths = [];
|
|
8155
|
-
const expandedResults = [];
|
|
8156
|
-
for (const [namespace, nsResults] of byNamespace.entries()) {
|
|
8157
|
-
if (deadlineExpired()) break;
|
|
8158
|
-
const storage = await this.storageRouter.storageFor(namespace);
|
|
8159
|
-
const seedCandidates = nsResults.slice(0, perNamespaceSeedCap);
|
|
8160
|
-
seedResults.push(...seedCandidates);
|
|
8161
|
-
const seedRelativePaths = typeof options.deadlineAtMs === "number" ? await this.graphSeedPathsWithinDeadline(
|
|
8162
|
-
storage,
|
|
8163
|
-
seedCandidates,
|
|
8164
|
-
options.deadlineAtMs,
|
|
8165
|
-
[namespace]
|
|
8166
|
-
) : (await Promise.all(
|
|
8167
|
-
seedCandidates.map(
|
|
8168
|
-
(result) => this.graphSeedPathRelativeToStorage(storage, result, [
|
|
8169
|
-
namespace
|
|
8170
|
-
])
|
|
8171
|
-
)
|
|
8172
|
-
)).filter(
|
|
8173
|
-
(value) => typeof value === "string" && value.length > 0
|
|
8174
|
-
);
|
|
8175
|
-
if (deadlineExpired()) break;
|
|
8176
|
-
if (seedRelativePaths.length === 0) continue;
|
|
8177
|
-
const seedRecallScore = seedCandidates.reduce(
|
|
8178
|
-
(max, item) => Math.max(max, item.score),
|
|
8179
|
-
0
|
|
8180
|
-
);
|
|
8181
|
-
seedPaths.push(
|
|
8182
|
-
...seedRelativePaths.map((rel) => path6.join(storage.dir, rel))
|
|
8183
|
-
);
|
|
8184
|
-
const seedSet = new Set(seedRelativePaths);
|
|
8185
|
-
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
8186
|
-
seedRelativePaths,
|
|
8187
|
-
this.config.maxGraphTraversalSteps,
|
|
8188
|
-
{
|
|
8189
|
-
...options.includeLowConfidence === true ? { includeLowConfidence: true } : {},
|
|
8190
|
-
...typeof options.deadlineAtMs === "number" ? { deadlineAtMs: options.deadlineAtMs } : {}
|
|
8191
|
-
}
|
|
8192
|
-
);
|
|
8193
|
-
if (expanded.length === 0) continue;
|
|
8194
|
-
if (deadlineExpired()) break;
|
|
8195
|
-
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
8196
|
-
if (deadlineExpired()) break;
|
|
8197
|
-
if (seedSet.has(candidate.path)) continue;
|
|
8198
|
-
const memoryPath = path6.resolve(storage.dir, candidate.path);
|
|
8199
|
-
const memory = await storage.readMemoryByPath(memoryPath);
|
|
8200
|
-
if (deadlineExpired()) break;
|
|
8201
|
-
if (!memory) continue;
|
|
8202
|
-
if (isArtifactMemoryPath(memory.path)) continue;
|
|
8203
|
-
if (memory.frontmatter.status && memory.frontmatter.status !== "active")
|
|
8204
|
-
continue;
|
|
8205
|
-
const snippet = memory.content.slice(0, 400);
|
|
8206
|
-
const score = blendGraphExpandedRecallScore({
|
|
8207
|
-
graphActivationScore: candidate.score,
|
|
8208
|
-
seedRecallScore,
|
|
8209
|
-
activationWeight: this.config.graphExpansionActivationWeight,
|
|
8210
|
-
blendMin: this.config.graphExpansionBlendMin,
|
|
8211
|
-
blendMax: this.config.graphExpansionBlendMax
|
|
8212
|
-
});
|
|
8213
|
-
expandedResults.push({
|
|
8214
|
-
docid: memory.frontmatter.id,
|
|
8215
|
-
path: memory.path,
|
|
8216
|
-
snippet,
|
|
8217
|
-
score
|
|
8218
|
-
});
|
|
8219
|
-
expandedPaths.push({
|
|
8220
|
-
path: memory.path,
|
|
8221
|
-
score,
|
|
8222
|
-
namespace,
|
|
8223
|
-
seed: path6.resolve(storage.dir, candidate.seed),
|
|
8224
|
-
hopDepth: candidate.hopDepth,
|
|
8225
|
-
decayedWeight: candidate.decayedWeight,
|
|
8226
|
-
graphType: candidate.graphType,
|
|
8227
|
-
// Issue #681 PR 3/3 — surface the per-edge confidence used for
|
|
8228
|
-
// PageRank weighting / floor pruning so downstream observability
|
|
8229
|
-
// (recall_xray, memory_graph_explain) can attribute ranking and
|
|
8230
|
-
// pruning decisions to specific edges.
|
|
8231
|
-
edgeConfidence: candidate.edgeConfidence
|
|
8232
|
-
});
|
|
8233
|
-
}
|
|
8234
|
-
}
|
|
8235
|
-
return {
|
|
8236
|
-
merged: mergeGraphExpandedResults(options.memoryResults, expandedResults),
|
|
8237
|
-
seedPaths,
|
|
8238
|
-
expandedPaths,
|
|
8239
|
-
seedResults
|
|
8240
|
-
};
|
|
8348
|
+
return this.graphRecallCoordinator.expandResultsViaGraph(options);
|
|
8241
8349
|
}
|
|
8350
|
+
// Issue #1526 (seam 14): graph-recall snapshot moved to
|
|
8351
|
+
// GraphRecallCoordinator. Thin delegation keeps the private API stable.
|
|
8242
8352
|
async recordLastGraphRecallSnapshot(options) {
|
|
8243
|
-
|
|
8244
|
-
const snapshotPath = path6.join(
|
|
8245
|
-
options.storage.dir,
|
|
8246
|
-
"state",
|
|
8247
|
-
"last_graph_recall.json"
|
|
8248
|
-
);
|
|
8249
|
-
await mkdir3(path6.dirname(snapshotPath), { recursive: true });
|
|
8250
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8251
|
-
const totalSeedCount = options.seedPaths.length;
|
|
8252
|
-
const totalExpandedCount = options.expandedPaths.length;
|
|
8253
|
-
const seeds = options.seedPaths.slice(0, 64);
|
|
8254
|
-
const expanded = clampGraphRecallExpandedEntries(
|
|
8255
|
-
options.expandedPaths,
|
|
8256
|
-
64
|
|
8257
|
-
);
|
|
8258
|
-
const payload = {
|
|
8259
|
-
recordedAt: now,
|
|
8260
|
-
mode: options.recallMode,
|
|
8261
|
-
queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
|
|
8262
|
-
queryLength: options.prompt.length,
|
|
8263
|
-
namespaces: options.recallNamespaces,
|
|
8264
|
-
seedCount: totalSeedCount,
|
|
8265
|
-
expandedCount: totalExpandedCount,
|
|
8266
|
-
seeds,
|
|
8267
|
-
expanded,
|
|
8268
|
-
status: options.status,
|
|
8269
|
-
reason: options.reason,
|
|
8270
|
-
shadowMode: options.shadowMode === true,
|
|
8271
|
-
queryIntent: options.queryIntent,
|
|
8272
|
-
seedResults: (options.seedResults ?? []).slice(0, 64),
|
|
8273
|
-
finalResults: (options.finalResults ?? []).slice(0, 64),
|
|
8274
|
-
shadowComparison: options.shadowComparison
|
|
8275
|
-
};
|
|
8276
|
-
await writeFile3(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
8277
|
-
} catch (err) {
|
|
8278
|
-
log.debug(`last graph recall write failed: ${err}`);
|
|
8279
|
-
}
|
|
8353
|
+
return this.graphRecallCoordinator.recordLastGraphRecallSnapshot(options);
|
|
8280
8354
|
}
|
|
8281
8355
|
async recordLastIntentSnapshot(options) {
|
|
8282
8356
|
try {
|
|
8283
|
-
const snapshotPath =
|
|
8357
|
+
const snapshotPath = path7.join(
|
|
8284
8358
|
options.storage.dir,
|
|
8285
8359
|
"state",
|
|
8286
8360
|
"last_intent.json"
|
|
8287
8361
|
);
|
|
8288
|
-
await
|
|
8289
|
-
await
|
|
8362
|
+
await mkdir4(path7.dirname(snapshotPath), { recursive: true });
|
|
8363
|
+
await writeFile4(
|
|
8290
8364
|
snapshotPath,
|
|
8291
8365
|
JSON.stringify(options.snapshot, null, 2),
|
|
8292
8366
|
"utf-8"
|
|
@@ -8297,13 +8371,13 @@ ${doc.content}` : doc.content,
|
|
|
8297
8371
|
}
|
|
8298
8372
|
async recordLastQmdRecallSnapshot(options) {
|
|
8299
8373
|
try {
|
|
8300
|
-
const snapshotPath =
|
|
8374
|
+
const snapshotPath = path7.join(
|
|
8301
8375
|
options.storage.dir,
|
|
8302
8376
|
"state",
|
|
8303
8377
|
"last_qmd_recall.json"
|
|
8304
8378
|
);
|
|
8305
|
-
await
|
|
8306
|
-
await
|
|
8379
|
+
await mkdir4(path7.dirname(snapshotPath), { recursive: true });
|
|
8380
|
+
await writeFile4(
|
|
8307
8381
|
snapshotPath,
|
|
8308
8382
|
JSON.stringify(options.snapshot, null, 2),
|
|
8309
8383
|
"utf-8"
|
|
@@ -8317,9 +8391,9 @@ ${doc.content}` : doc.content,
|
|
|
8317
8391
|
const stateDir = await this.resolveStateDirForNamespace(
|
|
8318
8392
|
options.namespace
|
|
8319
8393
|
);
|
|
8320
|
-
const snapshotPath =
|
|
8321
|
-
await
|
|
8322
|
-
await
|
|
8394
|
+
const snapshotPath = path7.join(stateDir, "last_intent.json");
|
|
8395
|
+
await mkdir4(path7.dirname(snapshotPath), { recursive: true });
|
|
8396
|
+
await writeFile4(
|
|
8323
8397
|
snapshotPath,
|
|
8324
8398
|
JSON.stringify(options.snapshot, null, 2),
|
|
8325
8399
|
"utf-8"
|
|
@@ -8330,12 +8404,12 @@ ${doc.content}` : doc.content,
|
|
|
8330
8404
|
}
|
|
8331
8405
|
async resolveStateDirForNamespace(namespace) {
|
|
8332
8406
|
if (!resolveNamespaceCapabilities(this.config).namespaces) {
|
|
8333
|
-
return
|
|
8407
|
+
return path7.join(this.config.memoryDir, "state");
|
|
8334
8408
|
}
|
|
8335
8409
|
if (namespace !== this.config.defaultNamespace) {
|
|
8336
|
-
return
|
|
8410
|
+
return path7.join(this.config.memoryDir, "namespaces", namespace, "state");
|
|
8337
8411
|
}
|
|
8338
|
-
const candidate =
|
|
8412
|
+
const candidate = path7.join(
|
|
8339
8413
|
this.config.memoryDir,
|
|
8340
8414
|
"namespaces",
|
|
8341
8415
|
this.config.defaultNamespace
|
|
@@ -8343,11 +8417,11 @@ ${doc.content}` : doc.content,
|
|
|
8343
8417
|
try {
|
|
8344
8418
|
const candidateStat = await stat(candidate);
|
|
8345
8419
|
if (candidateStat.isDirectory()) {
|
|
8346
|
-
return
|
|
8420
|
+
return path7.join(candidate, "state");
|
|
8347
8421
|
}
|
|
8348
8422
|
} catch {
|
|
8349
8423
|
}
|
|
8350
|
-
return
|
|
8424
|
+
return path7.join(this.config.memoryDir, "state");
|
|
8351
8425
|
}
|
|
8352
8426
|
buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
|
|
8353
8427
|
return results.slice(0, limit).map((result) => ({
|
|
@@ -8478,8 +8552,8 @@ ${doc.content}` : doc.content,
|
|
|
8478
8552
|
timings,
|
|
8479
8553
|
logger: log
|
|
8480
8554
|
});
|
|
8481
|
-
const promptHash =
|
|
8482
|
-
const traceId =
|
|
8555
|
+
const promptHash = createHash3("sha256").update(prompt).digest("hex");
|
|
8556
|
+
const traceId = createHash3("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
|
|
8483
8557
|
const sectionBuckets = /* @__PURE__ */ new Map();
|
|
8484
8558
|
const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
|
|
8485
8559
|
cronRecallPolicyEnabled: resolveRecallAuxiliaryCapabilities(this.config).cronRecallPolicy,
|
|
@@ -8488,7 +8562,7 @@ ${doc.content}` : doc.content,
|
|
|
8488
8562
|
cronConversationRecallMode: this.config.cronConversationRecallMode
|
|
8489
8563
|
});
|
|
8490
8564
|
const retrievalQuery = queryPolicy.retrievalQuery || prompt;
|
|
8491
|
-
const retrievalQueryHash =
|
|
8565
|
+
const retrievalQueryHash = createHash3("sha256").update(retrievalQuery).digest("hex");
|
|
8492
8566
|
const policyVersion = this.currentPolicyVersion();
|
|
8493
8567
|
let impressionRecorded = false;
|
|
8494
8568
|
let recallSource = "none";
|
|
@@ -8627,7 +8701,7 @@ ${doc.content}` : doc.content,
|
|
|
8627
8701
|
const graphExpandedResultPaths = /* @__PURE__ */ new Set();
|
|
8628
8702
|
const graphSourceLabelsForPath = (resultPath) => {
|
|
8629
8703
|
const labels = [];
|
|
8630
|
-
const normalizedPath = resultPath.split(
|
|
8704
|
+
const normalizedPath = resultPath.split(path7.sep).join("/");
|
|
8631
8705
|
const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
|
|
8632
8706
|
if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
|
|
8633
8707
|
if (graphExpandedResultPaths.has(resultPath))
|
|
@@ -8777,7 +8851,7 @@ ${doc.content}` : doc.content,
|
|
|
8777
8851
|
profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
|
|
8778
8852
|
);
|
|
8779
8853
|
const emptyProfileStorage = new Proxy(
|
|
8780
|
-
{ dir:
|
|
8854
|
+
{ dir: path7.join(this.config.memoryDir, ".empty-scope-profile") },
|
|
8781
8855
|
{
|
|
8782
8856
|
get(target, prop) {
|
|
8783
8857
|
if (prop in target) return target[prop];
|
|
@@ -10253,11 +10327,11 @@ ${formatted}`;
|
|
|
10253
10327
|
if (!resolveRecallAuxiliaryCapabilities(this.config).compactionReset) return null;
|
|
10254
10328
|
const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
|
|
10255
10329
|
const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
|
|
10256
|
-
const signalPath =
|
|
10330
|
+
const signalPath = path7.join(
|
|
10257
10331
|
workspaceDir,
|
|
10258
10332
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
10259
10333
|
);
|
|
10260
|
-
const bootPath =
|
|
10334
|
+
const bootPath = path7.join(workspaceDir, "BOOT.md");
|
|
10261
10335
|
try {
|
|
10262
10336
|
const signalStat = await stat(signalPath).catch(() => null);
|
|
10263
10337
|
if (!signalStat) return null;
|
|
@@ -12528,7 +12602,7 @@ _Context: ${topQuestion.context}_`
|
|
|
12528
12602
|
const shouldUseStableBatchKey = turns.some(
|
|
12529
12603
|
(turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
|
|
12530
12604
|
);
|
|
12531
|
-
const stableBatchFingerprint = shouldUseStableBatchKey ?
|
|
12605
|
+
const stableBatchFingerprint = shouldUseStableBatchKey ? createHash3("sha256").update(
|
|
12532
12606
|
turns.map(
|
|
12533
12607
|
(turn) => [
|
|
12534
12608
|
turn.role,
|
|
@@ -12778,7 +12852,7 @@ _Context: ${topQuestion.context}_`
|
|
|
12778
12852
|
buildExtractionFingerprint(turns, bufferKey) {
|
|
12779
12853
|
const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
|
|
12780
12854
|
if (!normalized) return null;
|
|
12781
|
-
return
|
|
12855
|
+
return createHash3("sha256").update(`${bufferKey}
|
|
12782
12856
|
${normalized}`).digest("hex");
|
|
12783
12857
|
}
|
|
12784
12858
|
shouldQueueExtraction(turns, options = {}) {
|
|
@@ -14859,7 +14933,7 @@ ${normalized}`).digest("hex");
|
|
|
14859
14933
|
const allMems = allMemsForGraph ?? [];
|
|
14860
14934
|
for (const m of allMems) {
|
|
14861
14935
|
if (m.frontmatter.entityRef === entityRef) {
|
|
14862
|
-
const rel =
|
|
14936
|
+
const rel = path7.relative(storage.dir, m.path);
|
|
14863
14937
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
14864
14938
|
}
|
|
14865
14939
|
}
|
|
@@ -15183,7 +15257,7 @@ ${normalized}`).digest("hex");
|
|
|
15183
15257
|
}
|
|
15184
15258
|
if (resolveConsolidationCapabilities(this.config).semanticConsolidation) {
|
|
15185
15259
|
try {
|
|
15186
|
-
const stateFilePath =
|
|
15260
|
+
const stateFilePath = path7.join(
|
|
15187
15261
|
this.config.memoryDir,
|
|
15188
15262
|
"state",
|
|
15189
15263
|
"semantic-consolidation-last-run.json"
|
|
@@ -15231,9 +15305,9 @@ ${normalized}`).digest("hex");
|
|
|
15231
15305
|
);
|
|
15232
15306
|
}
|
|
15233
15307
|
if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
|
|
15234
|
-
const stateDir =
|
|
15235
|
-
await
|
|
15236
|
-
await
|
|
15308
|
+
const stateDir = path7.join(this.config.memoryDir, "state");
|
|
15309
|
+
await mkdir4(stateDir, { recursive: true });
|
|
15310
|
+
await writeFile4(
|
|
15237
15311
|
stateFilePath,
|
|
15238
15312
|
JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
15239
15313
|
"utf-8"
|
|
@@ -15627,12 +15701,12 @@ ${reflectionsContent.trim()}
|
|
|
15627
15701
|
*/
|
|
15628
15702
|
semanticDedupScopeFor(targetStorage) {
|
|
15629
15703
|
if (!resolveNamespaceCapabilities(this.config).namespaces) return {};
|
|
15630
|
-
const memoryDir =
|
|
15631
|
-
const storageDir =
|
|
15704
|
+
const memoryDir = path7.resolve(this.config.memoryDir);
|
|
15705
|
+
const storageDir = path7.resolve(targetStorage.dir);
|
|
15632
15706
|
if (storageDir === memoryDir) {
|
|
15633
15707
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
15634
15708
|
}
|
|
15635
|
-
let rel =
|
|
15709
|
+
let rel = path7.relative(memoryDir, storageDir);
|
|
15636
15710
|
if (!rel || rel.startsWith("..")) {
|
|
15637
15711
|
log.debug(
|
|
15638
15712
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -15651,7 +15725,7 @@ ${reflectionsContent.trim()}
|
|
|
15651
15725
|
if (hits.length === 0) return [];
|
|
15652
15726
|
const results = [];
|
|
15653
15727
|
for (const hit of hits) {
|
|
15654
|
-
const fullPath =
|
|
15728
|
+
const fullPath = path7.isAbsolute(hit.path) ? hit.path : path7.join(this.config.memoryDir, hit.path);
|
|
15655
15729
|
const memory = await this.storage.readMemoryByPath(fullPath);
|
|
15656
15730
|
if (!memory) continue;
|
|
15657
15731
|
results.push({
|
|
@@ -15848,7 +15922,7 @@ ${reflectionsContent.trim()}
|
|
|
15848
15922
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
15849
15923
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
15850
15924
|
if (!storageDir) continue;
|
|
15851
|
-
const recallRoot =
|
|
15925
|
+
const recallRoot = path7.resolve(storageDir);
|
|
15852
15926
|
if (seenRecallRoots.has(recallRoot)) continue;
|
|
15853
15927
|
seenRecallRoots.add(recallRoot);
|
|
15854
15928
|
recallRoots.push(recallRoot);
|
|
@@ -15872,8 +15946,8 @@ ${reflectionsContent.trim()}
|
|
|
15872
15946
|
if (resolvedCold) scopedResults.push(resolvedCold.result);
|
|
15873
15947
|
continue;
|
|
15874
15948
|
}
|
|
15875
|
-
if (
|
|
15876
|
-
const resolvedPath =
|
|
15949
|
+
if (path7.isAbsolute(result.path)) {
|
|
15950
|
+
const resolvedPath = path7.resolve(result.path);
|
|
15877
15951
|
if (recallRoots.some(
|
|
15878
15952
|
(recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
|
|
15879
15953
|
)) {
|
|
@@ -16574,32 +16648,6 @@ ${reflectionsContent.trim()}
|
|
|
16574
16648
|
namespaceScope
|
|
16575
16649
|
);
|
|
16576
16650
|
}
|
|
16577
|
-
async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
|
|
16578
|
-
const parts = qmdCollectionPathParts(result.path);
|
|
16579
|
-
if (parts) {
|
|
16580
|
-
const memory = await this.readQmdResultMemory(
|
|
16581
|
-
result.path,
|
|
16582
|
-
storage,
|
|
16583
|
-
recallNamespaces
|
|
16584
|
-
);
|
|
16585
|
-
return memory ? graphPathRelativeToStorage(storage.dir, memory.path) : null;
|
|
16586
|
-
}
|
|
16587
|
-
return graphPathRelativeToStorage(storage.dir, result.path);
|
|
16588
|
-
}
|
|
16589
|
-
async graphSeedPathsWithinDeadline(storage, results, deadlineAtMs, recallNamespaces = []) {
|
|
16590
|
-
const resolved = [];
|
|
16591
|
-
for (const result of results) {
|
|
16592
|
-
if (Date.now() >= deadlineAtMs) break;
|
|
16593
|
-
const seedPath = await this.graphSeedPathRelativeToStorage(
|
|
16594
|
-
storage,
|
|
16595
|
-
result,
|
|
16596
|
-
recallNamespaces
|
|
16597
|
-
);
|
|
16598
|
-
if (Date.now() >= deadlineAtMs) break;
|
|
16599
|
-
if (seedPath) resolved.push(seedPath);
|
|
16600
|
-
}
|
|
16601
|
-
return resolved;
|
|
16602
|
-
}
|
|
16603
16651
|
namespaceFromPath(p) {
|
|
16604
16652
|
if (!resolveNamespaceCapabilities(this.config).namespaces) return this.config.defaultNamespace;
|
|
16605
16653
|
const parts = qmdCollectionPathParts(p);
|
|
@@ -16659,6 +16707,9 @@ export {
|
|
|
16659
16707
|
buildProcedureRecallSection,
|
|
16660
16708
|
hasIdentityRecoveryIntent,
|
|
16661
16709
|
resolveEffectiveIdentityInjectionMode,
|
|
16710
|
+
mergeGraphExpandedResults,
|
|
16711
|
+
graphPathRelativeToStorage,
|
|
16712
|
+
blendGraphExpandedRecallScore,
|
|
16662
16713
|
decideSemanticDedup,
|
|
16663
16714
|
DEFAULT_TAXONOMY,
|
|
16664
16715
|
generateResolverDocument,
|
|
@@ -16690,9 +16741,6 @@ export {
|
|
|
16690
16741
|
resolveRecallModeDecisionAsync,
|
|
16691
16742
|
computeArtifactCandidateFetchLimit,
|
|
16692
16743
|
computeQmdHybridFetchLimit,
|
|
16693
|
-
mergeGraphExpandedResults,
|
|
16694
|
-
graphPathRelativeToStorage,
|
|
16695
|
-
blendGraphExpandedRecallScore,
|
|
16696
16744
|
summarizeGraphShadowComparison,
|
|
16697
16745
|
mergeArtifactRecallCandidates,
|
|
16698
16746
|
resolveRecentThreadMemoryPaths,
|
|
@@ -16701,4 +16749,4 @@ export {
|
|
|
16701
16749
|
resolvePersistedMemoryRelativePath,
|
|
16702
16750
|
Orchestrator
|
|
16703
16751
|
};
|
|
16704
|
-
//# sourceMappingURL=chunk-
|
|
16752
|
+
//# sourceMappingURL=chunk-SODQQCAZ.js.map
|