@graphorin/memory 0.6.0 → 0.7.0

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 (227) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +24 -7
  3. package/dist/conflict/index.js +0 -1
  4. package/dist/conflict/pipeline.js +0 -1
  5. package/dist/conflict/pipeline.js.map +1 -1
  6. package/dist/conflict/stages/stage3-heuristic-regex.js +0 -1
  7. package/dist/conflict/stages/stage3-heuristic-regex.js.map +1 -1
  8. package/dist/conflict/types.d.ts +1 -1
  9. package/dist/conflict/types.js.map +1 -1
  10. package/dist/consolidator/index.js +2 -0
  11. package/dist/consolidator/index.js.map +1 -1
  12. package/dist/consolidator/lock.js +7 -1
  13. package/dist/consolidator/lock.js.map +1 -1
  14. package/dist/consolidator/phases/deep.js +19 -12
  15. package/dist/consolidator/phases/deep.js.map +1 -1
  16. package/dist/consolidator/phases/induce.d.ts.map +1 -1
  17. package/dist/consolidator/phases/induce.js +2 -3
  18. package/dist/consolidator/phases/induce.js.map +1 -1
  19. package/dist/consolidator/phases/reflect.js +35 -8
  20. package/dist/consolidator/phases/reflect.js.map +1 -1
  21. package/dist/consolidator/phases/standard.js +199 -28
  22. package/dist/consolidator/phases/standard.js.map +1 -1
  23. package/dist/consolidator/reconcile.js +16 -15
  24. package/dist/consolidator/reconcile.js.map +1 -1
  25. package/dist/consolidator/runtime.d.ts.map +1 -1
  26. package/dist/consolidator/runtime.js +129 -47
  27. package/dist/consolidator/runtime.js.map +1 -1
  28. package/dist/consolidator/scheduler.d.ts +17 -3
  29. package/dist/consolidator/scheduler.d.ts.map +1 -1
  30. package/dist/consolidator/scheduler.js.map +1 -1
  31. package/dist/consolidator/types.d.ts +30 -1
  32. package/dist/consolidator/types.d.ts.map +1 -1
  33. package/dist/consolidator/types.js +10 -0
  34. package/dist/consolidator/types.js.map +1 -1
  35. package/dist/context-engine/compaction/clear-tool-results.d.ts +1 -1
  36. package/dist/context-engine/compaction/clear-tool-results.js +1 -1
  37. package/dist/context-engine/compaction/clear-tool-results.js.map +1 -1
  38. package/dist/context-engine/compaction/compactor.d.ts +1 -0
  39. package/dist/context-engine/compaction/compactor.d.ts.map +1 -1
  40. package/dist/context-engine/compaction/compactor.js +32 -8
  41. package/dist/context-engine/compaction/compactor.js.map +1 -1
  42. package/dist/context-engine/compaction/hooks/types.d.ts +1 -1
  43. package/dist/context-engine/compaction/index.d.ts +1 -0
  44. package/dist/context-engine/compaction/templates/marker.d.ts +33 -0
  45. package/dist/context-engine/compaction/templates/marker.d.ts.map +1 -0
  46. package/dist/context-engine/compaction/templates/marker.js +34 -0
  47. package/dist/context-engine/compaction/templates/marker.js.map +1 -0
  48. package/dist/context-engine/compaction/templates/summary-9-section.d.ts +1 -1
  49. package/dist/context-engine/compaction/templates/summary-9-section.d.ts.map +1 -1
  50. package/dist/context-engine/compaction/templates/summary-9-section.js +4 -3
  51. package/dist/context-engine/compaction/templates/summary-9-section.js.map +1 -1
  52. package/dist/context-engine/engine.d.ts +7 -176
  53. package/dist/context-engine/engine.d.ts.map +1 -1
  54. package/dist/context-engine/engine.js +0 -2
  55. package/dist/context-engine/engine.js.map +1 -1
  56. package/dist/context-engine/index.d.ts +8 -49
  57. package/dist/context-engine/io-types.d.ts +144 -0
  58. package/dist/context-engine/io-types.d.ts.map +1 -0
  59. package/dist/context-engine/locale-packs/types.d.ts +1 -1
  60. package/dist/context-engine/locale-packs/types.js.map +1 -1
  61. package/dist/context-engine/privacy-filter.d.ts +1 -2
  62. package/dist/context-engine/privacy-filter.d.ts.map +1 -1
  63. package/dist/context-engine/privacy-filter.js +1 -2
  64. package/dist/context-engine/privacy-filter.js.map +1 -1
  65. package/dist/errors/index.d.ts +2 -2
  66. package/dist/errors/index.js +2 -2
  67. package/dist/errors/index.js.map +1 -1
  68. package/dist/facade.d.ts +43 -52
  69. package/dist/facade.d.ts.map +1 -1
  70. package/dist/facade.js +5 -3
  71. package/dist/facade.js.map +1 -1
  72. package/dist/graph/entity-resolver.js +1 -1
  73. package/dist/graph/entity-resolver.js.map +1 -1
  74. package/dist/index.d.ts +17 -15
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +5 -7
  77. package/dist/index.js.map +1 -1
  78. package/dist/internal/envelope.js +57 -0
  79. package/dist/internal/envelope.js.map +1 -0
  80. package/dist/internal/injection-heuristics.js +0 -0
  81. package/dist/internal/injection-heuristics.js.map +1 -1
  82. package/dist/internal/llm-json.js +40 -0
  83. package/dist/internal/llm-json.js.map +1 -0
  84. package/dist/internal/storage-adapter.d.ts +23 -10
  85. package/dist/internal/storage-adapter.d.ts.map +1 -1
  86. package/dist/memory-interface.d.ts +131 -0
  87. package/dist/memory-interface.d.ts.map +1 -0
  88. package/dist/package.js +6 -0
  89. package/dist/package.js.map +1 -0
  90. package/dist/search/iterative.d.ts.map +1 -1
  91. package/dist/search/iterative.js +2 -3
  92. package/dist/search/iterative.js.map +1 -1
  93. package/dist/search/query-transform.d.ts.map +1 -1
  94. package/dist/search/query-transform.js +2 -3
  95. package/dist/search/query-transform.js.map +1 -1
  96. package/dist/tiers/episodic-memory.js +3 -3
  97. package/dist/tiers/episodic-memory.js.map +1 -1
  98. package/dist/tiers/index.d.ts +2 -2
  99. package/dist/tiers/insight-memory.js +1 -1
  100. package/dist/tiers/insight-memory.js.map +1 -1
  101. package/dist/tiers/procedural-memory.d.ts +1 -1
  102. package/dist/tiers/procedural-memory.js +2 -2
  103. package/dist/tiers/procedural-memory.js.map +1 -1
  104. package/dist/tiers/semantic-memory.d.ts +58 -4
  105. package/dist/tiers/semantic-memory.d.ts.map +1 -1
  106. package/dist/tiers/semantic-memory.js +103 -20
  107. package/dist/tiers/semantic-memory.js.map +1 -1
  108. package/dist/tools/block-tools.d.ts +19 -57
  109. package/dist/tools/block-tools.d.ts.map +1 -1
  110. package/dist/tools/block-tools.js.map +1 -1
  111. package/dist/tools/fact-tools.d.ts +53 -214
  112. package/dist/tools/fact-tools.d.ts.map +1 -1
  113. package/dist/tools/fact-tools.js +3 -2
  114. package/dist/tools/fact-tools.js.map +1 -1
  115. package/dist/tools/recall-tools.d.ts +34 -175
  116. package/dist/tools/recall-tools.d.ts.map +1 -1
  117. package/dist/tools/recall-tools.js +5 -4
  118. package/dist/tools/recall-tools.js.map +1 -1
  119. package/dist/tools/runbook-tools.d.ts +15 -58
  120. package/dist/tools/runbook-tools.d.ts.map +1 -1
  121. package/dist/tools/runbook-tools.js.map +1 -1
  122. package/dist/tools/types.d.ts +1 -1
  123. package/package.json +18 -17
  124. package/src/conflict/index.ts +29 -0
  125. package/src/conflict/locale-packs/en.ts +142 -0
  126. package/src/conflict/locale-packs/index.ts +17 -0
  127. package/src/conflict/locale-packs/types.ts +138 -0
  128. package/src/conflict/pipeline.ts +371 -0
  129. package/src/conflict/stages/helpers.ts +65 -0
  130. package/src/conflict/stages/stage1-exact-dedup.ts +40 -0
  131. package/src/conflict/stages/stage2-embedding-three-zone.ts +54 -0
  132. package/src/conflict/stages/stage3-heuristic-regex.ts +51 -0
  133. package/src/conflict/stages/stage4-subject-predicate.ts +46 -0
  134. package/src/conflict/stages/stage5-defer-to-deep.ts +34 -0
  135. package/src/conflict/types.ts +263 -0
  136. package/src/consolidator/budget.ts +312 -0
  137. package/src/consolidator/decay.ts +246 -0
  138. package/src/consolidator/dlq.ts +61 -0
  139. package/src/consolidator/errors.ts +87 -0
  140. package/src/consolidator/idempotency.ts +27 -0
  141. package/src/consolidator/index.ts +269 -0
  142. package/src/consolidator/lock.ts +141 -0
  143. package/src/consolidator/noise-filter.ts +235 -0
  144. package/src/consolidator/phases/deep.ts +308 -0
  145. package/src/consolidator/phases/induce.ts +423 -0
  146. package/src/consolidator/phases/learned-context.ts +233 -0
  147. package/src/consolidator/phases/light.ts +166 -0
  148. package/src/consolidator/phases/reflect.ts +504 -0
  149. package/src/consolidator/phases/standard.ts +1002 -0
  150. package/src/consolidator/reconcile.ts +273 -0
  151. package/src/consolidator/runtime.ts +1049 -0
  152. package/src/consolidator/scheduler.ts +182 -0
  153. package/src/consolidator/triggers.ts +134 -0
  154. package/src/consolidator/types.ts +622 -0
  155. package/src/context-engine/annotations.ts +161 -0
  156. package/src/context-engine/auto-recall.ts +92 -0
  157. package/src/context-engine/compaction/clear-tool-results.ts +232 -0
  158. package/src/context-engine/compaction/compactor.ts +403 -0
  159. package/src/context-engine/compaction/hooks/reanchor-persona-block.ts +55 -0
  160. package/src/context-engine/compaction/hooks/reanchor-pinned-facts.ts +66 -0
  161. package/src/context-engine/compaction/hooks/reanchor-project-rules.ts +57 -0
  162. package/src/context-engine/compaction/hooks/reanchor-recent-results.ts +116 -0
  163. package/src/context-engine/compaction/hooks/types.ts +68 -0
  164. package/src/context-engine/compaction/index.ts +60 -0
  165. package/src/context-engine/compaction/templates/marker.ts +33 -0
  166. package/src/context-engine/compaction/templates/summary-9-section.ts +223 -0
  167. package/src/context-engine/compaction/thresholds.ts +107 -0
  168. package/src/context-engine/compaction/types.ts +255 -0
  169. package/src/context-engine/engine.ts +970 -0
  170. package/src/context-engine/index.ts +118 -0
  171. package/src/context-engine/io-types.ts +162 -0
  172. package/src/context-engine/locale-packs/en.ts +107 -0
  173. package/src/context-engine/locale-packs/index.ts +19 -0
  174. package/src/context-engine/locale-packs/resolver.ts +197 -0
  175. package/src/context-engine/locale-packs/types.ts +177 -0
  176. package/src/context-engine/metadata.ts +114 -0
  177. package/src/context-engine/preambles/inbound-en.ts +19 -0
  178. package/src/context-engine/privacy-filter.ts +190 -0
  179. package/src/context-engine/templates/base-en.ts +19 -0
  180. package/src/context-engine/templates/composer.ts +91 -0
  181. package/src/context-engine/token-budget.ts +319 -0
  182. package/src/context-engine/token-counter.ts +157 -0
  183. package/src/errors/index.ts +273 -0
  184. package/src/facade.ts +750 -0
  185. package/src/graph/entity-resolver.ts +364 -0
  186. package/src/graph/index.ts +24 -0
  187. package/src/index.ts +259 -0
  188. package/src/internal/contextualize.ts +173 -0
  189. package/src/internal/embedder-binding.ts +53 -0
  190. package/src/internal/envelope.ts +70 -0
  191. package/src/internal/id.ts +23 -0
  192. package/src/internal/injection-heuristics.ts +0 -0
  193. package/src/internal/llm-json.ts +38 -0
  194. package/src/internal/spans.ts +35 -0
  195. package/src/internal/storage-adapter.ts +963 -0
  196. package/src/memory-interface.ts +158 -0
  197. package/src/migration/embedder-migration.ts +237 -0
  198. package/src/migration/index.ts +13 -0
  199. package/src/search/explain.ts +123 -0
  200. package/src/search/fit-weights.ts +109 -0
  201. package/src/search/graph-ppr.ts +38 -0
  202. package/src/search/index.ts +55 -0
  203. package/src/search/iterative.ts +658 -0
  204. package/src/search/query-transform.ts +285 -0
  205. package/src/search/rrf.ts +225 -0
  206. package/src/search/trust.ts +55 -0
  207. package/src/search/types.ts +50 -0
  208. package/src/tiers/episodic-memory.ts +463 -0
  209. package/src/tiers/index.ts +50 -0
  210. package/src/tiers/insight-memory.ts +208 -0
  211. package/src/tiers/procedural-memory.ts +482 -0
  212. package/src/tiers/semantic-memory.ts +1729 -0
  213. package/src/tiers/session-memory.ts +271 -0
  214. package/src/tiers/shared-memory.ts +62 -0
  215. package/src/tiers/working-memory.ts +368 -0
  216. package/src/tools/block-tools.ts +172 -0
  217. package/src/tools/fact-tools.ts +473 -0
  218. package/src/tools/index.ts +109 -0
  219. package/src/tools/recall-tools.ts +303 -0
  220. package/src/tools/runbook-tools.ts +107 -0
  221. package/src/tools/taint.ts +39 -0
  222. package/src/tools/types.ts +37 -0
  223. package/dist/conflict/locale-packs/index.js +0 -4
  224. package/dist/context-engine/compaction/index.js +0 -10
  225. package/dist/context-engine/index.d.ts.map +0 -1
  226. package/dist/context-engine/index.js +0 -25
  227. package/dist/context-engine/locale-packs/index.js +0 -4
