@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/expo/index.cjs
CHANGED
|
@@ -4125,6 +4125,7 @@ function isOwnedByCtxUser(ctx, record) {
|
|
|
4125
4125
|
function baseVaultConditions(ctx, options) {
|
|
4126
4126
|
return [
|
|
4127
4127
|
...options?.includeDeleted ? [] : [import_watermelondb9.Q.where("is_deleted", false)],
|
|
4128
|
+
...options?.includeSuperseded ? [] : [import_watermelondb9.Q.where("superseded_by", null)],
|
|
4128
4129
|
...ctx.userId !== void 0 ? [import_watermelondb9.Q.where("user_id", ctx.userId)] : [],
|
|
4129
4130
|
...options?.since ? [import_watermelondb9.Q.where("updated_at", import_watermelondb9.Q.gt(options.since.getTime()))] : []
|
|
4130
4131
|
];
|
|
@@ -4165,6 +4166,9 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
4165
4166
|
eventTimeKind: memory.eventTimeKind ?? null,
|
|
4166
4167
|
topicsUserManaged: memory.topicsUserManaged ?? false,
|
|
4167
4168
|
topicsExtractedAt: memory.topicsExtractedAt ?? null,
|
|
4169
|
+
topicsExtractedVersion: memory.topicsExtractedVersion ?? null,
|
|
4170
|
+
supersededBy: memory.supersededBy ?? null,
|
|
4171
|
+
supersededAt: memory.supersededAt ?? null,
|
|
4168
4172
|
createdAt: memory.createdAt,
|
|
4169
4173
|
updatedAt: memory.updatedAt,
|
|
4170
4174
|
isDeleted: memory.isDeleted
|
|
@@ -4210,6 +4214,59 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
4210
4214
|
});
|
|
4211
4215
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
4212
4216
|
}
|
|
4217
|
+
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
4218
|
+
if (!targetId) return { created: null, retired: false };
|
|
4219
|
+
const scope = opts.scope ?? "private";
|
|
4220
|
+
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
4221
|
+
opts.content,
|
|
4222
|
+
ctx.walletAddress,
|
|
4223
|
+
ctx.signMessage,
|
|
4224
|
+
ctx.embeddedWalletSigner
|
|
4225
|
+
) : opts.content;
|
|
4226
|
+
let createdRecord = null;
|
|
4227
|
+
await ctx.database.write(async () => {
|
|
4228
|
+
let target;
|
|
4229
|
+
try {
|
|
4230
|
+
target = await ctx.vaultMemoryCollection.find(targetId);
|
|
4231
|
+
} catch {
|
|
4232
|
+
return;
|
|
4233
|
+
}
|
|
4234
|
+
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
4235
|
+
createdRecord = await ctx.vaultMemoryCollection.create((record) => {
|
|
4236
|
+
record._setRaw("content", encryptedContent);
|
|
4237
|
+
record._setRaw("scope", scope);
|
|
4238
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
4239
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
4240
|
+
record._setRaw("is_deleted", false);
|
|
4241
|
+
if (opts.embedding !== void 0) {
|
|
4242
|
+
record._setRaw("embedding", opts.embedding);
|
|
4243
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
4244
|
+
}
|
|
4245
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
4246
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
4247
|
+
}
|
|
4248
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
4249
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
4250
|
+
if (opts.eventTime) {
|
|
4251
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
4252
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
4253
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
4254
|
+
}
|
|
4255
|
+
});
|
|
4256
|
+
await target.update((r) => {
|
|
4257
|
+
r._setRaw("superseded_by", createdRecord.id);
|
|
4258
|
+
r._setRaw("superseded_at", Date.now());
|
|
4259
|
+
});
|
|
4260
|
+
});
|
|
4261
|
+
if (!createdRecord) return { created: null, retired: false };
|
|
4262
|
+
const created = await vaultMemoryToStored(
|
|
4263
|
+
createdRecord,
|
|
4264
|
+
ctx.walletAddress,
|
|
4265
|
+
ctx.signMessage,
|
|
4266
|
+
ctx.embeddedWalletSigner
|
|
4267
|
+
);
|
|
4268
|
+
return { created, retired: true };
|
|
4269
|
+
}
|
|
4213
4270
|
async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
|
|
4214
4271
|
const records = await ctx.vaultMemoryCollection.query(
|
|
4215
4272
|
...baseVaultConditions(ctx),
|
|
@@ -4349,6 +4406,9 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
4349
4406
|
// SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
|
|
4350
4407
|
topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
|
|
4351
4408
|
topicsExtractedAt: raw.topics_extracted_at ?? null,
|
|
4409
|
+
topicsExtractedVersion: raw.topics_extracted_version ?? null,
|
|
4410
|
+
supersededBy: raw.superseded_by ?? null,
|
|
4411
|
+
supersededAt: raw.superseded_at ?? null,
|
|
4352
4412
|
createdAt: new Date(raw.created_at),
|
|
4353
4413
|
updatedAt: new Date(raw.updated_at),
|
|
4354
4414
|
isDeleted: raw.is_deleted === true || raw.is_deleted === 1
|
|
@@ -4390,7 +4450,7 @@ async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
|
4390
4450
|
async function updateVaultMemoryOp(ctx, id, opts) {
|
|
4391
4451
|
try {
|
|
4392
4452
|
const probe = await ctx.vaultMemoryCollection.find(id);
|
|
4393
|
-
if (probe.isDeleted || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
4453
|
+
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
4394
4454
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
4395
4455
|
opts.content,
|
|
4396
4456
|
ctx.walletAddress,
|
|
@@ -4401,7 +4461,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
4401
4461
|
const record = probe;
|
|
4402
4462
|
const originalUpdatedAt = record.updatedAt.getTime();
|
|
4403
4463
|
await ctx.database.write(async () => {
|
|
4404
|
-
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
4464
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
|
|
4405
4465
|
stale = true;
|
|
4406
4466
|
return;
|
|
4407
4467
|
}
|
|
@@ -4479,6 +4539,40 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
4479
4539
|
return false;
|
|
4480
4540
|
}
|
|
4481
4541
|
}
|
|
4542
|
+
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
4543
|
+
if (id === supersededById) return false;
|
|
4544
|
+
try {
|
|
4545
|
+
const record = await ctx.vaultMemoryCollection.find(id);
|
|
4546
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) return false;
|
|
4547
|
+
let successor;
|
|
4548
|
+
try {
|
|
4549
|
+
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
4550
|
+
} catch {
|
|
4551
|
+
return false;
|
|
4552
|
+
}
|
|
4553
|
+
if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
|
|
4554
|
+
return false;
|
|
4555
|
+
}
|
|
4556
|
+
let stale = false;
|
|
4557
|
+
await ctx.database.write(async () => {
|
|
4558
|
+
if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
|
|
4559
|
+
stale = true;
|
|
4560
|
+
return;
|
|
4561
|
+
}
|
|
4562
|
+
if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
|
|
4563
|
+
stale = true;
|
|
4564
|
+
return;
|
|
4565
|
+
}
|
|
4566
|
+
await record.update((r) => {
|
|
4567
|
+
r._setRaw("superseded_by", supersededById);
|
|
4568
|
+
r._setRaw("superseded_at", Date.now());
|
|
4569
|
+
});
|
|
4570
|
+
});
|
|
4571
|
+
return !stale;
|
|
4572
|
+
} catch {
|
|
4573
|
+
return false;
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4482
4576
|
async function getUnfiledVaultMemoriesOp(ctx) {
|
|
4483
4577
|
const conditions = [
|
|
4484
4578
|
import_watermelondb9.Q.where("folder_id", null),
|
|
@@ -4509,7 +4603,10 @@ async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
|
4509
4603
|
for (const raw of rows) {
|
|
4510
4604
|
const stamp = raw.topics_extracted_at ?? null;
|
|
4511
4605
|
if (stamp !== null) {
|
|
4512
|
-
|
|
4606
|
+
const version = raw.topics_extracted_version ?? 0;
|
|
4607
|
+
if (raw.updated_at > stamp || version < TOPICS_EXTRACTION_VERSION) {
|
|
4608
|
+
stampedPending.push(raw);
|
|
4609
|
+
}
|
|
4513
4610
|
} else {
|
|
4514
4611
|
unstamped.push(raw);
|
|
4515
4612
|
}
|
|
@@ -4539,7 +4636,7 @@ async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
|
4539
4636
|
);
|
|
4540
4637
|
return { pending, linkedUnstamped };
|
|
4541
4638
|
}
|
|
4542
|
-
async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt) {
|
|
4639
|
+
async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = TOPICS_EXTRACTION_VERSION) {
|
|
4543
4640
|
if (memoryIds.length === 0) return [];
|
|
4544
4641
|
const uniqueIds = Array.from(new Set(memoryIds));
|
|
4545
4642
|
const CHUNK = 500;
|
|
@@ -4562,6 +4659,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt) {
|
|
|
4562
4659
|
prepared.push(
|
|
4563
4660
|
record.prepareUpdate((r) => {
|
|
4564
4661
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
4662
|
+
r._setRaw("topics_extracted_version", version);
|
|
4565
4663
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
4566
4664
|
})
|
|
4567
4665
|
);
|
|
@@ -4614,13 +4712,14 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel)
|
|
|
4614
4712
|
return false;
|
|
4615
4713
|
}
|
|
4616
4714
|
}
|
|
4617
|
-
var import_watermelondb9;
|
|
4715
|
+
var import_watermelondb9, TOPICS_EXTRACTION_VERSION;
|
|
4618
4716
|
var init_operations3 = __esm({
|
|
4619
4717
|
"src/lib/db/memoryVault/operations.ts"() {
|
|
4620
4718
|
"use strict";
|
|
4621
4719
|
import_watermelondb9 = require("@nozbe/watermelondb");
|
|
4622
4720
|
init_operations2();
|
|
4623
4721
|
init_encryption2();
|
|
4722
|
+
TOPICS_EXTRACTION_VERSION = 1;
|
|
4624
4723
|
}
|
|
4625
4724
|
});
|
|
4626
4725
|
|
|
@@ -6896,7 +6995,9 @@ function validate2(parsed, newContent, validIds) {
|
|
|
6896
6995
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
6897
6996
|
const obj = parsed;
|
|
6898
6997
|
const action = obj.action;
|
|
6899
|
-
if (action !== "create" && action !== "update" && action !== "noop")
|
|
6998
|
+
if (action !== "create" && action !== "update" && action !== "noop" && action !== "supersede") {
|
|
6999
|
+
return null;
|
|
7000
|
+
}
|
|
6900
7001
|
if (action === "create") {
|
|
6901
7002
|
const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
6902
7003
|
return { action: "create", content: c2.length > 0 ? c2 : newContent };
|
|
@@ -6908,7 +7009,7 @@ function validate2(parsed, newContent, validIds) {
|
|
|
6908
7009
|
}
|
|
6909
7010
|
const c = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
6910
7011
|
if (c.length === 0) return null;
|
|
6911
|
-
return { action
|
|
7012
|
+
return { action, targetId, content: c };
|
|
6912
7013
|
}
|
|
6913
7014
|
var DEFAULT_MODEL2, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS, SYSTEM_PROMPT2;
|
|
6914
7015
|
var init_consolidate = __esm({
|
|
@@ -6924,10 +7025,11 @@ var init_consolidate = __esm({
|
|
|
6924
7025
|
|
|
6925
7026
|
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.
|
|
6926
7027
|
|
|
6927
|
-
Decide one of
|
|
7028
|
+
Decide one of four actions:
|
|
6928
7029
|
|
|
6929
7030
|
- "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
|
|
6930
|
-
- "update": the new memory describes the SAME FACET as exactly one existing memory
|
|
7031
|
+
- "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).
|
|
7032
|
+
- "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.
|
|
6931
7033
|
- "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
|
|
6932
7034
|
|
|
6933
7035
|
RULES (carry these strictly):
|
|
@@ -6935,18 +7037,21 @@ RULES (carry these strictly):
|
|
|
6935
7037
|
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.
|
|
6936
7038
|
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.
|
|
6937
7039
|
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.
|
|
6938
|
-
4.
|
|
6939
|
-
|
|
7040
|
+
4. EVENTS vs STANDING STATE.
|
|
7041
|
+
- 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.
|
|
7042
|
+
- 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).
|
|
7043
|
+
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.
|
|
6940
7044
|
|
|
6941
7045
|
OUTPUT \u2014 strict JSON, no prose:
|
|
6942
7046
|
{
|
|
6943
|
-
"action": "create" | "update" | "noop",
|
|
6944
|
-
"targetId": "<existing memory id
|
|
6945
|
-
"content": "<
|
|
7047
|
+
"action": "create" | "update" | "supersede" | "noop",
|
|
7048
|
+
"targetId": "<existing memory id \u2014 required for update/supersede/noop, omit for create>",
|
|
7049
|
+
"content": "<content \u2014 required for create/update/supersede, omit for noop>"
|
|
6946
7050
|
}
|
|
6947
7051
|
|
|
6948
7052
|
For "create": content is the new memory verbatim (or a slight refinement).
|
|
6949
7053
|
For "update": content is the merged richest-version, \u226480 words.
|
|
7054
|
+
For "supersede": content is the NEW fact only (\u226480 words); targetId is the stale memory being retired.
|
|
6950
7055
|
For "noop": no content (existing memory is already correct).`;
|
|
6951
7056
|
}
|
|
6952
7057
|
});
|
|
@@ -6978,6 +7083,7 @@ __export(index_exports, {
|
|
|
6978
7083
|
StoredVaultFolderModel: () => VaultFolder,
|
|
6979
7084
|
StoredVaultMemoryModel: () => VaultMemory,
|
|
6980
7085
|
StreamExpiredError: () => StreamExpiredError,
|
|
7086
|
+
TOPICS_EXTRACTION_VERSION: () => TOPICS_EXTRACTION_VERSION,
|
|
6981
7087
|
TOPIC_EXTRACTION_BATCH_SIZE: () => TOPIC_EXTRACTION_BATCH_SIZE,
|
|
6982
7088
|
WalletPoller: () => WalletPoller,
|
|
6983
7089
|
addConversationMemoriesOp: () => addConversationMemoriesOp,
|
|
@@ -7079,6 +7185,7 @@ __export(index_exports, {
|
|
|
7079
7185
|
stampTopicsExtractedAtOp: () => stampTopicsExtractedAtOp,
|
|
7080
7186
|
streamCancelPath: () => streamCancelPath,
|
|
7081
7187
|
streamReplayPath: () => streamReplayPath,
|
|
7188
|
+
supersedeVaultMemoryOp: () => supersedeVaultMemoryOp,
|
|
7082
7189
|
updateVaultFolderContextOp: () => updateVaultFolderContextOp,
|
|
7083
7190
|
updateVaultFolderOp: () => updateVaultFolderOp,
|
|
7084
7191
|
updateVaultMemoryEmbeddingOp: () => updateVaultMemoryEmbeddingOp,
|
|
@@ -12543,6 +12650,15 @@ __decorateClass([
|
|
|
12543
12650
|
__decorateClass([
|
|
12544
12651
|
(0, import_decorators3.field)("topics_extracted_at")
|
|
12545
12652
|
], VaultMemory.prototype, "topicsExtractedAt", 2);
|
|
12653
|
+
__decorateClass([
|
|
12654
|
+
(0, import_decorators3.field)("superseded_by")
|
|
12655
|
+
], VaultMemory.prototype, "supersededBy", 2);
|
|
12656
|
+
__decorateClass([
|
|
12657
|
+
(0, import_decorators3.field)("superseded_at")
|
|
12658
|
+
], VaultMemory.prototype, "supersededAt", 2);
|
|
12659
|
+
__decorateClass([
|
|
12660
|
+
(0, import_decorators3.field)("topics_extracted_version")
|
|
12661
|
+
], VaultMemory.prototype, "topicsExtractedVersion", 2);
|
|
12546
12662
|
__decorateClass([
|
|
12547
12663
|
import_decorators3.readonly,
|
|
12548
12664
|
(0, import_decorators3.date)("created_at")
|
|
@@ -12926,53 +13042,62 @@ async function retain(content, ctx, options = {}) {
|
|
|
12926
13042
|
const enableAutoMerge = options.enableAutoMerge ?? true;
|
|
12927
13043
|
const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
|
|
12928
13044
|
const resolvedScope = options.scope ?? DEFAULT_SCOPE;
|
|
13045
|
+
let supersedeTargetId;
|
|
13046
|
+
let supersedeContent;
|
|
12929
13047
|
if (enableAutoMerge) {
|
|
12930
13048
|
if (options.consolidateOptions) {
|
|
12931
|
-
const
|
|
12932
|
-
if (
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
|
|
12952
|
-
|
|
12953
|
-
|
|
12954
|
-
);
|
|
12955
|
-
|
|
12956
|
-
|
|
12957
|
-
|
|
12958
|
-
|
|
12959
|
-
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
13049
|
+
const outcome = await tryConsolidate(trimmed, ctx, options);
|
|
13050
|
+
if (outcome) {
|
|
13051
|
+
if ("done" in outcome) return outcome.done;
|
|
13052
|
+
supersedeTargetId = outcome.supersede;
|
|
13053
|
+
supersedeContent = outcome.content;
|
|
13054
|
+
}
|
|
13055
|
+
}
|
|
13056
|
+
if (!supersedeTargetId) {
|
|
13057
|
+
const matches = await searchVaultMemories(
|
|
13058
|
+
trimmed,
|
|
13059
|
+
ctx.vaultCtx,
|
|
13060
|
+
ctx.embeddingOptions,
|
|
13061
|
+
ctx.vaultCache,
|
|
13062
|
+
{
|
|
13063
|
+
limit: 1,
|
|
13064
|
+
minSimilarity: threshold,
|
|
13065
|
+
useFusion: false,
|
|
13066
|
+
scopes: [resolvedScope],
|
|
13067
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
13068
|
+
}
|
|
13069
|
+
);
|
|
13070
|
+
if (matches.length > 0) {
|
|
13071
|
+
const targetId = matches[0].uniqueId;
|
|
13072
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
|
|
13073
|
+
if (existing && !existing.supersededBy) {
|
|
13074
|
+
const mergedSourceIds = unionStrings(
|
|
13075
|
+
existing.sourceChunkIds ?? [],
|
|
13076
|
+
options.sourceChunkIds ?? []
|
|
13077
|
+
);
|
|
13078
|
+
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
13079
|
+
const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
|
|
13080
|
+
content: existing.content,
|
|
13081
|
+
proofCountIncrement: 1,
|
|
13082
|
+
sourceChunkIds: mergedSourceIds,
|
|
13083
|
+
preserveUpdatedAt: true,
|
|
13084
|
+
...eventTimeUpdate && { eventTime: eventTimeUpdate }
|
|
13085
|
+
});
|
|
13086
|
+
if (updated) {
|
|
13087
|
+
return {
|
|
13088
|
+
action: "merge",
|
|
13089
|
+
memoryId: targetId,
|
|
13090
|
+
targetId,
|
|
13091
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
13092
|
+
};
|
|
13093
|
+
}
|
|
13094
|
+
await assertMergeTargetGoneOrThrow(ctx, targetId);
|
|
12970
13095
|
}
|
|
12971
|
-
await assertMergeTargetGoneOrThrow(ctx, targetId);
|
|
12972
13096
|
}
|
|
12973
13097
|
}
|
|
12974
13098
|
}
|
|
12975
|
-
const
|
|
13099
|
+
const contentToWrite = supersedeContent ?? trimmed;
|
|
13100
|
+
const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
12976
13101
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
12977
13102
|
if (options.respectTombstones) {
|
|
12978
13103
|
const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -12983,8 +13108,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
12983
13108
|
return { action: "suppressed", memoryId: tombstoneId, tombstoneId, proofCount: 0 };
|
|
12984
13109
|
}
|
|
12985
13110
|
}
|
|
12986
|
-
const
|
|
12987
|
-
content:
|
|
13111
|
+
const createOpts = {
|
|
13112
|
+
content: contentToWrite,
|
|
12988
13113
|
scope: resolvedScope,
|
|
12989
13114
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
12990
13115
|
embedding: JSON.stringify(embedding),
|
|
@@ -13001,7 +13126,24 @@ async function retain(content, ctx, options = {}) {
|
|
|
13001
13126
|
kind: options.eventTime.kind
|
|
13002
13127
|
}
|
|
13003
13128
|
}
|
|
13004
|
-
}
|
|
13129
|
+
};
|
|
13130
|
+
if (supersedeTargetId) {
|
|
13131
|
+
const { created: created2, retired } = await createSupersedingMemoryOp(
|
|
13132
|
+
ctx.vaultCtx,
|
|
13133
|
+
createOpts,
|
|
13134
|
+
supersedeTargetId
|
|
13135
|
+
);
|
|
13136
|
+
if (created2 && retired) {
|
|
13137
|
+
ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
|
|
13138
|
+
return {
|
|
13139
|
+
action: "supersede",
|
|
13140
|
+
memoryId: created2.uniqueId,
|
|
13141
|
+
targetId: supersedeTargetId,
|
|
13142
|
+
proofCount: 1
|
|
13143
|
+
};
|
|
13144
|
+
}
|
|
13145
|
+
}
|
|
13146
|
+
const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
|
|
13005
13147
|
ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
|
|
13006
13148
|
return {
|
|
13007
13149
|
action: "create",
|
|
@@ -13071,9 +13213,14 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
13071
13213
|
const { consolidateMemory: doConsolidate } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
|
|
13072
13214
|
const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
|
|
13073
13215
|
if (decision.action === "create") return null;
|
|
13216
|
+
if (decision.action === "supersede" && decision.targetId && decision.content) {
|
|
13217
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
13218
|
+
if (!existing || existing.supersededBy) return null;
|
|
13219
|
+
return { supersede: decision.targetId, content: decision.content };
|
|
13220
|
+
}
|
|
13074
13221
|
if (decision.action === "noop" && decision.targetId) {
|
|
13075
13222
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
13076
|
-
if (!existing) return null;
|
|
13223
|
+
if (!existing || existing.supersededBy) return null;
|
|
13077
13224
|
const mergedSourceIds = unionStrings(
|
|
13078
13225
|
existing.sourceChunkIds ?? [],
|
|
13079
13226
|
options.sourceChunkIds ?? []
|
|
@@ -13091,15 +13238,17 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
13091
13238
|
return null;
|
|
13092
13239
|
}
|
|
13093
13240
|
return {
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13241
|
+
done: {
|
|
13242
|
+
action: "merge",
|
|
13243
|
+
memoryId: decision.targetId,
|
|
13244
|
+
targetId: decision.targetId,
|
|
13245
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
13246
|
+
}
|
|
13098
13247
|
};
|
|
13099
13248
|
}
|
|
13100
13249
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
13101
13250
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
13102
|
-
if (!existing) return null;
|
|
13251
|
+
if (!existing || existing.supersededBy) return null;
|
|
13103
13252
|
const mergedSourceIds = unionStrings(
|
|
13104
13253
|
existing.sourceChunkIds ?? [],
|
|
13105
13254
|
options.sourceChunkIds ?? []
|
|
@@ -13126,10 +13275,12 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
13126
13275
|
}
|
|
13127
13276
|
ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
|
|
13128
13277
|
return {
|
|
13129
|
-
|
|
13130
|
-
|
|
13131
|
-
|
|
13132
|
-
|
|
13278
|
+
done: {
|
|
13279
|
+
action: "update",
|
|
13280
|
+
memoryId: decision.targetId,
|
|
13281
|
+
targetId: decision.targetId,
|
|
13282
|
+
proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
|
|
13283
|
+
}
|
|
13133
13284
|
};
|
|
13134
13285
|
}
|
|
13135
13286
|
return null;
|
|
@@ -16624,7 +16775,7 @@ __decorateClass([
|
|
|
16624
16775
|
], VaultFolder.prototype, "context", 2);
|
|
16625
16776
|
|
|
16626
16777
|
// src/lib/db/schema.ts
|
|
16627
|
-
var SDK_SCHEMA_VERSION =
|
|
16778
|
+
var SDK_SCHEMA_VERSION = 38;
|
|
16628
16779
|
var sdkSchema = (0, import_watermelondb19.appSchema)({
|
|
16629
16780
|
version: SDK_SCHEMA_VERSION,
|
|
16630
16781
|
tables: [
|
|
@@ -16749,7 +16900,20 @@ var sdkSchema = (0, import_watermelondb19.appSchema)({
|
|
|
16749
16900
|
// Unix ms of the last LLM topic-extraction pass over this memory's
|
|
16750
16901
|
// content. Null = never extracted standalone (legacy rows with entity
|
|
16751
16902
|
// links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
|
|
16752
|
-
{ name: "topics_extracted_at", type: "number", isOptional: true }
|
|
16903
|
+
{ name: "topics_extracted_at", type: "number", isOptional: true },
|
|
16904
|
+
// Write-time supersession (A2). When set, this fact was replaced by a
|
|
16905
|
+
// newer, incompatible-value fact (e.g. "Lives in Portland" superseded by
|
|
16906
|
+
// "Lives in SF"); `superseded_by` points at the newer memory's id and
|
|
16907
|
+
// `superseded_at` is the Unix ms it happened. Superseded rows stay in
|
|
16908
|
+
// the table (history / read-time fallback) but are excluded from recall
|
|
16909
|
+
// and dedup by default. Null = live (not superseded). Indexed so the
|
|
16910
|
+
// recall filter stays cheap.
|
|
16911
|
+
{ name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
|
|
16912
|
+
{ name: "superseded_at", type: "number", isOptional: true },
|
|
16913
|
+
// The extraction-logic version this memory was last stamped under. Null
|
|
16914
|
+
// (pre-v38) is treated as version 0, so a bump of TOPICS_EXTRACTION_VERSION
|
|
16915
|
+
// re-extracts stale rows. See getMemoriesNeedingTopicExtractionOp.
|
|
16916
|
+
{ name: "topics_extracted_version", type: "number", isOptional: true }
|
|
16753
16917
|
]
|
|
16754
16918
|
}),
|
|
16755
16919
|
// Entity table — canonical names extracted from auto-extraction (W5).
|
|
@@ -17360,6 +17524,34 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
17360
17524
|
columns: [{ name: "topics_extracted_at", type: "number", isOptional: true }]
|
|
17361
17525
|
})
|
|
17362
17526
|
]
|
|
17527
|
+
},
|
|
17528
|
+
// v36 -> v37: write-time supersession columns on memory_vault. Existing rows
|
|
17529
|
+
// keep both NULL (= live / not superseded), so no backfill — legacy
|
|
17530
|
+
// contradictory rows are handled by the read-time supersession fallback.
|
|
17531
|
+
{
|
|
17532
|
+
toVersion: 37,
|
|
17533
|
+
steps: [
|
|
17534
|
+
(0, import_migrations2.addColumns)({
|
|
17535
|
+
table: "memory_vault",
|
|
17536
|
+
columns: [
|
|
17537
|
+
{ name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
|
|
17538
|
+
{ name: "superseded_at", type: "number", isOptional: true }
|
|
17539
|
+
]
|
|
17540
|
+
})
|
|
17541
|
+
]
|
|
17542
|
+
},
|
|
17543
|
+
// v37 -> v38: topics_extracted_version on memory_vault. Existing rows keep it
|
|
17544
|
+
// NULL, read as version 0 by getMemoriesNeedingTopicExtractionOp — so the
|
|
17545
|
+
// first sweep after a TOPICS_EXTRACTION_VERSION bump re-extracts them (drained
|
|
17546
|
+
// across sweeps by the worker's limit). See topicExtract.ts.
|
|
17547
|
+
{
|
|
17548
|
+
toVersion: 38,
|
|
17549
|
+
steps: [
|
|
17550
|
+
(0, import_migrations2.addColumns)({
|
|
17551
|
+
table: "memory_vault",
|
|
17552
|
+
columns: [{ name: "topics_extracted_version", type: "number", isOptional: true }]
|
|
17553
|
+
})
|
|
17554
|
+
]
|
|
17363
17555
|
}
|
|
17364
17556
|
]
|
|
17365
17557
|
});
|
|
@@ -18724,6 +18916,7 @@ function createNotionTools(getAccessToken, requestNotionAccess) {
|
|
|
18724
18916
|
StoredVaultFolderModel,
|
|
18725
18917
|
StoredVaultMemoryModel,
|
|
18726
18918
|
StreamExpiredError,
|
|
18919
|
+
TOPICS_EXTRACTION_VERSION,
|
|
18727
18920
|
TOPIC_EXTRACTION_BATCH_SIZE,
|
|
18728
18921
|
WalletPoller,
|
|
18729
18922
|
addConversationMemoriesOp,
|
|
@@ -18825,6 +19018,7 @@ function createNotionTools(getAccessToken, requestNotionAccess) {
|
|
|
18825
19018
|
stampTopicsExtractedAtOp,
|
|
18826
19019
|
streamCancelPath,
|
|
18827
19020
|
streamReplayPath,
|
|
19021
|
+
supersedeVaultMemoryOp,
|
|
18828
19022
|
updateVaultFolderContextOp,
|
|
18829
19023
|
updateVaultFolderOp,
|
|
18830
19024
|
updateVaultMemoryEmbeddingOp,
|