@remnic/plugin-openclaw 1.0.35 → 1.0.37
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 +38 -4
- package/dist/{calibration-Z5WWNV7U.js → calibration-RKL2LRW4.js} +4 -4
- package/dist/{capsule-cli-GBM3WPAM.js → capsule-cli-EHZPMXBC.js} +2 -2
- package/dist/{capsule-crypto-K3IRTKRH.js → capsule-crypto-JS67OSWM.js} +3 -3
- package/dist/capsule-export-DX53CPIT.js +17 -0
- package/dist/capsule-import-4OXCPHOT.js +16 -0
- package/dist/{capsule-merge-IWOQ34KL.js → capsule-merge-25AUN33Q.js} +7 -7
- package/dist/{causal-chain-WYN5QOPS.js → causal-chain-BVTOWZKC.js} +4 -4
- package/dist/{causal-consolidation-C64NNE4T.js → causal-consolidation-DRPM2KOE.js} +13 -10
- package/dist/{causal-retrieval-NZHQOZOE.js → causal-retrieval-XAP6QKHZ.js} +4 -5
- package/dist/{causal-trajectory-graph-VBPE2WPM.js → causal-trajectory-graph-ZWQWZ7N5.js} +2 -2
- package/dist/{chunk-5LE4HTVL.js → chunk-25J4PXDH.js} +0 -18
- package/dist/{chunk-6UFI73TJ.js → chunk-3IKMUNW5.js} +53 -46
- package/dist/{chunk-EXDYWXMB.js → chunk-4XDQ3KEC.js} +1 -2
- package/dist/{chunk-JGIUTWZS.js → chunk-6O3H3DPL.js} +2 -2
- package/dist/{chunk-UTDLHBBV.js → chunk-BLC3RQNV.js} +5 -555
- package/dist/{chunk-4G2XCSD2.js → chunk-BZ4EYURA.js} +0 -5
- package/dist/{chunk-L6I4MQKO.js → chunk-CEL5ZLKP.js} +6 -6
- package/dist/{chunk-TDRJVMUP.js → chunk-EH4AXGRO.js} +0 -12
- package/dist/{chunk-EYCLXMIV.js → chunk-G3CZA4SD.js} +9 -427
- package/dist/chunk-I2KLQ2HA.js +22 -0
- package/dist/chunk-IO5WWY6A.js +156 -0
- package/dist/{contradiction-scan-A5NOTZPN.js → chunk-JC3FCKYL.js} +189 -86
- package/dist/{chunk-SVSQAG6M.js → chunk-KC7KSQR4.js} +47 -28
- package/dist/chunk-LZCGPRHS.js +228 -0
- package/dist/{chunk-CXM7EBAO.js → chunk-MXFJXUHC.js} +1 -1
- package/dist/{chunk-VRGUUHBV.js → chunk-NUWDSTP7.js} +1 -1
- package/dist/{chunk-4LYQ4ONL.js → chunk-QCCP4RU5.js} +8 -3
- package/dist/{chunk-6OJAU466.js → chunk-QMUQV5NP.js} +0 -1
- package/dist/{chunk-LLUROTZJ.js → chunk-QQXJODFL.js} +9 -9
- package/dist/{chunk-6F6EKSVP.js → chunk-QXXEF7VI.js} +1 -1
- package/dist/{chunk-CMKR6NDQ.js → chunk-SEGEX7W4.js} +73 -241
- package/dist/{chunk-VFULKFKI.js → chunk-SWOYEQN2.js} +42 -17
- package/dist/chunk-TH5FF5SC.js +16 -0
- package/dist/{chunk-FGTYFLL5.js → chunk-TXOEHSVP.js} +29 -32
- package/dist/chunk-UZJ7EERS.js +272 -0
- package/dist/chunk-YJYZMLD5.js +360 -0
- package/dist/{chunk-NKVIN6RD.js → chunk-YKV4EFUI.js} +84 -2
- package/dist/{chunk-SSFTU6LP.js → chunk-ZS6VABML.js} +4 -4
- package/dist/{cipher-VHAFCG7Z.js → cipher-E23BHBSO.js} +1 -1
- package/dist/{consolidation-undo-5ZSX4MWO.js → consolidation-undo-FKJZCJHS.js} +2 -2
- package/dist/contradiction-review-WJRWNQ5N.js +29 -0
- package/dist/contradiction-scan-5X423QGT.js +12 -0
- package/dist/{dreams-ledger-3I52ISYR.js → dreams-ledger-KDX44I7R.js} +1 -1
- package/dist/{engine-47AKKYJ4.js → engine-5P774HTZ.js} +6 -6
- package/dist/{extraction-judge-telemetry-GHOTVYMP.js → extraction-judge-telemetry-O4ZVGLTU.js} +1 -1
- package/dist/{fallback-llm-45A755XP.js → fallback-llm-43UMEXNJ.js} +3 -3
- package/dist/{first-start-migration-I24M2JEE.js → first-start-migration-H2SAXAGR.js} +4 -4
- package/dist/{forget-NI4RBDPB.js → forget-ZECIDNL5.js} +1 -1
- package/dist/{fs-utils-PZRI2HDZ.js → fs-utils-OYXSZSVV.js} +12 -2
- package/dist/{graph-edge-decay-5CVKWBYH.js → graph-edge-decay-24ZKD5QL.js} +5 -5
- package/dist/index.js +7098 -84293
- package/dist/{kdf-H5B23ZM2.js → kdf-RXKIWHRU.js} +1 -1
- package/dist/legacy-hook-compat-QHHKF4GK.js +2 -0
- package/dist/{logger-TNOKCH7X.js → logger-XG7JKLPS.js} +1 -1
- package/dist/{memory-governance-QS7Z425Y.js → memory-governance-6K4M4YXD.js} +5 -5
- package/dist/{metadata-JAGIWHEA.js → metadata-WK2TRPYZ.js} +1 -1
- package/dist/{migrate-from-identity-anchor-7MMSPEUM.js → migrate-from-identity-anchor-SNDNKHZD.js} +1 -1
- package/dist/path-ZKO74XXC.js +7 -0
- package/dist/{peers-KRFXWRQ6.js → peers-W53WSDXG.js} +1 -1
- package/dist/{purge-XN2VSPZ2.js → purge-IKJISXEQ.js} +1 -1
- package/dist/resolution-BN35OXDS.js +11 -0
- package/dist/{secure-store-A4NGCNXV.js → secure-store-F75I54O5.js} +3 -3
- package/dist/{state-PVISYXRH.js → state-4ITLYMAU.js} +1 -1
- package/dist/{state-store-N6TFBFSP.js → state-store-ET3ADVY5.js} +3 -3
- package/dist/{storage-DDYQGLXA.js → storage-5EY6T7ON.js} +3 -3
- package/dist/{tier-stats-IZNW66NC.js → tier-stats-ZRQBV6G2.js} +4 -4
- package/dist/{trace-NJESSGH7.js → trace-IL2Y34EH.js} +1 -1
- package/dist/{tui-MGK2LYJY.js → tui-7KRDCMYK.js} +1 -1
- package/dist/{types-R4DO7AKM.js → types-MBUINTB2.js} +3 -3
- package/openclaw.plugin.json +164 -8
- package/package.json +9 -6
- package/scripts/faiss_index.py +816 -0
- package/scripts/faiss_requirements.txt +3 -0
- package/dist/capsule-export-IXVERCQG.js +0 -17
- package/dist/capsule-import-IA6VIOPQ.js +0 -16
- package/dist/chunk-3GUF7RQI.js +0 -559
- package/dist/chunk-7OQEPGQF.js +0 -533
- package/dist/chunk-DIZW6H5J.js +0 -136
- package/dist/chunk-FQRSVYY4.js +0 -110
- package/dist/chunk-GUSMRW4H.js +0 -12
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-WPINX4MF.js +0 -380
- package/dist/contradiction-review-SVGBS3V5.js +0 -21
- package/dist/legacy-hook-compat-XQ7FP6FV.js +0 -35
- package/dist/path-JIEGNWFL.js +0 -7
- package/dist/resolution-YITUVUTH.js +0 -100
|
@@ -1,29 +1,42 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-WPINX4MF.js";
|
|
2
|
+
isSafeRouteNamespace
|
|
3
|
+
} from "./chunk-TH5FF5SC.js";
|
|
5
4
|
import {
|
|
6
|
-
StorageManager
|
|
7
|
-
|
|
8
|
-
} from "./chunk-EYCLXMIV.js";
|
|
5
|
+
StorageManager
|
|
6
|
+
} from "./chunk-G3CZA4SD.js";
|
|
9
7
|
import {
|
|
10
8
|
log
|
|
11
9
|
} from "./chunk-UFU5GGGA.js";
|
|
12
10
|
import {
|
|
13
11
|
readEnvVar,
|
|
14
12
|
resolveHomeDir
|
|
15
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-EH4AXGRO.js";
|
|
16
14
|
|
|
17
15
|
// ../remnic-core/src/connectors/codex-materialize-runner.ts
|
|
18
|
-
import path2 from "path";
|
|
19
16
|
import { existsSync } from "fs";
|
|
20
17
|
|
|
18
|
+
// ../remnic-core/src/namespaces/path.ts
|
|
19
|
+
import path from "path";
|
|
20
|
+
function assertNamespacePathInsideRoot(root, candidate, namespace, label = "namespace path") {
|
|
21
|
+
const relative = path.relative(root, candidate);
|
|
22
|
+
if (relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`invalid ${label}: ${namespace}`);
|
|
26
|
+
}
|
|
27
|
+
function resolveNamespaceChildRoot(memoryDir, namespace, label = "namespace path") {
|
|
28
|
+
const namespaceRoot = path.resolve(memoryDir, "namespaces");
|
|
29
|
+
const candidate = path.resolve(namespaceRoot, namespace);
|
|
30
|
+
assertNamespacePathInsideRoot(namespaceRoot, candidate, namespace, label);
|
|
31
|
+
return candidate;
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
// ../remnic-core/src/connectors/codex-materialize.ts
|
|
22
35
|
import {
|
|
23
36
|
createHash
|
|
24
37
|
} from "crypto";
|
|
25
38
|
import fs from "fs";
|
|
26
|
-
import
|
|
39
|
+
import path2 from "path";
|
|
27
40
|
var MATERIALIZE_VERSION = 1;
|
|
28
41
|
var SENTINEL_FILE = ".remnic-managed";
|
|
29
42
|
var TMP_DIR = ".remnic-tmp";
|
|
@@ -34,12 +47,11 @@ function materializeForNamespace(namespace, options) {
|
|
|
34
47
|
warn: (msg) => log.warn(`[codex-materialize] ${msg}`),
|
|
35
48
|
debug: (msg) => log.debug(`[codex-materialize] ${msg}`)
|
|
36
49
|
};
|
|
37
|
-
const
|
|
38
|
-
const memoriesDir = path.join(codexHome, "memories");
|
|
50
|
+
const memoriesDir = resolveCodexMemoriesDir(options.codexHome);
|
|
39
51
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
40
52
|
const maxSummaryTokens = typeof options.maxSummaryTokens === "number" && options.maxSummaryTokens >= 0 ? options.maxSummaryTokens : 4500;
|
|
41
53
|
const rolloutRetentionDays = typeof options.rolloutRetentionDays === "number" && options.rolloutRetentionDays >= 0 ? options.rolloutRetentionDays : 30;
|
|
42
|
-
const sentinelPath =
|
|
54
|
+
const sentinelPath = path2.join(memoriesDir, SENTINEL_FILE);
|
|
43
55
|
const existingSentinel = readSentinel(sentinelPath);
|
|
44
56
|
if (!existingSentinel) {
|
|
45
57
|
if (fs.existsSync(memoriesDir)) {
|
|
@@ -117,10 +129,10 @@ function materializeForNamespace(namespace, options) {
|
|
|
117
129
|
});
|
|
118
130
|
if (existingSentinel.content_hash === hash) {
|
|
119
131
|
const requiredFiles = [
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
...rolloutFiles.map((r) =>
|
|
132
|
+
path2.join(memoriesDir, "memory_summary.md"),
|
|
133
|
+
path2.join(memoriesDir, "MEMORY.md"),
|
|
134
|
+
path2.join(memoriesDir, "raw_memories.md"),
|
|
135
|
+
...rolloutFiles.map((r) => path2.join(memoriesDir, ROLLOUT_SUBDIR, r.name))
|
|
124
136
|
];
|
|
125
137
|
const allPresent = requiredFiles.every((f) => fs.existsSync(f));
|
|
126
138
|
if (allPresent) {
|
|
@@ -140,14 +152,14 @@ function materializeForNamespace(namespace, options) {
|
|
|
140
152
|
);
|
|
141
153
|
}
|
|
142
154
|
const runTag = `${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
143
|
-
const tmpDir =
|
|
155
|
+
const tmpDir = path2.join(memoriesDir, `${TMP_DIR}-${runTag}`);
|
|
144
156
|
const TMP_STALE_MS = 60 * 60 * 1e3;
|
|
145
157
|
const wallClockMs = Date.now();
|
|
146
158
|
try {
|
|
147
159
|
for (const entry of fs.readdirSync(memoriesDir, { withFileTypes: true })) {
|
|
148
160
|
if (!entry.isDirectory()) continue;
|
|
149
161
|
if (!entry.name.startsWith(TMP_DIR)) continue;
|
|
150
|
-
const stalePath =
|
|
162
|
+
const stalePath = path2.join(memoriesDir, entry.name);
|
|
151
163
|
try {
|
|
152
164
|
const stat = fs.statSync(stalePath);
|
|
153
165
|
if (wallClockMs - stat.mtimeMs < TMP_STALE_MS) continue;
|
|
@@ -158,24 +170,24 @@ function materializeForNamespace(namespace, options) {
|
|
|
158
170
|
} catch {
|
|
159
171
|
}
|
|
160
172
|
fs.mkdirSync(tmpDir, { recursive: true });
|
|
161
|
-
fs.mkdirSync(
|
|
173
|
+
fs.mkdirSync(path2.join(tmpDir, ROLLOUT_SUBDIR), { recursive: true });
|
|
162
174
|
const filesWritten = [];
|
|
163
|
-
fs.writeFileSync(
|
|
175
|
+
fs.writeFileSync(path2.join(tmpDir, "memory_summary.md"), memorySummary);
|
|
164
176
|
filesWritten.push("memory_summary.md");
|
|
165
|
-
fs.writeFileSync(
|
|
177
|
+
fs.writeFileSync(path2.join(tmpDir, "MEMORY.md"), memoryMd);
|
|
166
178
|
filesWritten.push("MEMORY.md");
|
|
167
|
-
fs.writeFileSync(
|
|
179
|
+
fs.writeFileSync(path2.join(tmpDir, "raw_memories.md"), rawMemories);
|
|
168
180
|
filesWritten.push("raw_memories.md");
|
|
169
181
|
for (const rollout of rolloutFiles) {
|
|
170
|
-
fs.writeFileSync(
|
|
171
|
-
filesWritten.push(
|
|
182
|
+
fs.writeFileSync(path2.join(tmpDir, ROLLOUT_SUBDIR, rollout.name), rollout.body);
|
|
183
|
+
filesWritten.push(path2.join(ROLLOUT_SUBDIR, rollout.name));
|
|
172
184
|
}
|
|
173
185
|
for (const rel of ["memory_summary.md", "MEMORY.md", "raw_memories.md"]) {
|
|
174
|
-
const src =
|
|
175
|
-
const dest =
|
|
186
|
+
const src = path2.join(tmpDir, rel);
|
|
187
|
+
const dest = path2.join(memoriesDir, rel);
|
|
176
188
|
fs.renameSync(src, dest);
|
|
177
189
|
}
|
|
178
|
-
const destRolloutsDir =
|
|
190
|
+
const destRolloutsDir = path2.join(memoriesDir, ROLLOUT_SUBDIR);
|
|
179
191
|
fs.mkdirSync(destRolloutsDir, { recursive: true });
|
|
180
192
|
if (rolloutsSupplied) {
|
|
181
193
|
const retainedRolloutNames = new Set(rolloutFiles.map((r) => r.name));
|
|
@@ -185,7 +197,7 @@ function materializeForNamespace(namespace, options) {
|
|
|
185
197
|
if (!entry.name.endsWith(".md")) continue;
|
|
186
198
|
if (retainedRolloutNames.has(entry.name)) continue;
|
|
187
199
|
try {
|
|
188
|
-
fs.unlinkSync(
|
|
200
|
+
fs.unlinkSync(path2.join(destRolloutsDir, entry.name));
|
|
189
201
|
} catch {
|
|
190
202
|
}
|
|
191
203
|
}
|
|
@@ -193,8 +205,8 @@ function materializeForNamespace(namespace, options) {
|
|
|
193
205
|
}
|
|
194
206
|
}
|
|
195
207
|
for (const rollout of rolloutFiles) {
|
|
196
|
-
const src =
|
|
197
|
-
const dest =
|
|
208
|
+
const src = path2.join(tmpDir, ROLLOUT_SUBDIR, rollout.name);
|
|
209
|
+
const dest = path2.join(destRolloutsDir, rollout.name);
|
|
198
210
|
fs.renameSync(src, dest);
|
|
199
211
|
}
|
|
200
212
|
const sentinel = {
|
|
@@ -419,7 +431,13 @@ function resolveCodexHome(override) {
|
|
|
419
431
|
if (override && override.trim().length > 0) return override;
|
|
420
432
|
const fromEnv = readEnvVar("CODEX_HOME");
|
|
421
433
|
if (fromEnv && fromEnv.trim().length > 0) return fromEnv;
|
|
422
|
-
return
|
|
434
|
+
return path2.join(resolveHomeDir(), ".codex");
|
|
435
|
+
}
|
|
436
|
+
function resolveCodexMemoriesDir(codexHome) {
|
|
437
|
+
return path2.join(resolveCodexHome(codexHome), "memories");
|
|
438
|
+
}
|
|
439
|
+
function hasCodexMaterializeSentinel(codexHome) {
|
|
440
|
+
return readSentinel(path2.join(resolveCodexMemoriesDir(codexHome), SENTINEL_FILE)) !== null;
|
|
423
441
|
}
|
|
424
442
|
function readSentinel(sentinelPath) {
|
|
425
443
|
if (!fs.existsSync(sentinelPath)) return null;
|
|
@@ -567,16 +585,19 @@ async function runCodexMaterialize(options) {
|
|
|
567
585
|
if (options.memories) {
|
|
568
586
|
memories = options.memories;
|
|
569
587
|
} else {
|
|
588
|
+
if (!hasCodexMaterializeSentinel(options.codexHome)) {
|
|
589
|
+
return materializeForNamespace(namespace, {
|
|
590
|
+
memories: [],
|
|
591
|
+
codexHome: options.codexHome,
|
|
592
|
+
maxSummaryTokens: cfg.codexMaterializeMaxSummaryTokens,
|
|
593
|
+
rolloutRetentionDays: cfg.codexMaterializeRolloutRetentionDays,
|
|
594
|
+
rolloutSummaries: options.rolloutSummaries,
|
|
595
|
+
now: options.now
|
|
596
|
+
});
|
|
597
|
+
}
|
|
570
598
|
const nsDir = resolveNamespaceDir(memoryDir, namespace, cfg);
|
|
571
599
|
const storage = new StorageManager(nsDir);
|
|
572
|
-
|
|
573
|
-
memories = await storage.readAllMemories();
|
|
574
|
-
} catch (error) {
|
|
575
|
-
log.warn(
|
|
576
|
-
`[codex-materialize] skipped \u2014 failed to read memories from ${nsDir}: ${error instanceof Error ? error.message : String(error)}`
|
|
577
|
-
);
|
|
578
|
-
return null;
|
|
579
|
-
}
|
|
600
|
+
memories = await storage.readAllMemories();
|
|
580
601
|
}
|
|
581
602
|
const result = materializeForNamespace(namespace, {
|
|
582
603
|
memories,
|
|
@@ -616,16 +637,22 @@ async function runPostConsolidationMaterialize(logPrefix, options) {
|
|
|
616
637
|
}
|
|
617
638
|
function resolveNamespace(override, cfg) {
|
|
618
639
|
const requested = (override ?? cfg.codexMaterializeNamespace ?? "auto").trim();
|
|
619
|
-
|
|
620
|
-
|
|
640
|
+
const defaultNamespace = (cfg.defaultNamespace ?? "").trim();
|
|
641
|
+
const namespace = requested.length === 0 || requested === "auto" ? defaultNamespace.length > 0 ? defaultNamespace : "default" : requested;
|
|
642
|
+
if (!isSafeRouteNamespace(namespace)) {
|
|
643
|
+
throw new Error(`invalid materialize namespace: ${namespace}`);
|
|
621
644
|
}
|
|
622
|
-
return
|
|
645
|
+
return namespace;
|
|
623
646
|
}
|
|
624
647
|
function resolveNamespaceDir(memoryDir, namespace, cfg) {
|
|
625
648
|
if (!cfg.namespacesEnabled) return memoryDir;
|
|
626
|
-
const
|
|
627
|
-
const
|
|
628
|
-
if (ns
|
|
649
|
+
const defaultNamespace = (cfg.defaultNamespace ?? "").trim();
|
|
650
|
+
const ns = (namespace || defaultNamespace || "default").trim();
|
|
651
|
+
if (!isSafeRouteNamespace(ns)) {
|
|
652
|
+
throw new Error(`invalid materialize namespace: ${ns}`);
|
|
653
|
+
}
|
|
654
|
+
const namespacedRoot = resolveNamespaceChildRoot(memoryDir, ns, "materialize namespace path");
|
|
655
|
+
if (ns === defaultNamespace) {
|
|
629
656
|
return existsSync(namespacedRoot) ? namespacedRoot : memoryDir;
|
|
630
657
|
}
|
|
631
658
|
return namespacedRoot;
|
|
@@ -853,190 +880,8 @@ ${ext.instructions}
|
|
|
853
880
|
}
|
|
854
881
|
return result;
|
|
855
882
|
}
|
|
856
|
-
function renderExtensionsFooter(extensions) {
|
|
857
|
-
if (extensions.length === 0) return "";
|
|
858
|
-
const names = extensions.map((ext) => ext.name).join(", ");
|
|
859
|
-
return `Active extensions: ${names}`;
|
|
860
|
-
}
|
|
861
883
|
|
|
862
884
|
// ../remnic-core/src/semantic-consolidation.ts
|
|
863
|
-
function findSimilarClusters(memories, config) {
|
|
864
|
-
const excluded = new Set(config.excludeCategories);
|
|
865
|
-
const byCategory = /* @__PURE__ */ new Map();
|
|
866
|
-
for (const m of memories) {
|
|
867
|
-
const cat = m.frontmatter.category;
|
|
868
|
-
if (excluded.has(cat)) continue;
|
|
869
|
-
if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
|
|
870
|
-
const list = byCategory.get(cat) ?? [];
|
|
871
|
-
list.push(m);
|
|
872
|
-
byCategory.set(cat, list);
|
|
873
|
-
}
|
|
874
|
-
const clusters = [];
|
|
875
|
-
let totalCandidates = 0;
|
|
876
|
-
for (const [category, mems] of byCategory) {
|
|
877
|
-
if (totalCandidates >= config.maxPerRun) break;
|
|
878
|
-
const tokenized = mems.map((m) => ({
|
|
879
|
-
memory: m,
|
|
880
|
-
tokens: new Set(normalizeRecallTokens(m.content, []))
|
|
881
|
-
}));
|
|
882
|
-
const clustered = /* @__PURE__ */ new Set();
|
|
883
|
-
for (let i = 0; i < tokenized.length && totalCandidates < config.maxPerRun; i++) {
|
|
884
|
-
if (clustered.has(tokenized[i].memory.frontmatter.id)) continue;
|
|
885
|
-
const cluster = [tokenized[i].memory];
|
|
886
|
-
let totalOverlap = 0;
|
|
887
|
-
let comparisons = 0;
|
|
888
|
-
for (let j = i + 1; j < tokenized.length; j++) {
|
|
889
|
-
if (clustered.has(tokenized[j].memory.frontmatter.id)) continue;
|
|
890
|
-
const aTokens = tokenized[i].tokens;
|
|
891
|
-
const bTokens = tokenized[j].tokens;
|
|
892
|
-
if (aTokens.size === 0 || bTokens.size === 0) continue;
|
|
893
|
-
const overlap = countRecallTokenOverlap(aTokens, [...bTokens].join(" "));
|
|
894
|
-
const maxTokens = Math.max(aTokens.size, bTokens.size);
|
|
895
|
-
const score = maxTokens > 0 ? overlap / maxTokens : 0;
|
|
896
|
-
if (score >= config.threshold) {
|
|
897
|
-
cluster.push(tokenized[j].memory);
|
|
898
|
-
totalOverlap += score;
|
|
899
|
-
comparisons++;
|
|
900
|
-
if (totalCandidates + cluster.length >= config.maxPerRun) break;
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
if (cluster.length >= config.minClusterSize) {
|
|
904
|
-
for (const m of cluster) clustered.add(m.frontmatter.id);
|
|
905
|
-
clusters.push({
|
|
906
|
-
category,
|
|
907
|
-
memories: cluster,
|
|
908
|
-
overlapScore: comparisons > 0 ? totalOverlap / comparisons : 0
|
|
909
|
-
});
|
|
910
|
-
totalCandidates += cluster.length;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
return clusters;
|
|
915
|
-
}
|
|
916
|
-
function buildConsolidationPrompt(cluster) {
|
|
917
|
-
const memoryTexts = cluster.memories.map(
|
|
918
|
-
(m, i) => `Memory ${i + 1} (${m.frontmatter.id}, created ${m.frontmatter.created}):
|
|
919
|
-
${m.content}`
|
|
920
|
-
).join("\n\n");
|
|
921
|
-
return `You are a memory consolidation system. The following ${cluster.memories.length} memories in the "${cluster.category}" category contain overlapping information.
|
|
922
|
-
|
|
923
|
-
Synthesize them into ONE canonical memory that:
|
|
924
|
-
1. Preserves ALL unique information from every source memory
|
|
925
|
-
2. Removes redundancy and repetition
|
|
926
|
-
3. Uses clear, concise language
|
|
927
|
-
4. Maintains the same category and tone
|
|
928
|
-
5. Does NOT add information that isn't in the sources
|
|
929
|
-
|
|
930
|
-
${memoryTexts}
|
|
931
|
-
|
|
932
|
-
Write ONLY the consolidated memory content (no metadata, no explanation, no preamble):`;
|
|
933
|
-
}
|
|
934
|
-
function parseConsolidationResponse(response) {
|
|
935
|
-
return response.trim();
|
|
936
|
-
}
|
|
937
|
-
function chooseConsolidationOperator(cluster) {
|
|
938
|
-
if (cluster.memories.length <= 1) return "update";
|
|
939
|
-
return "merge";
|
|
940
|
-
}
|
|
941
|
-
function buildOperatorAwareConsolidationPrompt(cluster) {
|
|
942
|
-
const memoryTexts = cluster.memories.map(
|
|
943
|
-
(m, i) => `Memory ${i + 1} (${m.frontmatter.id}, created ${m.frontmatter.created}):
|
|
944
|
-
${m.content}`
|
|
945
|
-
).join("\n\n");
|
|
946
|
-
return `You are a memory consolidation system. The following ${cluster.memories.length} memories in the "${cluster.category}" category contain overlapping information.
|
|
947
|
-
|
|
948
|
-
Pick exactly ONE consolidation operator for this cluster and return a JSON object.
|
|
949
|
-
|
|
950
|
-
Operator vocabulary:
|
|
951
|
-
- "merge" \u2014 multiple distinct source memories overlap and should be collapsed into one canonical memory (most common).
|
|
952
|
-
- "update" \u2014 one source memory carries a stale value that a newer source supersedes within the same logical fact.
|
|
953
|
-
- "split" \u2014 a single logical source really encodes multiple distinct facts that should be separated (rare; if you pick split, still emit ONE canonical body \u2014 the write path will chunk it later).
|
|
954
|
-
|
|
955
|
-
Output JSON ONLY, no prose before or after. The "operator" key MUST be set to exactly one of the three strings "merge", "update", or "split" \u2014 never a pipe-separated placeholder like "merge|update|split". Example shape:
|
|
956
|
-
{
|
|
957
|
-
"operator": "merge",
|
|
958
|
-
"output": "<the canonical memory text>"
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
The "output" value must:
|
|
962
|
-
1. Preserve ALL unique information from every source memory
|
|
963
|
-
2. Remove redundancy and repetition
|
|
964
|
-
3. Use clear, concise language
|
|
965
|
-
4. Match the "${cluster.category}" category and tone
|
|
966
|
-
5. NOT add information that isn't in the sources
|
|
967
|
-
|
|
968
|
-
${memoryTexts}
|
|
969
|
-
|
|
970
|
-
Return ONLY the JSON object:`;
|
|
971
|
-
}
|
|
972
|
-
function parseOperatorAwareConsolidationResponse(response, cluster) {
|
|
973
|
-
const fallback = {
|
|
974
|
-
operator: chooseConsolidationOperator(cluster),
|
|
975
|
-
output: response.trim()
|
|
976
|
-
};
|
|
977
|
-
const trimmed = response.trim();
|
|
978
|
-
if (trimmed.length === 0) return fallback;
|
|
979
|
-
const fenced = /^```(?:json)?\s*([\s\S]*?)```\s*$/u.exec(trimmed);
|
|
980
|
-
const payload = fenced ? fenced[1].trim() : trimmed;
|
|
981
|
-
const parsed = findLastJsonObjectWithOperator(payload);
|
|
982
|
-
if (parsed === void 0) return fallback;
|
|
983
|
-
if (typeof parsed !== "object" || parsed === null) return fallback;
|
|
984
|
-
const obj = parsed;
|
|
985
|
-
const rawOperator = typeof obj.operator === "string" ? obj.operator.trim().toLowerCase() : "";
|
|
986
|
-
const rawOutput = typeof obj.output === "string" ? obj.output : "";
|
|
987
|
-
const operator = isSemanticConsolidationLlmOperator(rawOperator) ? rawOperator : chooseConsolidationOperator(cluster);
|
|
988
|
-
const output = rawOutput.trim().length > 0 ? rawOutput.trim() : response.trim();
|
|
989
|
-
return { operator, output };
|
|
990
|
-
}
|
|
991
|
-
function findLastJsonObjectWithOperator(text) {
|
|
992
|
-
let searchFrom = 0;
|
|
993
|
-
let last = void 0;
|
|
994
|
-
while (searchFrom < text.length) {
|
|
995
|
-
const start = text.indexOf("{", searchFrom);
|
|
996
|
-
if (start < 0) return last;
|
|
997
|
-
let depth = 0;
|
|
998
|
-
let inString = false;
|
|
999
|
-
let escape = false;
|
|
1000
|
-
let closed = false;
|
|
1001
|
-
let endIdx = -1;
|
|
1002
|
-
for (let i = start; i < text.length; i++) {
|
|
1003
|
-
const ch = text[i];
|
|
1004
|
-
if (inString) {
|
|
1005
|
-
if (escape) {
|
|
1006
|
-
escape = false;
|
|
1007
|
-
} else if (ch === "\\") {
|
|
1008
|
-
escape = true;
|
|
1009
|
-
} else if (ch === '"') {
|
|
1010
|
-
inString = false;
|
|
1011
|
-
}
|
|
1012
|
-
continue;
|
|
1013
|
-
}
|
|
1014
|
-
if (ch === '"') {
|
|
1015
|
-
inString = true;
|
|
1016
|
-
} else if (ch === "{") {
|
|
1017
|
-
depth += 1;
|
|
1018
|
-
} else if (ch === "}") {
|
|
1019
|
-
depth -= 1;
|
|
1020
|
-
if (depth === 0) {
|
|
1021
|
-
closed = true;
|
|
1022
|
-
endIdx = i;
|
|
1023
|
-
break;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
if (!closed) return last;
|
|
1028
|
-
const slice = text.slice(start, endIdx + 1);
|
|
1029
|
-
try {
|
|
1030
|
-
const parsed = JSON.parse(slice);
|
|
1031
|
-
if (typeof parsed === "object" && parsed !== null && "operator" in parsed) {
|
|
1032
|
-
last = parsed;
|
|
1033
|
-
}
|
|
1034
|
-
} catch {
|
|
1035
|
-
}
|
|
1036
|
-
searchFrom = endIdx + 1;
|
|
1037
|
-
}
|
|
1038
|
-
return last;
|
|
1039
|
-
}
|
|
1040
885
|
async function buildExtensionsBlockForConsolidation(config) {
|
|
1041
886
|
if (!config.memoryExtensionsEnabled) return "";
|
|
1042
887
|
const root = resolveExtensionsRoot(config);
|
|
@@ -1044,21 +889,8 @@ async function buildExtensionsBlockForConsolidation(config) {
|
|
|
1044
889
|
if (extensions.length === 0) return "";
|
|
1045
890
|
return renderExtensionsBlock(extensions);
|
|
1046
891
|
}
|
|
1047
|
-
async function materializeAfterSemanticConsolidation(options) {
|
|
1048
|
-
return runPostConsolidationMaterialize("[semantic-consolidation]", options);
|
|
1049
|
-
}
|
|
1050
892
|
|
|
1051
893
|
export {
|
|
1052
|
-
discoverMemoryExtensions,
|
|
1053
|
-
resolveExtensionsRoot,
|
|
1054
|
-
renderExtensionsFooter,
|
|
1055
894
|
runPostConsolidationMaterialize,
|
|
1056
|
-
|
|
1057
|
-
buildConsolidationPrompt,
|
|
1058
|
-
parseConsolidationResponse,
|
|
1059
|
-
chooseConsolidationOperator,
|
|
1060
|
-
buildOperatorAwareConsolidationPrompt,
|
|
1061
|
-
parseOperatorAwareConsolidationResponse,
|
|
1062
|
-
buildExtensionsBlockForConsolidation,
|
|
1063
|
-
materializeAfterSemanticConsolidation
|
|
895
|
+
buildExtensionsBlockForConsolidation
|
|
1064
896
|
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
expandTildePath,
|
|
9
9
|
readEnvVar,
|
|
10
10
|
resolveHomeDir
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-EH4AXGRO.js";
|
|
12
12
|
|
|
13
13
|
// ../remnic-core/src/fallback-llm.ts
|
|
14
14
|
import path2 from "path";
|
|
@@ -66,6 +66,8 @@ var _resolverLoaded = false;
|
|
|
66
66
|
var _resolverNextRetryAt = 0;
|
|
67
67
|
var RESOLVER_RETRY_BACKOFF_MS = 6e4;
|
|
68
68
|
var resolvedCache = /* @__PURE__ */ new Map();
|
|
69
|
+
var cacheObjectIds = /* @__PURE__ */ new WeakMap();
|
|
70
|
+
var nextCacheObjectId = 1;
|
|
69
71
|
var NON_LITERAL_AUTH_MARKERS = /* @__PURE__ */ new Set([
|
|
70
72
|
"secretref-managed",
|
|
71
73
|
"lm-studio"
|
|
@@ -191,30 +193,51 @@ function resolveFromNamedEnvVar(marker) {
|
|
|
191
193
|
const value = readEnvVar(marker);
|
|
192
194
|
return value && value.trim().length > 0 ? value.trim() : void 0;
|
|
193
195
|
}
|
|
196
|
+
function cacheIdentity(value) {
|
|
197
|
+
if (value === null) return "null";
|
|
198
|
+
if (value === void 0) return "undefined";
|
|
199
|
+
if (typeof value === "string") return `string:${value}`;
|
|
200
|
+
if (typeof value === "number") return `number:${String(value)}`;
|
|
201
|
+
if (typeof value === "boolean") return `boolean:${String(value)}`;
|
|
202
|
+
if (typeof value === "bigint") return `bigint:${String(value)}`;
|
|
203
|
+
if (typeof value === "symbol" || typeof value === "function") return typeof value;
|
|
204
|
+
if (typeof value === "object") {
|
|
205
|
+
const existingId = cacheObjectIds.get(value);
|
|
206
|
+
if (existingId !== void 0) return `object:${existingId}`;
|
|
207
|
+
const newId = nextCacheObjectId++;
|
|
208
|
+
cacheObjectIds.set(value, newId);
|
|
209
|
+
return `object:${newId}`;
|
|
210
|
+
}
|
|
211
|
+
return String(value);
|
|
212
|
+
}
|
|
213
|
+
function providerSecretCacheKey(providerId, resolvedAgentDir, credentialValue, gatewayConfig) {
|
|
214
|
+
return [
|
|
215
|
+
`provider:${providerId}`,
|
|
216
|
+
`agentDir:${resolvedAgentDir}`,
|
|
217
|
+
`apiKey:${cacheIdentity(credentialValue)}`,
|
|
218
|
+
`cfg:${cacheIdentity(gatewayConfig)}`
|
|
219
|
+
].join(":");
|
|
220
|
+
}
|
|
194
221
|
async function resolveProviderCredential(providerId, credentialValue, gatewayConfig, agentDir) {
|
|
195
222
|
const resolvedAgentDir = path.resolve(
|
|
196
223
|
agentDir ?? path.join(os.homedir(), ".openclaw", "agents", "main", "agent")
|
|
197
224
|
);
|
|
198
|
-
const cacheKey = `provider:${providerId}:agentDir:${resolvedAgentDir}`;
|
|
199
|
-
if (resolvedCache.has(cacheKey)) {
|
|
200
|
-
return resolvedCache.get(cacheKey);
|
|
201
|
-
}
|
|
202
225
|
let resolved;
|
|
203
226
|
if (typeof credentialValue === "string" && credentialValue.trim().length > 0) {
|
|
204
227
|
const trimmedCredentialValue = credentialValue.trim();
|
|
205
228
|
if (isNonLiteralAuthMarker(trimmedCredentialValue)) {
|
|
206
229
|
const markerEnvValue = resolveFromNamedEnvVar(trimmedCredentialValue);
|
|
207
230
|
if (markerEnvValue) {
|
|
208
|
-
|
|
209
|
-
resolvedCache.set(cacheKey, resolved);
|
|
210
|
-
return resolved;
|
|
231
|
+
return markerEnvValue;
|
|
211
232
|
}
|
|
212
233
|
} else {
|
|
213
|
-
|
|
214
|
-
resolvedCache.set(cacheKey, resolved);
|
|
215
|
-
return resolved;
|
|
234
|
+
return trimmedCredentialValue;
|
|
216
235
|
}
|
|
217
236
|
}
|
|
237
|
+
const cacheKey = providerSecretCacheKey(providerId, resolvedAgentDir, credentialValue, gatewayConfig);
|
|
238
|
+
if (resolvedCache.has(cacheKey)) {
|
|
239
|
+
return resolvedCache.get(cacheKey);
|
|
240
|
+
}
|
|
218
241
|
const resolver = await getGatewayResolver();
|
|
219
242
|
if (resolver) {
|
|
220
243
|
try {
|
|
@@ -402,7 +425,7 @@ var FallbackLlmClient = class {
|
|
|
402
425
|
* When agentId is provided, uses that agent persona's model chain instead of defaults.
|
|
403
426
|
*/
|
|
404
427
|
async chatCompletion(messages, options = {}) {
|
|
405
|
-
const models = this.getModelChain(options.agentId);
|
|
428
|
+
const models = this.getModelChain(options.agentId, options.model);
|
|
406
429
|
if (models.length === 0) {
|
|
407
430
|
log.warn("fallback LLM: no models configured in gateway");
|
|
408
431
|
return null;
|
|
@@ -513,7 +536,7 @@ var FallbackLlmClient = class {
|
|
|
513
536
|
* and uses that persona's model chain. Falls back to agents.defaults.model
|
|
514
537
|
* if agentId is not found or not provided.
|
|
515
538
|
*/
|
|
516
|
-
getModelChain(agentId) {
|
|
539
|
+
getModelChain(agentId, modelOverride) {
|
|
517
540
|
const chain = [];
|
|
518
541
|
const providers = this.gatewayConfig?.models?.providers ?? {};
|
|
519
542
|
let modelConfig;
|
|
@@ -534,8 +557,13 @@ var FallbackLlmClient = class {
|
|
|
534
557
|
modelConfig = this.gatewayConfig?.agents?.defaults?.model;
|
|
535
558
|
}
|
|
536
559
|
const modelStrings = [];
|
|
560
|
+
if (typeof modelOverride === "string" && modelOverride.trim().length > 0) {
|
|
561
|
+
modelStrings.push(modelOverride.trim());
|
|
562
|
+
}
|
|
537
563
|
if (modelConfig?.primary) {
|
|
538
|
-
modelStrings.
|
|
564
|
+
if (!modelStrings.includes(modelConfig.primary)) {
|
|
565
|
+
modelStrings.push(modelConfig.primary);
|
|
566
|
+
}
|
|
539
567
|
}
|
|
540
568
|
if (Array.isArray(modelConfig?.fallbacks)) {
|
|
541
569
|
for (const fb of modelConfig.fallbacks) {
|
|
@@ -973,8 +1001,5 @@ function extractResponsesOutputText(data) {
|
|
|
973
1001
|
}
|
|
974
1002
|
|
|
975
1003
|
export {
|
|
976
|
-
shouldAssumeOpenAiChatCompletions,
|
|
977
|
-
buildChatCompletionTokenLimit,
|
|
978
|
-
findGatewayRuntimeModules,
|
|
979
1004
|
FallbackLlmClient
|
|
980
1005
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// ../remnic-core/src/routing/engine.ts
|
|
2
|
+
function normalizeNamespace(namespace) {
|
|
3
|
+
return namespace.trim();
|
|
4
|
+
}
|
|
5
|
+
function isSafeRouteNamespace(namespace) {
|
|
6
|
+
const value = normalizeNamespace(namespace);
|
|
7
|
+
if (value.length === 0) return false;
|
|
8
|
+
if (value === ".") return false;
|
|
9
|
+
if (value.includes("/") || value.includes("\\")) return false;
|
|
10
|
+
if (value.includes("..")) return false;
|
|
11
|
+
return /^[A-Za-z0-9._-]{1,64}$/.test(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
isSafeRouteNamespace
|
|
16
|
+
};
|