@remnic/plugin-openclaw 1.0.35 → 1.0.36

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.
Files changed (87) hide show
  1. package/README.md +38 -4
  2. package/dist/{calibration-Z5WWNV7U.js → calibration-RKL2LRW4.js} +4 -4
  3. package/dist/{capsule-cli-GBM3WPAM.js → capsule-cli-EHZPMXBC.js} +2 -2
  4. package/dist/{capsule-crypto-K3IRTKRH.js → capsule-crypto-JS67OSWM.js} +3 -3
  5. package/dist/capsule-export-YPDWRB3C.js +17 -0
  6. package/dist/capsule-import-SWPOFG6F.js +16 -0
  7. package/dist/{capsule-merge-IWOQ34KL.js → capsule-merge-YXAF7ZJW.js} +7 -7
  8. package/dist/{causal-chain-WYN5QOPS.js → causal-chain-BVTOWZKC.js} +4 -4
  9. package/dist/{causal-consolidation-C64NNE4T.js → causal-consolidation-DRPM2KOE.js} +13 -10
  10. package/dist/{causal-retrieval-NZHQOZOE.js → causal-retrieval-XAP6QKHZ.js} +4 -5
  11. package/dist/{causal-trajectory-graph-VBPE2WPM.js → causal-trajectory-graph-ZWQWZ7N5.js} +2 -2
  12. package/dist/{chunk-5LE4HTVL.js → chunk-25J4PXDH.js} +0 -18
  13. package/dist/{chunk-FGTYFLL5.js → chunk-3IHGISUN.js} +29 -32
  14. package/dist/{chunk-6UFI73TJ.js → chunk-3IKMUNW5.js} +53 -46
  15. package/dist/{chunk-EXDYWXMB.js → chunk-4XDQ3KEC.js} +1 -2
  16. package/dist/{chunk-JGIUTWZS.js → chunk-6O3H3DPL.js} +2 -2
  17. package/dist/{chunk-UTDLHBBV.js → chunk-BLC3RQNV.js} +5 -555
  18. package/dist/{chunk-4G2XCSD2.js → chunk-BZ4EYURA.js} +0 -5
  19. package/dist/{chunk-4LYQ4ONL.js → chunk-E4RM7637.js} +1 -1
  20. package/dist/{chunk-TDRJVMUP.js → chunk-EH4AXGRO.js} +0 -12
  21. package/dist/{chunk-EYCLXMIV.js → chunk-G3CZA4SD.js} +9 -427
  22. package/dist/chunk-I2KLQ2HA.js +22 -0
  23. package/dist/chunk-IO5WWY6A.js +156 -0
  24. package/dist/{contradiction-scan-A5NOTZPN.js → chunk-JC3FCKYL.js} +189 -86
  25. package/dist/{chunk-SVSQAG6M.js → chunk-KC7KSQR4.js} +47 -28
  26. package/dist/chunk-LZCGPRHS.js +228 -0
  27. package/dist/{chunk-CXM7EBAO.js → chunk-MXFJXUHC.js} +1 -1
  28. package/dist/{chunk-L6I4MQKO.js → chunk-NNAN63QK.js} +6 -6
  29. package/dist/{chunk-VRGUUHBV.js → chunk-NUWDSTP7.js} +1 -1
  30. package/dist/{chunk-6OJAU466.js → chunk-QMUQV5NP.js} +0 -1
  31. package/dist/{chunk-LLUROTZJ.js → chunk-QQXJODFL.js} +9 -9
  32. package/dist/{chunk-6F6EKSVP.js → chunk-QXXEF7VI.js} +1 -1
  33. package/dist/{chunk-CMKR6NDQ.js → chunk-SEGEX7W4.js} +73 -241
  34. package/dist/{chunk-VFULKFKI.js → chunk-SWOYEQN2.js} +42 -17
  35. package/dist/chunk-TH5FF5SC.js +16 -0
  36. package/dist/chunk-UZJ7EERS.js +272 -0
  37. package/dist/chunk-YJYZMLD5.js +360 -0
  38. package/dist/{chunk-NKVIN6RD.js → chunk-YKV4EFUI.js} +84 -2
  39. package/dist/{chunk-SSFTU6LP.js → chunk-ZS6VABML.js} +4 -4
  40. package/dist/{cipher-VHAFCG7Z.js → cipher-E23BHBSO.js} +1 -1
  41. package/dist/{consolidation-undo-5ZSX4MWO.js → consolidation-undo-FKJZCJHS.js} +2 -2
  42. package/dist/contradiction-review-WJRWNQ5N.js +29 -0
  43. package/dist/contradiction-scan-5X423QGT.js +12 -0
  44. package/dist/{dreams-ledger-3I52ISYR.js → dreams-ledger-KDX44I7R.js} +1 -1
  45. package/dist/{engine-47AKKYJ4.js → engine-5P774HTZ.js} +6 -6
  46. package/dist/{extraction-judge-telemetry-GHOTVYMP.js → extraction-judge-telemetry-O4ZVGLTU.js} +1 -1
  47. package/dist/{fallback-llm-45A755XP.js → fallback-llm-43UMEXNJ.js} +3 -3
  48. package/dist/{first-start-migration-I24M2JEE.js → first-start-migration-H2SAXAGR.js} +4 -4
  49. package/dist/{forget-NI4RBDPB.js → forget-ZECIDNL5.js} +1 -1
  50. package/dist/{fs-utils-PZRI2HDZ.js → fs-utils-OYXSZSVV.js} +12 -2
  51. package/dist/{graph-edge-decay-5CVKWBYH.js → graph-edge-decay-24ZKD5QL.js} +5 -5
  52. package/dist/index.js +7091 -84285
  53. package/dist/{kdf-H5B23ZM2.js → kdf-RXKIWHRU.js} +1 -1
  54. package/dist/legacy-hook-compat-QHHKF4GK.js +2 -0
  55. package/dist/{logger-TNOKCH7X.js → logger-XG7JKLPS.js} +1 -1
  56. package/dist/{memory-governance-QS7Z425Y.js → memory-governance-6K4M4YXD.js} +5 -5
  57. package/dist/{metadata-JAGIWHEA.js → metadata-WK2TRPYZ.js} +1 -1
  58. package/dist/{migrate-from-identity-anchor-7MMSPEUM.js → migrate-from-identity-anchor-SNDNKHZD.js} +1 -1
  59. package/dist/path-ZKO74XXC.js +7 -0
  60. package/dist/{peers-KRFXWRQ6.js → peers-W53WSDXG.js} +1 -1
  61. package/dist/{purge-XN2VSPZ2.js → purge-IKJISXEQ.js} +1 -1
  62. package/dist/resolution-BN35OXDS.js +11 -0
  63. package/dist/{secure-store-A4NGCNXV.js → secure-store-F75I54O5.js} +3 -3
  64. package/dist/{state-PVISYXRH.js → state-4ITLYMAU.js} +1 -1
  65. package/dist/{state-store-N6TFBFSP.js → state-store-ET3ADVY5.js} +3 -3
  66. package/dist/{storage-DDYQGLXA.js → storage-5EY6T7ON.js} +3 -3
  67. package/dist/{tier-stats-IZNW66NC.js → tier-stats-ZRQBV6G2.js} +4 -4
  68. package/dist/{trace-NJESSGH7.js → trace-IL2Y34EH.js} +1 -1
  69. package/dist/{tui-MGK2LYJY.js → tui-7KRDCMYK.js} +1 -1
  70. package/dist/{types-R4DO7AKM.js → types-7L34HYDW.js} +3 -3
  71. package/openclaw.plugin.json +17 -8
  72. package/package.json +8 -5
  73. package/scripts/faiss_index.py +756 -0
  74. package/scripts/faiss_requirements.txt +3 -0
  75. package/dist/capsule-export-IXVERCQG.js +0 -17
  76. package/dist/capsule-import-IA6VIOPQ.js +0 -16
  77. package/dist/chunk-3GUF7RQI.js +0 -559
  78. package/dist/chunk-7OQEPGQF.js +0 -533
  79. package/dist/chunk-DIZW6H5J.js +0 -136
  80. package/dist/chunk-FQRSVYY4.js +0 -110
  81. package/dist/chunk-GUSMRW4H.js +0 -12
  82. package/dist/chunk-MLKGABMK.js +0 -9
  83. package/dist/chunk-WPINX4MF.js +0 -380
  84. package/dist/contradiction-review-SVGBS3V5.js +0 -21
  85. package/dist/legacy-hook-compat-XQ7FP6FV.js +0 -35
  86. package/dist/path-JIEGNWFL.js +0 -7
  87. package/dist/resolution-YITUVUTH.js +0 -100
