@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.
- package/dist/expo/{chunk-UOUJUZM4.mjs → chunk-TCRDSUC6.mjs} +107 -5
- package/dist/expo/{consolidate-HEMQGOUD.mjs → consolidate-3QQPUWD6.mjs} +15 -9
- package/dist/expo/index.cjs +264 -70
- package/dist/expo/index.d.mts +77 -17
- package/dist/expo/index.d.ts +77 -17
- package/dist/expo/index.mjs +148 -58
- package/dist/{react/recall-G3CS444F.mjs → expo/recall-FQU3NUTL.mjs} +1 -1
- package/dist/react/{chunk-IYDQBFS2.mjs → chunk-ZXS3KOY4.mjs} +111 -6
- package/dist/react/{consolidate-IJH7LD2T.mjs → consolidate-3MXZV3G7.mjs} +15 -9
- package/dist/react/index.cjs +268 -71
- package/dist/react/index.d.mts +85 -20
- package/dist/react/index.d.ts +85 -20
- package/dist/react/index.mjs +148 -58
- package/dist/{expo/recall-HI7VO3VM.mjs → react/recall-PV7L3SN3.mjs} +1 -1
- package/dist/server/{chunk-3MLG7SUH.mjs → chunk-Z6II54I7.mjs} +107 -5
- package/dist/server/{consolidate-TDT4HRHG.mjs → consolidate-CN2GQV4D.mjs} +15 -9
- package/dist/server/index.cjs +264 -70
- package/dist/server/index.d.mts +77 -17
- package/dist/server/index.d.ts +77 -17
- package/dist/server/index.mjs +148 -58
- package/dist/server/{recall-MJHGXMHZ.mjs → recall-CQT24XLH.mjs} +1 -1
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ENTITY_KINDS,
|
|
9
9
|
LRUCache,
|
|
10
10
|
RerankerUnavailableError,
|
|
11
|
+
TOPICS_EXTRACTION_VERSION,
|
|
11
12
|
backfillMemoryEntityUserIdsOp,
|
|
12
13
|
chunkAndEmbedAllMessages,
|
|
13
14
|
chunkAndEmbedMessage,
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
createMemoryVaultSearchTool,
|
|
27
28
|
createMessageOp,
|
|
28
29
|
createSseClient,
|
|
30
|
+
createSupersedingMemoryOp,
|
|
29
31
|
createVaultEmbeddingCache,
|
|
30
32
|
createVaultMemoriesBatchOp,
|
|
31
33
|
createVaultMemoryOp,
|
|
@@ -116,6 +118,7 @@ import {
|
|
|
116
118
|
shouldChunkMessage,
|
|
117
119
|
stampTopicsExtractedAtOp,
|
|
118
120
|
stripToolCalls,
|
|
121
|
+
supersedeVaultMemoryOp,
|
|
119
122
|
updateConversationPinnedOp,
|
|
120
123
|
updateConversationProjectOp,
|
|
121
124
|
updateConversationTitleOp,
|
|
@@ -128,7 +131,7 @@ import {
|
|
|
128
131
|
updateVaultMemoryOp,
|
|
129
132
|
useEncryption,
|
|
130
133
|
vaultMemoryToStored
|
|
131
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-ZXS3KOY4.mjs";
|
|
132
135
|
import {
|
|
133
136
|
PiiRedactor,
|
|
134
137
|
createStreamingDeAnonymizer,
|
|
@@ -6669,6 +6672,15 @@ __decorateClass([
|
|
|
6669
6672
|
__decorateClass([
|
|
6670
6673
|
field3("topics_extracted_at")
|
|
6671
6674
|
], VaultMemory.prototype, "topicsExtractedAt", 2);
|
|
6675
|
+
__decorateClass([
|
|
6676
|
+
field3("superseded_by")
|
|
6677
|
+
], VaultMemory.prototype, "supersededBy", 2);
|
|
6678
|
+
__decorateClass([
|
|
6679
|
+
field3("superseded_at")
|
|
6680
|
+
], VaultMemory.prototype, "supersededAt", 2);
|
|
6681
|
+
__decorateClass([
|
|
6682
|
+
field3("topics_extracted_version")
|
|
6683
|
+
], VaultMemory.prototype, "topicsExtractedVersion", 2);
|
|
6672
6684
|
__decorateClass([
|
|
6673
6685
|
readonly2,
|
|
6674
6686
|
date3("created_at")
|
|
@@ -6696,53 +6708,62 @@ async function retain(content, ctx, options = {}) {
|
|
|
6696
6708
|
const enableAutoMerge = options.enableAutoMerge ?? true;
|
|
6697
6709
|
const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
|
|
6698
6710
|
const resolvedScope = options.scope ?? DEFAULT_SCOPE;
|
|
6711
|
+
let supersedeTargetId;
|
|
6712
|
+
let supersedeContent;
|
|
6699
6713
|
if (enableAutoMerge) {
|
|
6700
6714
|
if (options.consolidateOptions) {
|
|
6701
|
-
const
|
|
6702
|
-
if (
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
);
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6715
|
+
const outcome = await tryConsolidate(trimmed, ctx, options);
|
|
6716
|
+
if (outcome) {
|
|
6717
|
+
if ("done" in outcome) return outcome.done;
|
|
6718
|
+
supersedeTargetId = outcome.supersede;
|
|
6719
|
+
supersedeContent = outcome.content;
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
if (!supersedeTargetId) {
|
|
6723
|
+
const matches = await searchVaultMemories(
|
|
6724
|
+
trimmed,
|
|
6725
|
+
ctx.vaultCtx,
|
|
6726
|
+
ctx.embeddingOptions,
|
|
6727
|
+
ctx.vaultCache,
|
|
6728
|
+
{
|
|
6729
|
+
limit: 1,
|
|
6730
|
+
minSimilarity: threshold,
|
|
6731
|
+
useFusion: false,
|
|
6732
|
+
scopes: [resolvedScope],
|
|
6733
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
6734
|
+
}
|
|
6735
|
+
);
|
|
6736
|
+
if (matches.length > 0) {
|
|
6737
|
+
const targetId = matches[0].uniqueId;
|
|
6738
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
|
|
6739
|
+
if (existing && !existing.supersededBy) {
|
|
6740
|
+
const mergedSourceIds = unionStrings(
|
|
6741
|
+
existing.sourceChunkIds ?? [],
|
|
6742
|
+
options.sourceChunkIds ?? []
|
|
6743
|
+
);
|
|
6744
|
+
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
6745
|
+
const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
|
|
6746
|
+
content: existing.content,
|
|
6747
|
+
proofCountIncrement: 1,
|
|
6748
|
+
sourceChunkIds: mergedSourceIds,
|
|
6749
|
+
preserveUpdatedAt: true,
|
|
6750
|
+
...eventTimeUpdate && { eventTime: eventTimeUpdate }
|
|
6751
|
+
});
|
|
6752
|
+
if (updated) {
|
|
6753
|
+
return {
|
|
6754
|
+
action: "merge",
|
|
6755
|
+
memoryId: targetId,
|
|
6756
|
+
targetId,
|
|
6757
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
6758
|
+
};
|
|
6759
|
+
}
|
|
6760
|
+
await assertMergeTargetGoneOrThrow(ctx, targetId);
|
|
6740
6761
|
}
|
|
6741
|
-
await assertMergeTargetGoneOrThrow(ctx, targetId);
|
|
6742
6762
|
}
|
|
6743
6763
|
}
|
|
6744
6764
|
}
|
|
6745
|
-
const
|
|
6765
|
+
const contentToWrite = supersedeContent ?? trimmed;
|
|
6766
|
+
const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
6746
6767
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
6747
6768
|
if (options.respectTombstones) {
|
|
6748
6769
|
const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -6753,8 +6774,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
6753
6774
|
return { action: "suppressed", memoryId: tombstoneId, tombstoneId, proofCount: 0 };
|
|
6754
6775
|
}
|
|
6755
6776
|
}
|
|
6756
|
-
const
|
|
6757
|
-
content:
|
|
6777
|
+
const createOpts = {
|
|
6778
|
+
content: contentToWrite,
|
|
6758
6779
|
scope: resolvedScope,
|
|
6759
6780
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
6760
6781
|
embedding: JSON.stringify(embedding),
|
|
@@ -6771,7 +6792,24 @@ async function retain(content, ctx, options = {}) {
|
|
|
6771
6792
|
kind: options.eventTime.kind
|
|
6772
6793
|
}
|
|
6773
6794
|
}
|
|
6774
|
-
}
|
|
6795
|
+
};
|
|
6796
|
+
if (supersedeTargetId) {
|
|
6797
|
+
const { created: created2, retired } = await createSupersedingMemoryOp(
|
|
6798
|
+
ctx.vaultCtx,
|
|
6799
|
+
createOpts,
|
|
6800
|
+
supersedeTargetId
|
|
6801
|
+
);
|
|
6802
|
+
if (created2 && retired) {
|
|
6803
|
+
ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
|
|
6804
|
+
return {
|
|
6805
|
+
action: "supersede",
|
|
6806
|
+
memoryId: created2.uniqueId,
|
|
6807
|
+
targetId: supersedeTargetId,
|
|
6808
|
+
proofCount: 1
|
|
6809
|
+
};
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6812
|
+
const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
|
|
6775
6813
|
ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
|
|
6776
6814
|
return {
|
|
6777
6815
|
action: "create",
|
|
@@ -6838,12 +6876,17 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
6838
6876
|
content: m.content,
|
|
6839
6877
|
similarity: m.similarity
|
|
6840
6878
|
}));
|
|
6841
|
-
const { consolidateMemory: doConsolidate } = await import("./consolidate-
|
|
6879
|
+
const { consolidateMemory: doConsolidate } = await import("./consolidate-3MXZV3G7.mjs");
|
|
6842
6880
|
const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
|
|
6843
6881
|
if (decision.action === "create") return null;
|
|
6882
|
+
if (decision.action === "supersede" && decision.targetId && decision.content) {
|
|
6883
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
6884
|
+
if (!existing || existing.supersededBy) return null;
|
|
6885
|
+
return { supersede: decision.targetId, content: decision.content };
|
|
6886
|
+
}
|
|
6844
6887
|
if (decision.action === "noop" && decision.targetId) {
|
|
6845
6888
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
6846
|
-
if (!existing) return null;
|
|
6889
|
+
if (!existing || existing.supersededBy) return null;
|
|
6847
6890
|
const mergedSourceIds = unionStrings(
|
|
6848
6891
|
existing.sourceChunkIds ?? [],
|
|
6849
6892
|
options.sourceChunkIds ?? []
|
|
@@ -6861,15 +6904,17 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
6861
6904
|
return null;
|
|
6862
6905
|
}
|
|
6863
6906
|
return {
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6907
|
+
done: {
|
|
6908
|
+
action: "merge",
|
|
6909
|
+
memoryId: decision.targetId,
|
|
6910
|
+
targetId: decision.targetId,
|
|
6911
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
6912
|
+
}
|
|
6868
6913
|
};
|
|
6869
6914
|
}
|
|
6870
6915
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
6871
6916
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
6872
|
-
if (!existing) return null;
|
|
6917
|
+
if (!existing || existing.supersededBy) return null;
|
|
6873
6918
|
const mergedSourceIds = unionStrings(
|
|
6874
6919
|
existing.sourceChunkIds ?? [],
|
|
6875
6920
|
options.sourceChunkIds ?? []
|
|
@@ -6896,10 +6941,12 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
6896
6941
|
}
|
|
6897
6942
|
ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
|
|
6898
6943
|
return {
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6944
|
+
done: {
|
|
6945
|
+
action: "update",
|
|
6946
|
+
memoryId: decision.targetId,
|
|
6947
|
+
targetId: decision.targetId,
|
|
6948
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
6949
|
+
}
|
|
6903
6950
|
};
|
|
6904
6951
|
}
|
|
6905
6952
|
return null;
|
|
@@ -12187,7 +12234,7 @@ __decorateClass([
|
|
|
12187
12234
|
], VaultFolder.prototype, "context", 2);
|
|
12188
12235
|
|
|
12189
12236
|
// src/lib/db/schema.ts
|
|
12190
|
-
var SDK_SCHEMA_VERSION =
|
|
12237
|
+
var SDK_SCHEMA_VERSION = 38;
|
|
12191
12238
|
var sdkSchema = appSchema2({
|
|
12192
12239
|
version: SDK_SCHEMA_VERSION,
|
|
12193
12240
|
tables: [
|
|
@@ -12312,7 +12359,20 @@ var sdkSchema = appSchema2({
|
|
|
12312
12359
|
// Unix ms of the last LLM topic-extraction pass over this memory's
|
|
12313
12360
|
// content. Null = never extracted standalone (legacy rows with entity
|
|
12314
12361
|
// links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
|
|
12315
|
-
{ name: "topics_extracted_at", type: "number", isOptional: true }
|
|
12362
|
+
{ name: "topics_extracted_at", type: "number", isOptional: true },
|
|
12363
|
+
// Write-time supersession (A2). When set, this fact was replaced by a
|
|
12364
|
+
// newer, incompatible-value fact (e.g. "Lives in Portland" superseded by
|
|
12365
|
+
// "Lives in SF"); `superseded_by` points at the newer memory's id and
|
|
12366
|
+
// `superseded_at` is the Unix ms it happened. Superseded rows stay in
|
|
12367
|
+
// the table (history / read-time fallback) but are excluded from recall
|
|
12368
|
+
// and dedup by default. Null = live (not superseded). Indexed so the
|
|
12369
|
+
// recall filter stays cheap.
|
|
12370
|
+
{ name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
|
|
12371
|
+
{ name: "superseded_at", type: "number", isOptional: true },
|
|
12372
|
+
// The extraction-logic version this memory was last stamped under. Null
|
|
12373
|
+
// (pre-v38) is treated as version 0, so a bump of TOPICS_EXTRACTION_VERSION
|
|
12374
|
+
// re-extracts stale rows. See getMemoriesNeedingTopicExtractionOp.
|
|
12375
|
+
{ name: "topics_extracted_version", type: "number", isOptional: true }
|
|
12316
12376
|
]
|
|
12317
12377
|
}),
|
|
12318
12378
|
// Entity table — canonical names extracted from auto-extraction (W5).
|
|
@@ -12923,6 +12983,34 @@ var sdkMigrations = schemaMigrations2({
|
|
|
12923
12983
|
columns: [{ name: "topics_extracted_at", type: "number", isOptional: true }]
|
|
12924
12984
|
})
|
|
12925
12985
|
]
|
|
12986
|
+
},
|
|
12987
|
+
// v36 -> v37: write-time supersession columns on memory_vault. Existing rows
|
|
12988
|
+
// keep both NULL (= live / not superseded), so no backfill — legacy
|
|
12989
|
+
// contradictory rows are handled by the read-time supersession fallback.
|
|
12990
|
+
{
|
|
12991
|
+
toVersion: 37,
|
|
12992
|
+
steps: [
|
|
12993
|
+
addColumns2({
|
|
12994
|
+
table: "memory_vault",
|
|
12995
|
+
columns: [
|
|
12996
|
+
{ name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
|
|
12997
|
+
{ name: "superseded_at", type: "number", isOptional: true }
|
|
12998
|
+
]
|
|
12999
|
+
})
|
|
13000
|
+
]
|
|
13001
|
+
},
|
|
13002
|
+
// v37 -> v38: topics_extracted_version on memory_vault. Existing rows keep it
|
|
13003
|
+
// NULL, read as version 0 by getMemoriesNeedingTopicExtractionOp — so the
|
|
13004
|
+
// first sweep after a TOPICS_EXTRACTION_VERSION bump re-extracts them (drained
|
|
13005
|
+
// across sweeps by the worker's limit). See topicExtract.ts.
|
|
13006
|
+
{
|
|
13007
|
+
toVersion: 38,
|
|
13008
|
+
steps: [
|
|
13009
|
+
addColumns2({
|
|
13010
|
+
table: "memory_vault",
|
|
13011
|
+
columns: [{ name: "topics_extracted_version", type: "number", isOptional: true }]
|
|
13012
|
+
})
|
|
13013
|
+
]
|
|
12926
13014
|
}
|
|
12927
13015
|
]
|
|
12928
13016
|
});
|
|
@@ -22578,6 +22666,7 @@ export {
|
|
|
22578
22666
|
VaultMemory as StoredVaultMemoryModel,
|
|
22579
22667
|
StreamExpiredError,
|
|
22580
22668
|
THEME_ATTRS,
|
|
22669
|
+
TOPICS_EXTRACTION_VERSION,
|
|
22581
22670
|
TOPIC_EXTRACTION_BATCH_SIZE,
|
|
22582
22671
|
TextProcessor,
|
|
22583
22672
|
UIInteractionProvider,
|
|
@@ -22854,6 +22943,7 @@ export {
|
|
|
22854
22943
|
storeNotionReturnUrl,
|
|
22855
22944
|
streamCancelPath,
|
|
22856
22945
|
streamReplayPath,
|
|
22946
|
+
supersedeVaultMemoryOp,
|
|
22857
22947
|
updateAttrs,
|
|
22858
22948
|
updateConversationProjectOp,
|
|
22859
22949
|
updateMediaMessageIdBatchOp,
|
|
@@ -16057,6 +16057,7 @@ function isOwnedByCtxUser(ctx, record) {
|
|
|
16057
16057
|
function baseVaultConditions(ctx, options) {
|
|
16058
16058
|
return [
|
|
16059
16059
|
...options?.includeDeleted ? [] : [import_watermelondb3.Q.where("is_deleted", false)],
|
|
16060
|
+
...options?.includeSuperseded ? [] : [import_watermelondb3.Q.where("superseded_by", null)],
|
|
16060
16061
|
...ctx.userId !== void 0 ? [import_watermelondb3.Q.where("user_id", ctx.userId)] : [],
|
|
16061
16062
|
...options?.since ? [import_watermelondb3.Q.where("updated_at", import_watermelondb3.Q.gt(options.since.getTime()))] : []
|
|
16062
16063
|
];
|
|
@@ -16097,6 +16098,9 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
16097
16098
|
eventTimeKind: memory.eventTimeKind ?? null,
|
|
16098
16099
|
topicsUserManaged: memory.topicsUserManaged ?? false,
|
|
16099
16100
|
topicsExtractedAt: memory.topicsExtractedAt ?? null,
|
|
16101
|
+
topicsExtractedVersion: memory.topicsExtractedVersion ?? null,
|
|
16102
|
+
supersededBy: memory.supersededBy ?? null,
|
|
16103
|
+
supersededAt: memory.supersededAt ?? null,
|
|
16100
16104
|
createdAt: memory.createdAt,
|
|
16101
16105
|
updatedAt: memory.updatedAt,
|
|
16102
16106
|
isDeleted: memory.isDeleted
|
|
@@ -16142,6 +16146,59 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
16142
16146
|
});
|
|
16143
16147
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
16144
16148
|
}
|
|
16149
|
+
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
16150
|
+
if (!targetId) return { created: null, retired: false };
|
|
16151
|
+
const scope = opts.scope ?? "private";
|
|
16152
|
+
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
16153
|
+
opts.content,
|
|
16154
|
+
ctx.walletAddress,
|
|
16155
|
+
ctx.signMessage,
|
|
16156
|
+
ctx.embeddedWalletSigner
|
|
16157
|
+
) : opts.content;
|
|
16158
|
+
let createdRecord = null;
|
|
16159
|
+
await ctx.database.write(async () => {
|
|
16160
|
+
let target;
|
|
16161
|
+
try {
|
|
16162
|
+
target = await ctx.vaultMemoryCollection.find(targetId);
|
|
16163
|
+
} catch {
|
|
16164
|
+
return;
|
|
16165
|
+
}
|
|
16166
|
+
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
16167
|
+
createdRecord = await ctx.vaultMemoryCollection.create((record) => {
|
|
16168
|
+
record._setRaw("content", encryptedContent);
|
|
16169
|
+
record._setRaw("scope", scope);
|
|
16170
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
16171
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
16172
|
+
record._setRaw("is_deleted", false);
|
|
16173
|
+
if (opts.embedding !== void 0) {
|
|
16174
|
+
record._setRaw("embedding", opts.embedding);
|
|
16175
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
16176
|
+
}
|
|
16177
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
16178
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
16179
|
+
}
|
|
16180
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
16181
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
16182
|
+
if (opts.eventTime) {
|
|
16183
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
16184
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
16185
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
16186
|
+
}
|
|
16187
|
+
});
|
|
16188
|
+
await target.update((r) => {
|
|
16189
|
+
r._setRaw("superseded_by", createdRecord.id);
|
|
16190
|
+
r._setRaw("superseded_at", Date.now());
|
|
16191
|
+
});
|
|
16192
|
+
});
|
|
16193
|
+
if (!createdRecord) return { created: null, retired: false };
|
|
16194
|
+
const created = await vaultMemoryToStored(
|
|
16195
|
+
createdRecord,
|
|
16196
|
+
ctx.walletAddress,
|
|
16197
|
+
ctx.signMessage,
|
|
16198
|
+
ctx.embeddedWalletSigner
|
|
16199
|
+
);
|
|
16200
|
+
return { created, retired: true };
|
|
16201
|
+
}
|
|
16145
16202
|
async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
|
|
16146
16203
|
const records = await ctx.vaultMemoryCollection.query(
|
|
16147
16204
|
...baseVaultConditions(ctx),
|
|
@@ -16281,6 +16338,9 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
16281
16338
|
// SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
|
|
16282
16339
|
topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
|
|
16283
16340
|
topicsExtractedAt: raw.topics_extracted_at ?? null,
|
|
16341
|
+
topicsExtractedVersion: raw.topics_extracted_version ?? null,
|
|
16342
|
+
supersededBy: raw.superseded_by ?? null,
|
|
16343
|
+
supersededAt: raw.superseded_at ?? null,
|
|
16284
16344
|
createdAt: new Date(raw.created_at),
|
|
16285
16345
|
updatedAt: new Date(raw.updated_at),
|
|
16286
16346
|
isDeleted: raw.is_deleted === true || raw.is_deleted === 1
|
|
@@ -16322,7 +16382,7 @@ async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
|
16322
16382
|
async function updateVaultMemoryOp(ctx, id, opts) {
|
|
16323
16383
|
try {
|
|
16324
16384
|
const probe = await ctx.vaultMemoryCollection.find(id);
|
|
16325
|
-
if (probe.isDeleted || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
16385
|
+
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
16326
16386
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
16327
16387
|
opts.content,
|
|
16328
16388
|
ctx.walletAddress,
|
|
@@ -16333,7 +16393,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
16333
16393
|
const record = probe;
|
|
16334
16394
|
const originalUpdatedAt = record.updatedAt.getTime();
|
|
16335
16395
|
await ctx.database.write(async () => {
|
|
16336
|
-
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
16396
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
|
|
16337
16397
|
stale = true;
|
|
16338
16398
|
return;
|
|
16339
16399
|
}
|
|
@@ -16411,6 +16471,40 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
16411
16471
|
return false;
|
|
16412
16472
|
}
|
|
16413
16473
|
}
|
|
16474
|
+
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
16475
|
+
if (id === supersededById) return false;
|
|
16476
|
+
try {
|
|
16477
|
+
const record = await ctx.vaultMemoryCollection.find(id);
|
|
16478
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) return false;
|
|
16479
|
+
let successor;
|
|
16480
|
+
try {
|
|
16481
|
+
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
16482
|
+
} catch {
|
|
16483
|
+
return false;
|
|
16484
|
+
}
|
|
16485
|
+
if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
|
|
16486
|
+
return false;
|
|
16487
|
+
}
|
|
16488
|
+
let stale = false;
|
|
16489
|
+
await ctx.database.write(async () => {
|
|
16490
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
|
|
16491
|
+
stale = true;
|
|
16492
|
+
return;
|
|
16493
|
+
}
|
|
16494
|
+
if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
|
|
16495
|
+
stale = true;
|
|
16496
|
+
return;
|
|
16497
|
+
}
|
|
16498
|
+
await record.update((r) => {
|
|
16499
|
+
r._setRaw("superseded_by", supersededById);
|
|
16500
|
+
r._setRaw("superseded_at", Date.now());
|
|
16501
|
+
});
|
|
16502
|
+
});
|
|
16503
|
+
return !stale;
|
|
16504
|
+
} catch {
|
|
16505
|
+
return false;
|
|
16506
|
+
}
|
|
16507
|
+
}
|
|
16414
16508
|
async function getUnfiledVaultMemoriesOp(ctx) {
|
|
16415
16509
|
const conditions = [
|
|
16416
16510
|
import_watermelondb3.Q.where("folder_id", null),
|
|
@@ -16423,6 +16517,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
16423
16517
|
(record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
16424
16518
|
);
|
|
16425
16519
|
}
|
|
16520
|
+
var TOPICS_EXTRACTION_VERSION = 1;
|
|
16426
16521
|
async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
16427
16522
|
const entityCtx = ctx.entityCtx;
|
|
16428
16523
|
if (!entityCtx) {
|
|
@@ -16441,7 +16536,10 @@ async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
|
16441
16536
|
for (const raw of rows) {
|
|
16442
16537
|
const stamp = raw.topics_extracted_at ?? null;
|
|
16443
16538
|
if (stamp !== null) {
|
|
16444
|
-
|
|
16539
|
+
const version = raw.topics_extracted_version ?? 0;
|
|
16540
|
+
if (raw.updated_at > stamp || version < TOPICS_EXTRACTION_VERSION) {
|
|
16541
|
+
stampedPending.push(raw);
|
|
16542
|
+
}
|
|
16445
16543
|
} else {
|
|
16446
16544
|
unstamped.push(raw);
|
|
16447
16545
|
}
|
|
@@ -16471,7 +16569,7 @@ async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
|
16471
16569
|
);
|
|
16472
16570
|
return { pending, linkedUnstamped };
|
|
16473
16571
|
}
|
|
16474
|
-
async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt) {
|
|
16572
|
+
async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = TOPICS_EXTRACTION_VERSION) {
|
|
16475
16573
|
if (memoryIds.length === 0) return [];
|
|
16476
16574
|
const uniqueIds = Array.from(new Set(memoryIds));
|
|
16477
16575
|
const CHUNK = 500;
|
|
@@ -16494,6 +16592,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt) {
|
|
|
16494
16592
|
prepared.push(
|
|
16495
16593
|
record.prepareUpdate((r) => {
|
|
16496
16594
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
16595
|
+
r._setRaw("topics_extracted_version", version);
|
|
16497
16596
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
16498
16597
|
})
|
|
16499
16598
|
);
|
|
@@ -19108,7 +19207,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
19108
19207
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
19109
19208
|
);
|
|
19110
19209
|
}
|
|
19111
|
-
const { recall: recall2 } = await import("./recall-
|
|
19210
|
+
const { recall: recall2 } = await import("./recall-CQT24XLH.mjs");
|
|
19112
19211
|
const result = await recall2(
|
|
19113
19212
|
query,
|
|
19114
19213
|
{ vaultCtx, embeddingOptions, vaultCache: cache },
|
|
@@ -19797,13 +19896,16 @@ export {
|
|
|
19797
19896
|
replaceMemoryEntitiesGuardedOp,
|
|
19798
19897
|
vaultMemoryToStored,
|
|
19799
19898
|
createVaultMemoryOp,
|
|
19899
|
+
createSupersedingMemoryOp,
|
|
19800
19900
|
createVaultMemoriesBatchOp,
|
|
19801
19901
|
getVaultMemoryOp,
|
|
19802
19902
|
getAllVaultMemoriesOp,
|
|
19803
19903
|
getAllVaultMemoryContentsOp,
|
|
19804
19904
|
updateVaultMemoryOp,
|
|
19805
19905
|
deleteVaultMemoryOp,
|
|
19906
|
+
supersedeVaultMemoryOp,
|
|
19806
19907
|
getUnfiledVaultMemoriesOp,
|
|
19908
|
+
TOPICS_EXTRACTION_VERSION,
|
|
19807
19909
|
getMemoriesNeedingTopicExtractionOp,
|
|
19808
19910
|
stampTopicsExtractedAtOp,
|
|
19809
19911
|
deleteAllVaultMemoriesForUserOp,
|
|
@@ -15,10 +15,11 @@ var SYSTEM_PROMPT = `You consolidate a new memory against existing memories from
|
|
|
15
15
|
|
|
16
16
|
A "memory" is a self-contained natural-language fact about the user. Multiple memories about the same EXACT FACET (the same dimension of the same subject) should never coexist \u2014 they should be merged into one. Different facets on the same subject (e.g. user's dog's name vs user's dog's age) are SEPARATE memories.
|
|
17
17
|
|
|
18
|
-
Decide one of
|
|
18
|
+
Decide one of four actions:
|
|
19
19
|
|
|
20
20
|
- "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
|
|
21
|
-
- "update": the new memory describes the SAME FACET as exactly one existing memory
|
|
21
|
+
- "update": the new memory describes the SAME FACET as exactly one existing memory and is COMPATIBLE with it \u2014 it adds detail, fixes an incomplete value, or rephrases the same still-true fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
|
|
22
|
+
- "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return targetId of the STALE existing memory to retire + content = the NEW fact. The old memory is kept as history, not overwritten or deleted; do not re-state it.
|
|
22
23
|
- "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
|
|
23
24
|
|
|
24
25
|
RULES (carry these strictly):
|
|
@@ -26,18 +27,21 @@ RULES (carry these strictly):
|
|
|
26
27
|
1. ONE OBSERVATION PER DISTINCT FACET. If the new memory is about "user's aunt's twins" and an existing memory is also about "user's aunt's twins", they are the same facet \u2192 update, never create.
|
|
27
28
|
2. MATCH BY FACET, NOT TOPIC. Two memories both mentioning "Zara" is not enough to merge \u2014 only merge if they describe the same property (e.g. both about "user's pending Zara boot exchange"). Two memories about Zara on different topics (e.g. "user shops at Zara" + "user returned a sweater to Zara last week") are separate facets.
|
|
28
29
|
3. NO COMPUTATION. Do not sum counts, decrement quantities, or derive new facts from existing ones. If the new memory says "user spent $200 today" and an existing memory says "user spent $150 yesterday", these are TWO SEPARATE EVENTS \u2014 create.
|
|
29
|
-
4.
|
|
30
|
-
|
|
30
|
+
4. EVENTS vs STANDING STATE.
|
|
31
|
+
- Distinct EVENTS (episodic \u2014 something that happened on a date) are separate memories, even if the same activity: "user went to gym Monday" vs "user went to gym Friday" \u2192 create; keep both.
|
|
32
|
+
- A STANDING ATTRIBUTE (an ongoing state: where the user lives/works, relationship status, current role) has ONE current value. When the new memory changes that value ("Lives in Portland" \u2192 "Lives in San Francisco"; "Works at Google" \u2192 "Works at Riverbend"; "Engaged" \u2192 "Broke up"), the old value is no longer true \u2192 supersede (retire the old, record the new). Do NOT create (that leaves a stale contradiction) and do NOT update (that erases the history that the old value was once true).
|
|
33
|
+
5. When in doubt between create and update, choose create \u2014 EXCEPT when the new memory directly contradicts the current value of a standing attribute in an existing memory; then choose supersede. Over-merging loses information; a live contradiction is worse than either.
|
|
31
34
|
|
|
32
35
|
OUTPUT \u2014 strict JSON, no prose:
|
|
33
36
|
{
|
|
34
|
-
"action": "create" | "update" | "noop",
|
|
35
|
-
"targetId": "<existing memory id
|
|
36
|
-
"content": "<
|
|
37
|
+
"action": "create" | "update" | "supersede" | "noop",
|
|
38
|
+
"targetId": "<existing memory id \u2014 required for update/supersede/noop, omit for create>",
|
|
39
|
+
"content": "<content \u2014 required for create/update/supersede, omit for noop>"
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
For "create": content is the new memory verbatim (or a slight refinement).
|
|
40
43
|
For "update": content is the merged richest-version, \u226480 words.
|
|
44
|
+
For "supersede": content is the NEW fact only (\u226480 words); targetId is the stale memory being retired.
|
|
41
45
|
For "noop": no content (existing memory is already correct).`;
|
|
42
46
|
async function consolidateMemory(newContent, candidates, options) {
|
|
43
47
|
const fallback = {
|
|
@@ -112,7 +116,9 @@ function validate(parsed, newContent, validIds) {
|
|
|
112
116
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
113
117
|
const obj = parsed;
|
|
114
118
|
const action = obj.action;
|
|
115
|
-
if (action !== "create" && action !== "update" && action !== "noop")
|
|
119
|
+
if (action !== "create" && action !== "update" && action !== "noop" && action !== "supersede") {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
116
122
|
if (action === "create") {
|
|
117
123
|
const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
118
124
|
return { action: "create", content: c2.length > 0 ? c2 : newContent };
|
|
@@ -124,7 +130,7 @@ function validate(parsed, newContent, validIds) {
|
|
|
124
130
|
}
|
|
125
131
|
const c = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
126
132
|
if (c.length === 0) return null;
|
|
127
|
-
return { action
|
|
133
|
+
return { action, targetId, content: c };
|
|
128
134
|
}
|
|
129
135
|
export {
|
|
130
136
|
consolidateMemory
|