@anuma/sdk 2.4.2 → 2.5.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-A26RBLTJ.mjs} +97 -3
- package/dist/expo/{consolidate-HEMQGOUD.mjs → consolidate-3QQPUWD6.mjs} +15 -9
- package/dist/expo/index.cjs +232 -67
- package/dist/expo/index.d.mts +44 -7
- package/dist/expo/index.d.ts +44 -7
- package/dist/expo/index.mjs +126 -58
- package/dist/{react/recall-G3CS444F.mjs → expo/recall-JC5GF5CX.mjs} +1 -1
- package/dist/react/{chunk-IYDQBFS2.mjs → chunk-V5GC3ES7.mjs} +97 -3
- package/dist/react/{consolidate-IJH7LD2T.mjs → consolidate-3MXZV3G7.mjs} +15 -9
- package/dist/react/index.cjs +232 -67
- package/dist/react/index.d.mts +44 -7
- package/dist/react/index.d.ts +44 -7
- package/dist/react/index.mjs +126 -58
- package/dist/{expo/recall-HI7VO3VM.mjs → react/recall-IRTSMKYI.mjs} +1 -1
- package/dist/server/{chunk-3MLG7SUH.mjs → chunk-TWWLE6P3.mjs} +97 -3
- package/dist/server/{consolidate-TDT4HRHG.mjs → consolidate-CN2GQV4D.mjs} +15 -9
- package/dist/server/index.cjs +232 -67
- package/dist/server/index.d.mts +44 -7
- package/dist/server/index.d.ts +44 -7
- package/dist/server/index.mjs +126 -58
- package/dist/server/{recall-MJHGXMHZ.mjs → recall-44FIK2MJ.mjs} +1 -1
- package/package.json +1 -1
|
@@ -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
|
package/dist/react/index.cjs
CHANGED
|
@@ -4403,6 +4403,7 @@ function isOwnedByCtxUser(ctx, record) {
|
|
|
4403
4403
|
function baseVaultConditions(ctx, options) {
|
|
4404
4404
|
return [
|
|
4405
4405
|
...options?.includeDeleted ? [] : [import_watermelondb10.Q.where("is_deleted", false)],
|
|
4406
|
+
...options?.includeSuperseded ? [] : [import_watermelondb10.Q.where("superseded_by", null)],
|
|
4406
4407
|
...ctx.userId !== void 0 ? [import_watermelondb10.Q.where("user_id", ctx.userId)] : [],
|
|
4407
4408
|
...options?.since ? [import_watermelondb10.Q.where("updated_at", import_watermelondb10.Q.gt(options.since.getTime()))] : []
|
|
4408
4409
|
];
|
|
@@ -4443,6 +4444,8 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
4443
4444
|
eventTimeKind: memory.eventTimeKind ?? null,
|
|
4444
4445
|
topicsUserManaged: memory.topicsUserManaged ?? false,
|
|
4445
4446
|
topicsExtractedAt: memory.topicsExtractedAt ?? null,
|
|
4447
|
+
supersededBy: memory.supersededBy ?? null,
|
|
4448
|
+
supersededAt: memory.supersededAt ?? null,
|
|
4446
4449
|
createdAt: memory.createdAt,
|
|
4447
4450
|
updatedAt: memory.updatedAt,
|
|
4448
4451
|
isDeleted: memory.isDeleted
|
|
@@ -4488,6 +4491,59 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
4488
4491
|
});
|
|
4489
4492
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
4490
4493
|
}
|
|
4494
|
+
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
4495
|
+
if (!targetId) return { created: null, retired: false };
|
|
4496
|
+
const scope = opts.scope ?? "private";
|
|
4497
|
+
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
4498
|
+
opts.content,
|
|
4499
|
+
ctx.walletAddress,
|
|
4500
|
+
ctx.signMessage,
|
|
4501
|
+
ctx.embeddedWalletSigner
|
|
4502
|
+
) : opts.content;
|
|
4503
|
+
let createdRecord = null;
|
|
4504
|
+
await ctx.database.write(async () => {
|
|
4505
|
+
let target;
|
|
4506
|
+
try {
|
|
4507
|
+
target = await ctx.vaultMemoryCollection.find(targetId);
|
|
4508
|
+
} catch {
|
|
4509
|
+
return;
|
|
4510
|
+
}
|
|
4511
|
+
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
4512
|
+
createdRecord = await ctx.vaultMemoryCollection.create((record) => {
|
|
4513
|
+
record._setRaw("content", encryptedContent);
|
|
4514
|
+
record._setRaw("scope", scope);
|
|
4515
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
4516
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
4517
|
+
record._setRaw("is_deleted", false);
|
|
4518
|
+
if (opts.embedding !== void 0) {
|
|
4519
|
+
record._setRaw("embedding", opts.embedding);
|
|
4520
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
4521
|
+
}
|
|
4522
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
4523
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
4524
|
+
}
|
|
4525
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
4526
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
4527
|
+
if (opts.eventTime) {
|
|
4528
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
4529
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
4530
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
4531
|
+
}
|
|
4532
|
+
});
|
|
4533
|
+
await target.update((r) => {
|
|
4534
|
+
r._setRaw("superseded_by", createdRecord.id);
|
|
4535
|
+
r._setRaw("superseded_at", Date.now());
|
|
4536
|
+
});
|
|
4537
|
+
});
|
|
4538
|
+
if (!createdRecord) return { created: null, retired: false };
|
|
4539
|
+
const created = await vaultMemoryToStored(
|
|
4540
|
+
createdRecord,
|
|
4541
|
+
ctx.walletAddress,
|
|
4542
|
+
ctx.signMessage,
|
|
4543
|
+
ctx.embeddedWalletSigner
|
|
4544
|
+
);
|
|
4545
|
+
return { created, retired: true };
|
|
4546
|
+
}
|
|
4491
4547
|
async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
|
|
4492
4548
|
const records = await ctx.vaultMemoryCollection.query(
|
|
4493
4549
|
...baseVaultConditions(ctx),
|
|
@@ -4627,6 +4683,8 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
4627
4683
|
// SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
|
|
4628
4684
|
topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
|
|
4629
4685
|
topicsExtractedAt: raw.topics_extracted_at ?? null,
|
|
4686
|
+
supersededBy: raw.superseded_by ?? null,
|
|
4687
|
+
supersededAt: raw.superseded_at ?? null,
|
|
4630
4688
|
createdAt: new Date(raw.created_at),
|
|
4631
4689
|
updatedAt: new Date(raw.updated_at),
|
|
4632
4690
|
isDeleted: raw.is_deleted === true || raw.is_deleted === 1
|
|
@@ -4668,7 +4726,7 @@ async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
|
4668
4726
|
async function updateVaultMemoryOp(ctx, id, opts) {
|
|
4669
4727
|
try {
|
|
4670
4728
|
const probe = await ctx.vaultMemoryCollection.find(id);
|
|
4671
|
-
if (probe.isDeleted || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
4729
|
+
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
4672
4730
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
4673
4731
|
opts.content,
|
|
4674
4732
|
ctx.walletAddress,
|
|
@@ -4679,7 +4737,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
4679
4737
|
const record = probe;
|
|
4680
4738
|
const originalUpdatedAt = record.updatedAt.getTime();
|
|
4681
4739
|
await ctx.database.write(async () => {
|
|
4682
|
-
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
4740
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
|
|
4683
4741
|
stale = true;
|
|
4684
4742
|
return;
|
|
4685
4743
|
}
|
|
@@ -4811,6 +4869,40 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
4811
4869
|
return false;
|
|
4812
4870
|
}
|
|
4813
4871
|
}
|
|
4872
|
+
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
4873
|
+
if (id === supersededById) return false;
|
|
4874
|
+
try {
|
|
4875
|
+
const record = await ctx.vaultMemoryCollection.find(id);
|
|
4876
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) return false;
|
|
4877
|
+
let successor;
|
|
4878
|
+
try {
|
|
4879
|
+
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
4880
|
+
} catch {
|
|
4881
|
+
return false;
|
|
4882
|
+
}
|
|
4883
|
+
if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
|
|
4884
|
+
return false;
|
|
4885
|
+
}
|
|
4886
|
+
let stale = false;
|
|
4887
|
+
await ctx.database.write(async () => {
|
|
4888
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
|
|
4889
|
+
stale = true;
|
|
4890
|
+
return;
|
|
4891
|
+
}
|
|
4892
|
+
if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
|
|
4893
|
+
stale = true;
|
|
4894
|
+
return;
|
|
4895
|
+
}
|
|
4896
|
+
await record.update((r) => {
|
|
4897
|
+
r._setRaw("superseded_by", supersededById);
|
|
4898
|
+
r._setRaw("superseded_at", Date.now());
|
|
4899
|
+
});
|
|
4900
|
+
});
|
|
4901
|
+
return !stale;
|
|
4902
|
+
} catch {
|
|
4903
|
+
return false;
|
|
4904
|
+
}
|
|
4905
|
+
}
|
|
4814
4906
|
async function getUnfiledVaultMemoriesOp(ctx) {
|
|
4815
4907
|
const conditions = [
|
|
4816
4908
|
import_watermelondb10.Q.where("folder_id", null),
|
|
@@ -7228,7 +7320,9 @@ function validate2(parsed, newContent, validIds) {
|
|
|
7228
7320
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
7229
7321
|
const obj = parsed;
|
|
7230
7322
|
const action = obj.action;
|
|
7231
|
-
if (action !== "create" && action !== "update" && action !== "noop")
|
|
7323
|
+
if (action !== "create" && action !== "update" && action !== "noop" && action !== "supersede") {
|
|
7324
|
+
return null;
|
|
7325
|
+
}
|
|
7232
7326
|
if (action === "create") {
|
|
7233
7327
|
const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
7234
7328
|
return { action: "create", content: c2.length > 0 ? c2 : newContent };
|
|
@@ -7240,7 +7334,7 @@ function validate2(parsed, newContent, validIds) {
|
|
|
7240
7334
|
}
|
|
7241
7335
|
const c = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
7242
7336
|
if (c.length === 0) return null;
|
|
7243
|
-
return { action
|
|
7337
|
+
return { action, targetId, content: c };
|
|
7244
7338
|
}
|
|
7245
7339
|
var DEFAULT_MODEL2, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS, SYSTEM_PROMPT2;
|
|
7246
7340
|
var init_consolidate = __esm({
|
|
@@ -7256,10 +7350,11 @@ var init_consolidate = __esm({
|
|
|
7256
7350
|
|
|
7257
7351
|
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.
|
|
7258
7352
|
|
|
7259
|
-
Decide one of
|
|
7353
|
+
Decide one of four actions:
|
|
7260
7354
|
|
|
7261
7355
|
- "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
|
|
7262
|
-
- "update": the new memory describes the SAME FACET as exactly one existing memory
|
|
7356
|
+
- "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).
|
|
7357
|
+
- "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.
|
|
7263
7358
|
- "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
|
|
7264
7359
|
|
|
7265
7360
|
RULES (carry these strictly):
|
|
@@ -7267,18 +7362,21 @@ RULES (carry these strictly):
|
|
|
7267
7362
|
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.
|
|
7268
7363
|
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.
|
|
7269
7364
|
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.
|
|
7270
|
-
4.
|
|
7271
|
-
|
|
7365
|
+
4. EVENTS vs STANDING STATE.
|
|
7366
|
+
- 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.
|
|
7367
|
+
- 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).
|
|
7368
|
+
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.
|
|
7272
7369
|
|
|
7273
7370
|
OUTPUT \u2014 strict JSON, no prose:
|
|
7274
7371
|
{
|
|
7275
|
-
"action": "create" | "update" | "noop",
|
|
7276
|
-
"targetId": "<existing memory id
|
|
7277
|
-
"content": "<
|
|
7372
|
+
"action": "create" | "update" | "supersede" | "noop",
|
|
7373
|
+
"targetId": "<existing memory id \u2014 required for update/supersede/noop, omit for create>",
|
|
7374
|
+
"content": "<content \u2014 required for create/update/supersede, omit for noop>"
|
|
7278
7375
|
}
|
|
7279
7376
|
|
|
7280
7377
|
For "create": content is the new memory verbatim (or a slight refinement).
|
|
7281
7378
|
For "update": content is the merged richest-version, \u226480 words.
|
|
7379
|
+
For "supersede": content is the NEW fact only (\u226480 words); targetId is the stale memory being retired.
|
|
7282
7380
|
For "noop": no content (existing memory is already correct).`;
|
|
7283
7381
|
}
|
|
7284
7382
|
});
|
|
@@ -7633,6 +7731,7 @@ __export(index_exports, {
|
|
|
7633
7731
|
storeNotionReturnUrl: () => storeNotionReturnUrl,
|
|
7634
7732
|
streamCancelPath: () => streamCancelPath,
|
|
7635
7733
|
streamReplayPath: () => streamReplayPath,
|
|
7734
|
+
supersedeVaultMemoryOp: () => supersedeVaultMemoryOp,
|
|
7636
7735
|
updateAttrs: () => updateAttrs,
|
|
7637
7736
|
updateConversationProjectOp: () => updateConversationProjectOp,
|
|
7638
7737
|
updateMediaMessageIdBatchOp: () => updateMediaMessageIdBatchOp,
|
|
@@ -14234,6 +14333,12 @@ __decorateClass([
|
|
|
14234
14333
|
__decorateClass([
|
|
14235
14334
|
(0, import_decorators3.field)("topics_extracted_at")
|
|
14236
14335
|
], VaultMemory.prototype, "topicsExtractedAt", 2);
|
|
14336
|
+
__decorateClass([
|
|
14337
|
+
(0, import_decorators3.field)("superseded_by")
|
|
14338
|
+
], VaultMemory.prototype, "supersededBy", 2);
|
|
14339
|
+
__decorateClass([
|
|
14340
|
+
(0, import_decorators3.field)("superseded_at")
|
|
14341
|
+
], VaultMemory.prototype, "supersededAt", 2);
|
|
14237
14342
|
__decorateClass([
|
|
14238
14343
|
import_decorators3.readonly,
|
|
14239
14344
|
(0, import_decorators3.date)("created_at")
|
|
@@ -14277,53 +14382,62 @@ async function retain(content, ctx, options = {}) {
|
|
|
14277
14382
|
const enableAutoMerge = options.enableAutoMerge ?? true;
|
|
14278
14383
|
const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
|
|
14279
14384
|
const resolvedScope = options.scope ?? DEFAULT_SCOPE;
|
|
14385
|
+
let supersedeTargetId;
|
|
14386
|
+
let supersedeContent;
|
|
14280
14387
|
if (enableAutoMerge) {
|
|
14281
14388
|
if (options.consolidateOptions) {
|
|
14282
|
-
const
|
|
14283
|
-
if (
|
|
14284
|
-
|
|
14285
|
-
|
|
14286
|
-
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
|
|
14304
|
-
|
|
14305
|
-
);
|
|
14306
|
-
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
|
|
14310
|
-
|
|
14311
|
-
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
|
|
14315
|
-
|
|
14316
|
-
|
|
14317
|
-
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
14389
|
+
const outcome = await tryConsolidate(trimmed, ctx, options);
|
|
14390
|
+
if (outcome) {
|
|
14391
|
+
if ("done" in outcome) return outcome.done;
|
|
14392
|
+
supersedeTargetId = outcome.supersede;
|
|
14393
|
+
supersedeContent = outcome.content;
|
|
14394
|
+
}
|
|
14395
|
+
}
|
|
14396
|
+
if (!supersedeTargetId) {
|
|
14397
|
+
const matches = await searchVaultMemories(
|
|
14398
|
+
trimmed,
|
|
14399
|
+
ctx.vaultCtx,
|
|
14400
|
+
ctx.embeddingOptions,
|
|
14401
|
+
ctx.vaultCache,
|
|
14402
|
+
{
|
|
14403
|
+
limit: 1,
|
|
14404
|
+
minSimilarity: threshold,
|
|
14405
|
+
useFusion: false,
|
|
14406
|
+
scopes: [resolvedScope],
|
|
14407
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
14408
|
+
}
|
|
14409
|
+
);
|
|
14410
|
+
if (matches.length > 0) {
|
|
14411
|
+
const targetId = matches[0].uniqueId;
|
|
14412
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
|
|
14413
|
+
if (existing && !existing.supersededBy) {
|
|
14414
|
+
const mergedSourceIds = unionStrings(
|
|
14415
|
+
existing.sourceChunkIds ?? [],
|
|
14416
|
+
options.sourceChunkIds ?? []
|
|
14417
|
+
);
|
|
14418
|
+
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
14419
|
+
const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
|
|
14420
|
+
content: existing.content,
|
|
14421
|
+
proofCountIncrement: 1,
|
|
14422
|
+
sourceChunkIds: mergedSourceIds,
|
|
14423
|
+
preserveUpdatedAt: true,
|
|
14424
|
+
...eventTimeUpdate && { eventTime: eventTimeUpdate }
|
|
14425
|
+
});
|
|
14426
|
+
if (updated) {
|
|
14427
|
+
return {
|
|
14428
|
+
action: "merge",
|
|
14429
|
+
memoryId: targetId,
|
|
14430
|
+
targetId,
|
|
14431
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
14432
|
+
};
|
|
14433
|
+
}
|
|
14434
|
+
await assertMergeTargetGoneOrThrow(ctx, targetId);
|
|
14321
14435
|
}
|
|
14322
|
-
await assertMergeTargetGoneOrThrow(ctx, targetId);
|
|
14323
14436
|
}
|
|
14324
14437
|
}
|
|
14325
14438
|
}
|
|
14326
|
-
const
|
|
14439
|
+
const contentToWrite = supersedeContent ?? trimmed;
|
|
14440
|
+
const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
14327
14441
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
14328
14442
|
if (options.respectTombstones) {
|
|
14329
14443
|
const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -14334,8 +14448,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
14334
14448
|
return { action: "suppressed", memoryId: tombstoneId, tombstoneId, proofCount: 0 };
|
|
14335
14449
|
}
|
|
14336
14450
|
}
|
|
14337
|
-
const
|
|
14338
|
-
content:
|
|
14451
|
+
const createOpts = {
|
|
14452
|
+
content: contentToWrite,
|
|
14339
14453
|
scope: resolvedScope,
|
|
14340
14454
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
14341
14455
|
embedding: JSON.stringify(embedding),
|
|
@@ -14352,7 +14466,24 @@ async function retain(content, ctx, options = {}) {
|
|
|
14352
14466
|
kind: options.eventTime.kind
|
|
14353
14467
|
}
|
|
14354
14468
|
}
|
|
14355
|
-
}
|
|
14469
|
+
};
|
|
14470
|
+
if (supersedeTargetId) {
|
|
14471
|
+
const { created: created2, retired } = await createSupersedingMemoryOp(
|
|
14472
|
+
ctx.vaultCtx,
|
|
14473
|
+
createOpts,
|
|
14474
|
+
supersedeTargetId
|
|
14475
|
+
);
|
|
14476
|
+
if (created2 && retired) {
|
|
14477
|
+
ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
|
|
14478
|
+
return {
|
|
14479
|
+
action: "supersede",
|
|
14480
|
+
memoryId: created2.uniqueId,
|
|
14481
|
+
targetId: supersedeTargetId,
|
|
14482
|
+
proofCount: 1
|
|
14483
|
+
};
|
|
14484
|
+
}
|
|
14485
|
+
}
|
|
14486
|
+
const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
|
|
14356
14487
|
ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
|
|
14357
14488
|
return {
|
|
14358
14489
|
action: "create",
|
|
@@ -14422,9 +14553,14 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
14422
14553
|
const { consolidateMemory: doConsolidate } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
|
|
14423
14554
|
const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
|
|
14424
14555
|
if (decision.action === "create") return null;
|
|
14556
|
+
if (decision.action === "supersede" && decision.targetId && decision.content) {
|
|
14557
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
14558
|
+
if (!existing || existing.supersededBy) return null;
|
|
14559
|
+
return { supersede: decision.targetId, content: decision.content };
|
|
14560
|
+
}
|
|
14425
14561
|
if (decision.action === "noop" && decision.targetId) {
|
|
14426
14562
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
14427
|
-
if (!existing) return null;
|
|
14563
|
+
if (!existing || existing.supersededBy) return null;
|
|
14428
14564
|
const mergedSourceIds = unionStrings(
|
|
14429
14565
|
existing.sourceChunkIds ?? [],
|
|
14430
14566
|
options.sourceChunkIds ?? []
|
|
@@ -14442,15 +14578,17 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
14442
14578
|
return null;
|
|
14443
14579
|
}
|
|
14444
14580
|
return {
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14581
|
+
done: {
|
|
14582
|
+
action: "merge",
|
|
14583
|
+
memoryId: decision.targetId,
|
|
14584
|
+
targetId: decision.targetId,
|
|
14585
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
14586
|
+
}
|
|
14449
14587
|
};
|
|
14450
14588
|
}
|
|
14451
14589
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
14452
14590
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
14453
|
-
if (!existing) return null;
|
|
14591
|
+
if (!existing || existing.supersededBy) return null;
|
|
14454
14592
|
const mergedSourceIds = unionStrings(
|
|
14455
14593
|
existing.sourceChunkIds ?? [],
|
|
14456
14594
|
options.sourceChunkIds ?? []
|
|
@@ -14477,10 +14615,12 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
14477
14615
|
}
|
|
14478
14616
|
ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
|
|
14479
14617
|
return {
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14483
|
-
|
|
14618
|
+
done: {
|
|
14619
|
+
action: "update",
|
|
14620
|
+
memoryId: decision.targetId,
|
|
14621
|
+
targetId: decision.targetId,
|
|
14622
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
14623
|
+
}
|
|
14484
14624
|
};
|
|
14485
14625
|
}
|
|
14486
14626
|
return null;
|
|
@@ -19817,7 +19957,7 @@ __decorateClass([
|
|
|
19817
19957
|
], VaultFolder.prototype, "context", 2);
|
|
19818
19958
|
|
|
19819
19959
|
// src/lib/db/schema.ts
|
|
19820
|
-
var SDK_SCHEMA_VERSION =
|
|
19960
|
+
var SDK_SCHEMA_VERSION = 37;
|
|
19821
19961
|
var sdkSchema = (0, import_watermelondb20.appSchema)({
|
|
19822
19962
|
version: SDK_SCHEMA_VERSION,
|
|
19823
19963
|
tables: [
|
|
@@ -19942,7 +20082,16 @@ var sdkSchema = (0, import_watermelondb20.appSchema)({
|
|
|
19942
20082
|
// Unix ms of the last LLM topic-extraction pass over this memory's
|
|
19943
20083
|
// content. Null = never extracted standalone (legacy rows with entity
|
|
19944
20084
|
// links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
|
|
19945
|
-
{ name: "topics_extracted_at", type: "number", isOptional: true }
|
|
20085
|
+
{ name: "topics_extracted_at", type: "number", isOptional: true },
|
|
20086
|
+
// Write-time supersession (A2). When set, this fact was replaced by a
|
|
20087
|
+
// newer, incompatible-value fact (e.g. "Lives in Portland" superseded by
|
|
20088
|
+
// "Lives in SF"); `superseded_by` points at the newer memory's id and
|
|
20089
|
+
// `superseded_at` is the Unix ms it happened. Superseded rows stay in
|
|
20090
|
+
// the table (history / read-time fallback) but are excluded from recall
|
|
20091
|
+
// and dedup by default. Null = live (not superseded). Indexed so the
|
|
20092
|
+
// recall filter stays cheap.
|
|
20093
|
+
{ name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
|
|
20094
|
+
{ name: "superseded_at", type: "number", isOptional: true }
|
|
19946
20095
|
]
|
|
19947
20096
|
}),
|
|
19948
20097
|
// Entity table — canonical names extracted from auto-extraction (W5).
|
|
@@ -20553,6 +20702,21 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
20553
20702
|
columns: [{ name: "topics_extracted_at", type: "number", isOptional: true }]
|
|
20554
20703
|
})
|
|
20555
20704
|
]
|
|
20705
|
+
},
|
|
20706
|
+
// v36 -> v37: write-time supersession columns on memory_vault. Existing rows
|
|
20707
|
+
// keep both NULL (= live / not superseded), so no backfill — legacy
|
|
20708
|
+
// contradictory rows are handled by the read-time supersession fallback.
|
|
20709
|
+
{
|
|
20710
|
+
toVersion: 37,
|
|
20711
|
+
steps: [
|
|
20712
|
+
(0, import_migrations2.addColumns)({
|
|
20713
|
+
table: "memory_vault",
|
|
20714
|
+
columns: [
|
|
20715
|
+
{ name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
|
|
20716
|
+
{ name: "superseded_at", type: "number", isOptional: true }
|
|
20717
|
+
]
|
|
20718
|
+
})
|
|
20719
|
+
]
|
|
20556
20720
|
}
|
|
20557
20721
|
]
|
|
20558
20722
|
});
|
|
@@ -30509,6 +30673,7 @@ function renderAnumaJsx(jsx3) {
|
|
|
30509
30673
|
storeNotionReturnUrl,
|
|
30510
30674
|
streamCancelPath,
|
|
30511
30675
|
streamReplayPath,
|
|
30676
|
+
supersedeVaultMemoryOp,
|
|
30512
30677
|
updateAttrs,
|
|
30513
30678
|
updateConversationProjectOp,
|
|
30514
30679
|
updateMediaMessageIdBatchOp,
|