@anuma/sdk 2.4.2 → 2.6.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.
@@ -7,6 +7,7 @@ import {
7
7
  ENTITY_KINDS,
8
8
  LRUCache,
9
9
  RerankerUnavailableError,
10
+ TOPICS_EXTRACTION_VERSION,
10
11
  chunkAndEmbedAllMessages,
11
12
  chunkAndEmbedMessage,
12
13
  chunkText,
@@ -22,6 +23,7 @@ import {
22
23
  createMemoryVaultSearchTool,
23
24
  createMessageOp,
24
25
  createSseClient,
26
+ createSupersedingMemoryOp,
25
27
  createVaultEmbeddingCache,
26
28
  createVaultMemoriesBatchOp,
27
29
  createVaultMemoryOp,
@@ -92,6 +94,7 @@ import {
92
94
  shouldChunkMessage,
93
95
  stampTopicsExtractedAtOp,
94
96
  stripToolCalls,
97
+ supersedeVaultMemoryOp,
95
98
  updateConversationProjectOp,
96
99
  updateConversationTitleOp,
97
100
  updateMessageChunksOp,
@@ -102,7 +105,7 @@ import {
102
105
  updateVaultMemoryOp,
103
106
  upsertMessageOp,
104
107
  vaultMemoryToStored
105
- } from "./chunk-3MLG7SUH.mjs";
108
+ } from "./chunk-Z6II54I7.mjs";
106
109
  import {
107
110
  createStreamingDeAnonymizer,
108
111
  resolvePiiRedactor
@@ -1096,6 +1099,15 @@ __decorateClass([
1096
1099
  __decorateClass([
1097
1100
  (0, import_decorators6.field)("topics_extracted_at")
1098
1101
  ], VaultMemory.prototype, "topicsExtractedAt", 2);
1102
+ __decorateClass([
1103
+ (0, import_decorators6.field)("superseded_by")
1104
+ ], VaultMemory.prototype, "supersededBy", 2);
1105
+ __decorateClass([
1106
+ (0, import_decorators6.field)("superseded_at")
1107
+ ], VaultMemory.prototype, "supersededAt", 2);
1108
+ __decorateClass([
1109
+ (0, import_decorators6.field)("topics_extracted_version")
1110
+ ], VaultMemory.prototype, "topicsExtractedVersion", 2);
1099
1111
  __decorateClass([
1100
1112
  import_decorators6.readonly,
1101
1113
  (0, import_decorators6.date)("created_at")
@@ -1243,7 +1255,7 @@ __decorateClass([
1243
1255
  ], VaultFolder.prototype, "context", 2);
1244
1256
 
1245
1257
  // src/lib/db/schema.ts
1246
- var SDK_SCHEMA_VERSION = 36;
1258
+ var SDK_SCHEMA_VERSION = 38;
1247
1259
  var sdkSchema = (0, import_watermelondb12.appSchema)({
1248
1260
  version: SDK_SCHEMA_VERSION,
1249
1261
  tables: [
@@ -1368,7 +1380,20 @@ var sdkSchema = (0, import_watermelondb12.appSchema)({
1368
1380
  // Unix ms of the last LLM topic-extraction pass over this memory's
1369
1381
  // content. Null = never extracted standalone (legacy rows with entity
1370
1382
  // links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
1371
- { name: "topics_extracted_at", type: "number", isOptional: true }
1383
+ { name: "topics_extracted_at", type: "number", isOptional: true },
1384
+ // Write-time supersession (A2). When set, this fact was replaced by a
1385
+ // newer, incompatible-value fact (e.g. "Lives in Portland" superseded by
1386
+ // "Lives in SF"); `superseded_by` points at the newer memory's id and
1387
+ // `superseded_at` is the Unix ms it happened. Superseded rows stay in
1388
+ // the table (history / read-time fallback) but are excluded from recall
1389
+ // and dedup by default. Null = live (not superseded). Indexed so the
1390
+ // recall filter stays cheap.
1391
+ { name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
1392
+ { name: "superseded_at", type: "number", isOptional: true },
1393
+ // The extraction-logic version this memory was last stamped under. Null
1394
+ // (pre-v38) is treated as version 0, so a bump of TOPICS_EXTRACTION_VERSION
1395
+ // re-extracts stale rows. See getMemoriesNeedingTopicExtractionOp.
1396
+ { name: "topics_extracted_version", type: "number", isOptional: true }
1372
1397
  ]
1373
1398
  }),
1374
1399
  // Entity table — canonical names extracted from auto-extraction (W5).
@@ -1979,6 +2004,34 @@ var sdkMigrations = (0, import_migrations.schemaMigrations)({
1979
2004
  columns: [{ name: "topics_extracted_at", type: "number", isOptional: true }]
1980
2005
  })
1981
2006
  ]
2007
+ },
2008
+ // v36 -> v37: write-time supersession columns on memory_vault. Existing rows
2009
+ // keep both NULL (= live / not superseded), so no backfill — legacy
2010
+ // contradictory rows are handled by the read-time supersession fallback.
2011
+ {
2012
+ toVersion: 37,
2013
+ steps: [
2014
+ (0, import_migrations.addColumns)({
2015
+ table: "memory_vault",
2016
+ columns: [
2017
+ { name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
2018
+ { name: "superseded_at", type: "number", isOptional: true }
2019
+ ]
2020
+ })
2021
+ ]
2022
+ },
2023
+ // v37 -> v38: topics_extracted_version on memory_vault. Existing rows keep it
2024
+ // NULL, read as version 0 by getMemoriesNeedingTopicExtractionOp — so the
2025
+ // first sweep after a TOPICS_EXTRACTION_VERSION bump re-extracts them (drained
2026
+ // across sweeps by the worker's limit). See topicExtract.ts.
2027
+ {
2028
+ toVersion: 38,
2029
+ steps: [
2030
+ (0, import_migrations.addColumns)({
2031
+ table: "memory_vault",
2032
+ columns: [{ name: "topics_extracted_version", type: "number", isOptional: true }]
2033
+ })
2034
+ ]
1982
2035
  }
1983
2036
  ]
1984
2037
  });
@@ -4677,53 +4730,62 @@ async function retain(content, ctx, options = {}) {
4677
4730
  const enableAutoMerge = options.enableAutoMerge ?? true;
4678
4731
  const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
4679
4732
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
4733
+ let supersedeTargetId;
4734
+ let supersedeContent;
4680
4735
  if (enableAutoMerge) {
4681
4736
  if (options.consolidateOptions) {
4682
- const consolidationResult = await tryConsolidate(trimmed, ctx, options);
4683
- if (consolidationResult) return consolidationResult;
4684
- }
4685
- const matches = await searchVaultMemories(
4686
- trimmed,
4687
- ctx.vaultCtx,
4688
- ctx.embeddingOptions,
4689
- ctx.vaultCache,
4690
- {
4691
- limit: 1,
4692
- minSimilarity: threshold,
4693
- useFusion: false,
4694
- scopes: [resolvedScope],
4695
- ...options.folderId !== void 0 && { folderId: options.folderId }
4696
- }
4697
- );
4698
- if (matches.length > 0) {
4699
- const targetId = matches[0].uniqueId;
4700
- const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
4701
- if (existing) {
4702
- const mergedSourceIds = unionStrings(
4703
- existing.sourceChunkIds ?? [],
4704
- options.sourceChunkIds ?? []
4705
- );
4706
- const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
4707
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
4708
- content: existing.content,
4709
- proofCountIncrement: 1,
4710
- sourceChunkIds: mergedSourceIds,
4711
- preserveUpdatedAt: true,
4712
- ...eventTimeUpdate && { eventTime: eventTimeUpdate }
4713
- });
4714
- if (updated) {
4715
- return {
4716
- action: "merge",
4717
- memoryId: targetId,
4718
- targetId,
4719
- proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
4720
- };
4737
+ const outcome = await tryConsolidate(trimmed, ctx, options);
4738
+ if (outcome) {
4739
+ if ("done" in outcome) return outcome.done;
4740
+ supersedeTargetId = outcome.supersede;
4741
+ supersedeContent = outcome.content;
4742
+ }
4743
+ }
4744
+ if (!supersedeTargetId) {
4745
+ const matches = await searchVaultMemories(
4746
+ trimmed,
4747
+ ctx.vaultCtx,
4748
+ ctx.embeddingOptions,
4749
+ ctx.vaultCache,
4750
+ {
4751
+ limit: 1,
4752
+ minSimilarity: threshold,
4753
+ useFusion: false,
4754
+ scopes: [resolvedScope],
4755
+ ...options.folderId !== void 0 && { folderId: options.folderId }
4756
+ }
4757
+ );
4758
+ if (matches.length > 0) {
4759
+ const targetId = matches[0].uniqueId;
4760
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
4761
+ if (existing && !existing.supersededBy) {
4762
+ const mergedSourceIds = unionStrings(
4763
+ existing.sourceChunkIds ?? [],
4764
+ options.sourceChunkIds ?? []
4765
+ );
4766
+ const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
4767
+ const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
4768
+ content: existing.content,
4769
+ proofCountIncrement: 1,
4770
+ sourceChunkIds: mergedSourceIds,
4771
+ preserveUpdatedAt: true,
4772
+ ...eventTimeUpdate && { eventTime: eventTimeUpdate }
4773
+ });
4774
+ if (updated) {
4775
+ return {
4776
+ action: "merge",
4777
+ memoryId: targetId,
4778
+ targetId,
4779
+ proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
4780
+ };
4781
+ }
4782
+ await assertMergeTargetGoneOrThrow(ctx, targetId);
4721
4783
  }
4722
- await assertMergeTargetGoneOrThrow(ctx, targetId);
4723
4784
  }
4724
4785
  }
4725
4786
  }
4726
- const embedding = await generateEmbedding(trimmed, ctx.embeddingOptions);
4787
+ const contentToWrite = supersedeContent ?? trimmed;
4788
+ const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
4727
4789
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
4728
4790
  if (options.respectTombstones) {
4729
4791
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -4734,8 +4796,8 @@ async function retain(content, ctx, options = {}) {
4734
4796
  return { action: "suppressed", memoryId: tombstoneId, tombstoneId, proofCount: 0 };
4735
4797
  }
4736
4798
  }
4737
- const created = await createVaultMemoryOp(ctx.vaultCtx, {
4738
- content: trimmed,
4799
+ const createOpts = {
4800
+ content: contentToWrite,
4739
4801
  scope: resolvedScope,
4740
4802
  ...options.folderId !== void 0 && { folderId: options.folderId },
4741
4803
  embedding: JSON.stringify(embedding),
@@ -4752,7 +4814,24 @@ async function retain(content, ctx, options = {}) {
4752
4814
  kind: options.eventTime.kind
4753
4815
  }
4754
4816
  }
4755
- });
4817
+ };
4818
+ if (supersedeTargetId) {
4819
+ const { created: created2, retired } = await createSupersedingMemoryOp(
4820
+ ctx.vaultCtx,
4821
+ createOpts,
4822
+ supersedeTargetId
4823
+ );
4824
+ if (created2 && retired) {
4825
+ ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
4826
+ return {
4827
+ action: "supersede",
4828
+ memoryId: created2.uniqueId,
4829
+ targetId: supersedeTargetId,
4830
+ proofCount: 1
4831
+ };
4832
+ }
4833
+ }
4834
+ const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
4756
4835
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
4757
4836
  return {
4758
4837
  action: "create",
@@ -4819,12 +4898,17 @@ async function tryConsolidate(trimmed, ctx, options) {
4819
4898
  content: m.content,
4820
4899
  similarity: m.similarity
4821
4900
  }));
4822
- const { consolidateMemory: doConsolidate } = await import("./consolidate-TDT4HRHG.mjs");
4901
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-CN2GQV4D.mjs");
4823
4902
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
4824
4903
  if (decision.action === "create") return null;
4904
+ if (decision.action === "supersede" && decision.targetId && decision.content) {
4905
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
4906
+ if (!existing || existing.supersededBy) return null;
4907
+ return { supersede: decision.targetId, content: decision.content };
4908
+ }
4825
4909
  if (decision.action === "noop" && decision.targetId) {
4826
4910
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
4827
- if (!existing) return null;
4911
+ if (!existing || existing.supersededBy) return null;
4828
4912
  const mergedSourceIds = unionStrings(
4829
4913
  existing.sourceChunkIds ?? [],
4830
4914
  options.sourceChunkIds ?? []
@@ -4842,15 +4926,17 @@ async function tryConsolidate(trimmed, ctx, options) {
4842
4926
  return null;
4843
4927
  }
4844
4928
  return {
4845
- action: "merge",
4846
- memoryId: decision.targetId,
4847
- targetId: decision.targetId,
4848
- proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
4929
+ done: {
4930
+ action: "merge",
4931
+ memoryId: decision.targetId,
4932
+ targetId: decision.targetId,
4933
+ proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
4934
+ }
4849
4935
  };
4850
4936
  }
4851
4937
  if (decision.action === "update" && decision.targetId && decision.content) {
4852
4938
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
4853
- if (!existing) return null;
4939
+ if (!existing || existing.supersededBy) return null;
4854
4940
  const mergedSourceIds = unionStrings(
4855
4941
  existing.sourceChunkIds ?? [],
4856
4942
  options.sourceChunkIds ?? []
@@ -4877,10 +4963,12 @@ async function tryConsolidate(trimmed, ctx, options) {
4877
4963
  }
4878
4964
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
4879
4965
  return {
4880
- action: "update",
4881
- memoryId: decision.targetId,
4882
- targetId: decision.targetId,
4883
- proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
4966
+ done: {
4967
+ action: "update",
4968
+ memoryId: decision.targetId,
4969
+ targetId: decision.targetId,
4970
+ proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
4971
+ }
4884
4972
  };
4885
4973
  }
4886
4974
  return null;
@@ -11366,6 +11454,7 @@ export {
11366
11454
  STREAM_RESUMABLE_HEADER,
11367
11455
  StreamExpiredError,
11368
11456
  TOOL_CATALOG,
11457
+ TOPICS_EXTRACTION_VERSION,
11369
11458
  TOPIC_EXTRACTION_BATCH_SIZE,
11370
11459
  TextProcessor,
11371
11460
  UserPreference,
@@ -11552,6 +11641,7 @@ export {
11552
11641
  streamCancelPath,
11553
11642
  streamReplayPath,
11554
11643
  summaryToSystemMessage,
11644
+ supersedeVaultMemoryOp,
11555
11645
  toolSetSystemPrompts,
11556
11646
  updateConversationProjectOp,
11557
11647
  updateConversationTitleOp,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-3MLG7SUH.mjs";
3
+ } from "./chunk-Z6II54I7.mjs";
4
4
  import "./chunk-AHJT66EO.mjs";
5
5
  import "./chunk-3RPGXXPZ.mjs";
6
6
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "2.4.2",
3
+ "version": "2.6.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",