@@ -1,29 +1,42 @@
1
1
  import {
2
- countRecallTokenOverlap,
3
- normalizeRecallTokens
4
- } from "./chunk-WPINX4MF.js";
2
+ isSafeRouteNamespace
3
+ } from "./chunk-TH5FF5SC.js";
5
4
  import {
6
- StorageManager,
7
- isSemanticConsolidationLlmOperator
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-TDRJVMUP.js";
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 path from "path";
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 codexHome = resolveCodexHome(options.codexHome);
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 = path.join(memoriesDir, SENTINEL_FILE);
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
- path.join(memoriesDir, "memory_summary.md"),
121
- path.join(memoriesDir, "MEMORY.md"),
122
- path.join(memoriesDir, "raw_memories.md"),
123
- ...rolloutFiles.map((r) => path.join(memoriesDir, ROLLOUT_SUBDIR, r.name))
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 = path.join(memoriesDir, `${TMP_DIR}-${runTag}`);
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 = path.join(memoriesDir, entry.name);
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(path.join(tmpDir, ROLLOUT_SUBDIR), { recursive: true });
173
+ fs.mkdirSync(path2.join(tmpDir, ROLLOUT_SUBDIR), { recursive: true });
162
174
  const filesWritten = [];
163
- fs.writeFileSync(path.join(tmpDir, "memory_summary.md"), memorySummary);
175
+ fs.writeFileSync(path2.join(tmpDir, "memory_summary.md"), memorySummary);
164
176
  filesWritten.push("memory_summary.md");
165
- fs.writeFileSync(path.join(tmpDir, "MEMORY.md"), memoryMd);
177
+ fs.writeFileSync(path2.join(tmpDir, "MEMORY.md"), memoryMd);
166
178
  filesWritten.push("MEMORY.md");
167
- fs.writeFileSync(path.join(tmpDir, "raw_memories.md"), rawMemories);
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(path.join(tmpDir, ROLLOUT_SUBDIR, rollout.name), rollout.body);
171
- filesWritten.push(path.join(ROLLOUT_SUBDIR, rollout.name));
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 = path.join(tmpDir, rel);
175
- const dest = path.join(memoriesDir, rel);
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 = path.join(memoriesDir, ROLLOUT_SUBDIR);
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(path.join(destRolloutsDir, entry.name));
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 = path.join(tmpDir, ROLLOUT_SUBDIR, rollout.name);
197
- const dest = path.join(destRolloutsDir, rollout.name);
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 path.join(resolveHomeDir(), ".codex");
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
- try {
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
- if (requested.length === 0 || requested === "auto") {
620
- return cfg.defaultNamespace && cfg.defaultNamespace.length > 0 ? cfg.defaultNamespace : "default";
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 requested;
645
+ return namespace;
623
646
  }
624
647
  function resolveNamespaceDir(memoryDir, namespace, cfg) {
625
648
  if (!cfg.namespacesEnabled) return memoryDir;
626
- const ns = namespace || cfg.defaultNamespace || "default";
627
- const namespacedRoot = path2.join(memoryDir, "namespaces", ns);
628
- if (ns === cfg.defaultNamespace) {
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
- findSimilarClusters,
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-TDRJVMUP.js";
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
- resolved = markerEnvValue;
209
- resolvedCache.set(cacheKey, resolved);
210
- return resolved;
231
+ return markerEnvValue;
211
232
  }
212
233
  } else {
213
- resolved = trimmedCredentialValue;
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.push(modelConfig.primary);
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
+ };