@@ -1,12 +1,12 @@
1
1
  import { withMemorySpan } from "../internal/spans.js";
2
2
  import { DEFAULT_SALIENCE_WEIGHTS } from "../consolidator/decay.js";
3
3
  import { QuarantinePromotionRefusedError } from "../errors/index.js";
4
+ import { detectMemoryInjection } from "../internal/injection-heuristics.js";
4
5
  import { contextualize } from "../internal/contextualize.js";
5
6
  import { newMemoryId } from "../internal/id.js";
6
7
  import { normalizeEntityName } from "../graph/entity-resolver.js";
7
8
  import { DEFAULT_MAX_ITERATIONS, runIterativeRetrieval } from "../search/iterative.js";
8
9
  import { WeightedRRFReranker, fuseRrf, fuseWeighted } from "../search/rrf.js";
9
- import { detectMemoryInjection } from "../internal/injection-heuristics.js";
10
10
  import { explainRecall } from "../search/explain.js";
11
11
  import { pprActivation } from "../search/graph-ppr.js";
12
12
  import { trustDiscount } from "../search/trust.js";
@@ -37,8 +37,10 @@ var SemanticMemory = class {
37
37
  #entityResolver;
38
38
  #grader;
39
39
  #iterativeMaxIterations;
40
+ #iterativeDifficultyThreshold;
40
41
  #reranker;
41
42
  #trustWeights;
43
+ #searchDefaults;
42
44
  constructor(args) {
43
45
  this.#store = args.store;
44
46
  this.#tracer = args.tracer;
@@ -51,7 +53,9 @@ var SemanticMemory = class {
51
53
  this.#entityResolver = args.entityResolver ?? null;
52
54
  this.#grader = args.grader ?? null;
53
55
  this.#iterativeMaxIterations = args.iterativeMaxIterations ?? DEFAULT_MAX_ITERATIONS;
56
+ this.#iterativeDifficultyThreshold = args.iterativeDifficultyThreshold;
54
57
  this.#trustWeights = args.trustWeights ?? DEFAULT_SALIENCE_WEIGHTS;
58
+ this.#searchDefaults = args.searchDefaults ?? {};
55
59
  }
56
60
  /** Replace the active reranker. Returns the previous instance. */
57
61
  setReranker(reranker) {
@@ -230,7 +234,11 @@ var SemanticMemory = class {
230
234
  } catch {}
231
235
  }
232
236
  /** Hybrid (vector + FTS5) search merged through the configured reranker. */
233
- async search(scope, query, opts = {}) {
237
+ async search(scope, query, callOpts = {}) {
238
+ const opts = {
239
+ ...this.#searchDefaults,
240
+ ...callOpts
241
+ };
234
242
  return withMemorySpan(this.#tracer, "memory.search.semantic", scope, { "memory.search.query_length": query.length }, async (span) => {
235
243
  const candidateTopK = opts.candidateTopK ?? 60;
236
244
  const finalTopK = opts.topK ?? 10;
@@ -240,6 +248,8 @@ var SemanticMemory = class {
240
248
  const wGraph = weighted?.weights.graph ?? 1;
241
249
  const wEntity = weighted?.weights.entity ?? 1;
242
250
  const queries = await this.#expandQueries(query, opts);
251
+ const variantVectors = await this.#tryBatchEmbedQueries(queries);
252
+ const hydeHitsPromise = this.#tryHyde(scope, query, opts, candidateTopK);
243
253
  const lists = [];
244
254
  const listWeights = [];
245
255
  const listLabels = [];
@@ -260,7 +270,8 @@ var SemanticMemory = class {
260
270
  lists.push(ftsHits);
261
271
  listWeights.push(wFts);
262
272
  listLabels.push(`fts_${queries.indexOf(q)}`);
263
- const vectorHits = await this.#tryVectorSearch(scope, q, candidateTopK, opts.asOf, opts.includeQuarantined, opts.includeSuperseded, opts.owner);
273
+ const preVector = variantVectors?.get(q);
274
+ const vectorHits = preVector !== void 0 ? await this.#vectorSearchWithVector(scope, preVector, candidateTopK, opts.asOf, opts.includeQuarantined, opts.includeSuperseded, opts.owner) : await this.#tryVectorSearch(scope, q, candidateTopK, opts.asOf, opts.includeQuarantined, opts.includeSuperseded, opts.owner);
264
275
  if (vectorHits.length > 0) {
265
276
  lists.push(vectorHits);
266
277
  listWeights.push(wVector);
@@ -272,7 +283,7 @@ var SemanticMemory = class {
272
283
  isPrimary = false;
273
284
  }
274
285
  }
275
- const hydeHits = await this.#tryHyde(scope, query, opts, candidateTopK);
286
+ const hydeHits = await hydeHitsPromise;
276
287
  if (hydeHits.length > 0) {
277
288
  lists.push(hydeHits);
278
289
  listWeights.push(wVector);
@@ -294,7 +305,7 @@ var SemanticMemory = class {
294
305
  weights: listWeights,
295
306
  ...weighted.k !== void 0 ? { k: weighted.k } : {}
296
307
  }) : this.#reranker;
297
- const fusedTopK = opts.decay !== void 0 || (opts.tags?.length ?? 0) > 0 || opts.owner !== void 0 || (opts.expandHops ?? 0) > 0 || opts.entityMatch === true ? Math.max(finalTopK, lists.reduce((n, l) => n + l.length, 0)) : finalTopK;
308
+ const fusedTopK = opts.decay !== void 0 || (opts.tags?.length ?? 0) > 0 || opts.owner !== void 0 || (opts.expandHops ?? 0) > 0 || opts.entityMatch === true || opts.trustWeighting !== "off" || opts.includeQuarantined === true ? Math.max(finalTopK, lists.reduce((n, l) => n + l.length, 0)) : finalTopK;
298
309
  const fused = await reranker.rerank(query, lists, {
299
310
  topK: fusedTopK,
300
311
  labels: listLabels,
@@ -310,7 +321,7 @@ var SemanticMemory = class {
310
321
  const ownerFiltered = wantedOwners !== null ? filtered.filter((h) => wantedOwners.includes(h.record.owner ?? "user")) : filtered;
311
322
  const ranked = (opts.trustWeighting === "off" ? ownerFiltered : this.#applyTrustDiscount(ownerFiltered)).slice(0, finalTopK);
312
323
  if (ranked.length > 0 && typeof this.#store.semantic.markAccessed === "function") try {
313
- await this.#store.semantic.markAccessed(ranked.map((h) => h.record.id));
324
+ await this.#store.semantic.markAccessed(ranked.map((h) => h.record.id), void 0, scope);
314
325
  } catch {}
315
326
  const explanation = explainRecall(ranked, {
316
327
  query,
@@ -364,12 +375,16 @@ var SemanticMemory = class {
364
375
  idOf: (hit) => hit.record.id,
365
376
  grader: this.#grader,
366
377
  fuse: (lists) => fuseRrf(lists, 60)
367
- }, {
368
- maxIterations: opts.maxIterations ?? this.#iterativeMaxIterations,
369
- maxResults: opts.topK ?? 10,
370
- ...opts.forceHard !== void 0 ? { forceHard: opts.forceHard } : {},
371
- ...opts.signal !== void 0 ? { signal: opts.signal } : {}
372
- });
378
+ }, (() => {
379
+ const difficultyThreshold = opts.difficultyThreshold ?? this.#iterativeDifficultyThreshold;
380
+ return {
381
+ maxIterations: opts.maxIterations ?? this.#iterativeMaxIterations,
382
+ maxResults: opts.topK ?? 10,
383
+ ...opts.forceHard !== void 0 ? { forceHard: opts.forceHard } : {},
384
+ ...opts.signal !== void 0 ? { signal: opts.signal } : {},
385
+ ...difficultyThreshold !== void 0 ? { difficulty: { threshold: difficultyThreshold } } : {}
386
+ };
387
+ })());
373
388
  span.setAttributes({
374
389
  "memory.search.semantic.iterative.gate_hard": result.gateHard,
375
390
  "memory.search.semantic.iterative.iterations": result.iterations,
@@ -465,16 +480,51 @@ var SemanticMemory = class {
465
480
  }
466
481
  }
467
482
  span.setAttributes({ "memory.semantic.validate.forced": force });
468
- await this.#store.semantic.setStatus(factId, "active", reason);
483
+ await this.#store.semantic.setStatus(factId, "active", reason, scope);
484
+ if (existing !== null && existing.supersedes !== void 0) {
485
+ const oldFact = await this.#fetchExisting(existing.supersedes);
486
+ if (oldFact !== null && oldFact.supersededBy === void 0 && oldFact.validTo === void 0) {
487
+ span.setAttributes({ "memory.semantic.validate.completed_supersede": true });
488
+ await this.#store.semantic.supersede(existing.supersedes, {
489
+ ...existing,
490
+ status: "active"
491
+ }, reason ?? "validated-supersede");
492
+ }
493
+ }
469
494
  });
470
495
  }
471
- /** Mark `oldId` superseded by a new fact. Returns the new record. */
472
- async supersede(scope, oldId, newInput, reason) {
473
- return withMemorySpan(this.#tracer, "memory.write.semantic", scope, { "memory.semantic.action": "supersede" }, async () => {
496
+ /**
497
+ * Mark `oldId` superseded by a new fact. Returns the new record.
498
+ *
499
+ * W-019 (security-first, knowledge-preserving): when the successor
500
+ * lands QUARANTINED (the default for `extraction`/synthesized
501
+ * provenance), the old ACTIVE fact's validity interval is NOT closed
502
+ * - default recall keeps returning the old knowledge until the
503
+ * successor passes {@link validate}, which completes the closure.
504
+ * The link is recorded on the successor's `supersedes` field. With
505
+ * `autoPromoteSynthesized` (threaded from the consolidator's
506
+ * `autoPromoteExtraction` escape hatch) an injection-clean successor
507
+ * is active immediately and the interval closes right away - the
508
+ * pre-W-019 behaviour. Inverting the default (auto-activating the
509
+ * successor) would hand a MINJA attacker instant active memory via
510
+ * any text the reconciler classifies as an 'update'.
511
+ */
512
+ async supersede(scope, oldId, newInput, reason, options) {
513
+ return withMemorySpan(this.#tracer, "memory.write.semantic", scope, { "memory.semantic.action": "supersede" }, async (span) => {
474
514
  const newFact = await this.remember(scope, {
475
515
  ...newInput,
476
516
  supersedes: oldId
477
- }, { pipeline: "off" });
517
+ }, {
518
+ pipeline: "off",
519
+ ...options?.autoPromoteSynthesized === true ? { autoPromoteSynthesized: true } : {}
520
+ });
521
+ if (newFact.status === "quarantined") {
522
+ span.setAttributes({ "memory.semantic.supersede.pending": true });
523
+ return {
524
+ old: oldId,
525
+ new: newFact
526
+ };
527
+ }
478
528
  await this.#store.semantic.supersede(oldId, newFact, reason);
479
529
  return {
480
530
  old: oldId,
@@ -488,7 +538,7 @@ var SemanticMemory = class {
488
538
  "memory.semantic.action": "forget",
489
539
  "memory.semantic.fact_id": factId
490
540
  }, async () => {
491
- await this.#store.semantic.forget(factId, reason);
541
+ await this.#store.semantic.forget(factId, reason, scope);
492
542
  });
493
543
  }
494
544
  /**
@@ -504,7 +554,7 @@ var SemanticMemory = class {
504
554
  "memory.semantic.fact_id": factId
505
555
  }, async () => {
506
556
  if (typeof this.#store.semantic.purge !== "function") throw new TypeError("[graphorin/memory] SemanticMemory.purge(...) requires a storage adapter that implements `semantic.purge(id)`. For storage adapters without GDPR-grade hard-delete, prefer `SemanticMemory.forget(...)`.");
507
- await this.#store.semantic.purge(factId, reason);
557
+ await this.#store.semantic.purge(factId, reason, scope);
508
558
  });
509
559
  }
510
560
  /** Fuse multiple ranked lists outside of a `search()` call. */
@@ -565,7 +615,7 @@ var SemanticMemory = class {
565
615
  try {
566
616
  const pseudo = await this.#queryTransformer.hypothetical(query, { ...opts.signal !== void 0 ? { signal: opts.signal } : {} });
567
617
  if (pseudo === null || pseudo.trim().length === 0) return [];
568
- return this.#tryVectorSearch(scope, pseudo, topK, opts.asOf, opts.includeQuarantined);
618
+ return this.#tryVectorSearch(scope, pseudo, topK, opts.asOf, opts.includeQuarantined, opts.includeSuperseded, opts.owner);
569
619
  } catch {
570
620
  return [];
571
621
  }
@@ -661,9 +711,42 @@ var SemanticMemory = class {
661
711
  if (this.#embedder === null || embedderId === null || typeof this.#store.semantic.searchVector !== "function") return [];
662
712
  const [vector] = await this.#embedder.embed([query], { taskType: "query" });
663
713
  if (vector === void 0) return [];
714
+ return this.#vectorSearchWithVector(scope, vector, topK, asOf, includeQuarantined, includeSuperseded, owner);
715
+ }
716
+ /**
717
+ * W-087: the store half of {@link SemanticMemory.#tryVectorSearch} -
718
+ * runs the KNN read against an ALREADY-COMPUTED query vector so the
719
+ * multi-query fan-out can batch its N variant embeddings into one
720
+ * `embed([q1..qN])` call instead of N provider round-trips.
721
+ */
722
+ async #vectorSearchWithVector(scope, vector, topK, asOf, includeQuarantined, includeSuperseded, owner) {
723
+ const embedderId = this.#embedderIdProvider();
724
+ if (embedderId === null || typeof this.#store.semantic.searchVector !== "function") return [];
664
725
  return this.#store.semantic.searchVector(scope, vector, embedderId, topK, asOf, includeQuarantined, includeSuperseded, owner);
665
726
  }
666
727
  /**
728
+ * W-087: embed every fan-out variant in ONE embedder call. Returns
729
+ * `null` - and the caller degrades to the per-variant path - when
730
+ * there is no fan-out, no vector surface, or the batch call fails; a
731
+ * batching failure must never fail the search.
732
+ */
733
+ async #tryBatchEmbedQueries(queries) {
734
+ if (queries.length <= 1) return null;
735
+ if (this.#embedder === null || this.#embedderIdProvider() === null || typeof this.#store.semantic.searchVector !== "function") return null;
736
+ try {
737
+ const vectors = await this.#embedder.embed([...queries], { taskType: "query" });
738
+ if (vectors.length !== queries.length) return null;
739
+ const byQuery = /* @__PURE__ */ new Map();
740
+ queries.forEach((q, i) => {
741
+ const v = vectors[i];
742
+ if (v !== void 0) byQuery.set(q, v);
743
+ });
744
+ return byQuery;
745
+ } catch {
746
+ return null;
747
+ }
748
+ }
749
+ /**
667
750
  * C5: multiply each hit's fused score by its trust factor and re-sort.
668
751
  * No-ops (returns the same array) when every factor is 1.
669
752
  */