@anuma/sdk 7.4.0 → 7.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/index.cjs +172 -10
- package/dist/expo/index.d.mts +46 -1
- package/dist/expo/index.d.ts +46 -1
- package/dist/expo/index.mjs +172 -10
- package/dist/react/index.cjs +172 -10
- package/dist/react/index.d.mts +46 -1
- package/dist/react/index.d.ts +46 -1
- package/dist/react/index.mjs +172 -10
- package/dist/server/index.cjs +72 -10
- package/dist/server/index.d.mts +46 -1
- package/dist/server/index.d.ts +46 -1
- package/dist/server/index.mjs +72 -10
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -20671,6 +20671,8 @@ var MAX_QUERY_TOPICS = 100;
|
|
|
20671
20671
|
var MAX_QUERY_FILTER = 20;
|
|
20672
20672
|
var GRAPH_LANE_ROWS = 256;
|
|
20673
20673
|
var TEMPORAL_LANE_ROWS = 256;
|
|
20674
|
+
var REPAIR_ROWS = 50;
|
|
20675
|
+
var REPAIR_SCAN = 2e3;
|
|
20674
20676
|
var DECAY_TRANSITIONS_PER_SWEEP = 200;
|
|
20675
20677
|
var RemoteMemoryPartialCreateError = class extends Error {
|
|
20676
20678
|
constructor(created, cause) {
|
|
@@ -20680,6 +20682,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
|
|
|
20680
20682
|
this.name = "RemoteMemoryPartialCreateError";
|
|
20681
20683
|
}
|
|
20682
20684
|
};
|
|
20685
|
+
function rejectsInput(error) {
|
|
20686
|
+
return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
|
|
20687
|
+
}
|
|
20683
20688
|
function warnFailed(failed) {
|
|
20684
20689
|
if (failed.length)
|
|
20685
20690
|
getLogger().warn(
|
|
@@ -21296,9 +21301,104 @@ function createRemoteMemoryStore(options) {
|
|
|
21296
21301
|
polling = false;
|
|
21297
21302
|
});
|
|
21298
21303
|
};
|
|
21304
|
+
const unrepairable = /* @__PURE__ */ new Set();
|
|
21305
|
+
let repairCursor;
|
|
21306
|
+
const repairEmbeddings = async ({
|
|
21307
|
+
maxRows = REPAIR_ROWS,
|
|
21308
|
+
maxScan = REPAIR_SCAN,
|
|
21309
|
+
cursor: start = repairCursor
|
|
21310
|
+
} = {}) => {
|
|
21311
|
+
const scannedRows = [];
|
|
21312
|
+
let cursor2 = start;
|
|
21313
|
+
do {
|
|
21314
|
+
const page = await metadata2({
|
|
21315
|
+
include_deleted: true,
|
|
21316
|
+
include_archived: true,
|
|
21317
|
+
include_quarantined: true,
|
|
21318
|
+
include_superseded: true,
|
|
21319
|
+
limit: Math.min(200, Math.max(1, maxScan - scannedRows.length)),
|
|
21320
|
+
...cursor2 && { cursor: cursor2 }
|
|
21321
|
+
});
|
|
21322
|
+
scannedRows.push(...page.items);
|
|
21323
|
+
cursor2 = page.next_cursor;
|
|
21324
|
+
} while (cursor2 && scannedRows.length < maxScan);
|
|
21325
|
+
const allStale = scannedRows.filter(
|
|
21326
|
+
({ memory }) => memory.embedding_model !== model && !unrepairable.has(memory.memory_id)
|
|
21327
|
+
);
|
|
21328
|
+
const repaired = /* @__PURE__ */ new Set();
|
|
21329
|
+
const result = {
|
|
21330
|
+
scanned: scannedRows.length,
|
|
21331
|
+
reembedded: 0,
|
|
21332
|
+
failed: 0,
|
|
21333
|
+
skippedConflict: 0
|
|
21334
|
+
};
|
|
21335
|
+
const finish = () => {
|
|
21336
|
+
const settled = allStale.every(
|
|
21337
|
+
({ memory }) => repaired.has(memory.memory_id) || unrepairable.has(memory.memory_id)
|
|
21338
|
+
);
|
|
21339
|
+
repairCursor = settled ? cursor2 : start;
|
|
21340
|
+
return repairCursor ? { ...result, cursor: repairCursor } : result;
|
|
21341
|
+
};
|
|
21342
|
+
const stale = allStale.slice(0, maxRows).map(({ memory }) => memory.memory_id);
|
|
21343
|
+
if (stale.length === 0) return finish();
|
|
21344
|
+
const { records, unreadable } = await readEveryState(stale);
|
|
21345
|
+
result.failed += unreadable.size;
|
|
21346
|
+
for (const id of stale)
|
|
21347
|
+
if (unreadable.has(id) || !records.get(id)?.memory.content.trim()) unrepairable.add(id);
|
|
21348
|
+
const targets = stale.filter((id) => !unrepairable.has(id)).map((id) => records.get(id));
|
|
21349
|
+
if (targets.length === 0) return finish();
|
|
21350
|
+
const vectors = await embedForRepair(targets);
|
|
21351
|
+
if (!vectors) {
|
|
21352
|
+
result.failed += targets.length;
|
|
21353
|
+
return finish();
|
|
21354
|
+
}
|
|
21355
|
+
for (const [i, record2] of targets.entries()) {
|
|
21356
|
+
const vector = vectors[i];
|
|
21357
|
+
if (!vector) {
|
|
21358
|
+
result.failed++;
|
|
21359
|
+
continue;
|
|
21360
|
+
}
|
|
21361
|
+
await serialized(record2.memory.memory_id, async () => {
|
|
21362
|
+
try {
|
|
21363
|
+
const saved = await persistence.put(
|
|
21364
|
+
{ ...record2.memory, embedding: storedVector(vector), embedding_model: model },
|
|
21365
|
+
record2
|
|
21366
|
+
);
|
|
21367
|
+
notify("embedding", [saved]);
|
|
21368
|
+
repaired.add(record2.memory.memory_id);
|
|
21369
|
+
result.reembedded++;
|
|
21370
|
+
} catch (error) {
|
|
21371
|
+
if (error instanceof RemoteMemoryError && error.code === "version_conflict")
|
|
21372
|
+
result.skippedConflict++;
|
|
21373
|
+
else result.failed++;
|
|
21374
|
+
}
|
|
21375
|
+
});
|
|
21376
|
+
}
|
|
21377
|
+
return finish();
|
|
21378
|
+
};
|
|
21379
|
+
const embedForRepair = async (targets) => {
|
|
21380
|
+
const texts = targets.map(({ memory }) => memory.content);
|
|
21381
|
+
try {
|
|
21382
|
+
return await generateEmbeddings(texts, embeddingOptions);
|
|
21383
|
+
} catch (error) {
|
|
21384
|
+
getLogger().warn("[memory/remote-store] Failed to embed memories for repair:", error);
|
|
21385
|
+
if (!rejectsInput(error)) return null;
|
|
21386
|
+
}
|
|
21387
|
+
const vectors = [];
|
|
21388
|
+
for (const [i, text14] of texts.entries()) {
|
|
21389
|
+
try {
|
|
21390
|
+
[vectors[i]] = await generateEmbeddings([text14], embeddingOptions);
|
|
21391
|
+
} catch (error) {
|
|
21392
|
+
if (!rejectsInput(error)) return null;
|
|
21393
|
+
unrepairable.add(targets[i].memory.memory_id);
|
|
21394
|
+
}
|
|
21395
|
+
}
|
|
21396
|
+
return vectors;
|
|
21397
|
+
};
|
|
21299
21398
|
return {
|
|
21300
21399
|
masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
|
|
21301
21400
|
topicMaintenance,
|
|
21401
|
+
repairEmbeddings,
|
|
21302
21402
|
list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
|
|
21303
21403
|
(r) => stored(r.memory)
|
|
21304
21404
|
),
|
|
@@ -22361,6 +22461,43 @@ function createDurableAutoExtractor(options) {
|
|
|
22361
22461
|
return "private";
|
|
22362
22462
|
}
|
|
22363
22463
|
};
|
|
22464
|
+
async function fromSource(call) {
|
|
22465
|
+
let timeout;
|
|
22466
|
+
try {
|
|
22467
|
+
return await Promise.race([
|
|
22468
|
+
call,
|
|
22469
|
+
new Promise((_resolve, reject) => {
|
|
22470
|
+
timeout = setTimeout(
|
|
22471
|
+
() => reject(new Error("Message source did not answer in time")),
|
|
22472
|
+
options.sourceTimeoutMs ?? 3e4
|
|
22473
|
+
);
|
|
22474
|
+
})
|
|
22475
|
+
]);
|
|
22476
|
+
} finally {
|
|
22477
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
22478
|
+
}
|
|
22479
|
+
}
|
|
22480
|
+
async function loadFromSource(source, conversationId, ids) {
|
|
22481
|
+
const byId = new Map(
|
|
22482
|
+
(await fromSource(source.load(conversationId, ids))).map((m) => [m.id, m])
|
|
22483
|
+
);
|
|
22484
|
+
return ids.map((id) => {
|
|
22485
|
+
const message = byId.get(id);
|
|
22486
|
+
return message ? {
|
|
22487
|
+
uniqueId: message.id,
|
|
22488
|
+
messageId: message.seq,
|
|
22489
|
+
conversationId,
|
|
22490
|
+
role: message.role,
|
|
22491
|
+
content: message.content
|
|
22492
|
+
} : null;
|
|
22493
|
+
});
|
|
22494
|
+
}
|
|
22495
|
+
async function sourcesEligible(conversationId, ids) {
|
|
22496
|
+
const source = options.messageSource?.(conversationId);
|
|
22497
|
+
if (source)
|
|
22498
|
+
return await fromSource(source.status(conversationId)) === "ready" && (await loadFromSource(source, conversationId, ids)).every(Boolean);
|
|
22499
|
+
return await storage.conversationsCollection.query(Q9.where("conversation_id", conversationId), Q9.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q9.where("conversation_id", conversationId), Q9.where("id", Q9.oneOf(ids))).fetchCount() === ids.length;
|
|
22500
|
+
}
|
|
22364
22501
|
function schedule(delay) {
|
|
22365
22502
|
if (disposed) return;
|
|
22366
22503
|
if (running || timer !== void 0) {
|
|
@@ -22389,7 +22526,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22389
22526
|
...options.retainCtx,
|
|
22390
22527
|
vaultCtx: {
|
|
22391
22528
|
...vault,
|
|
22392
|
-
canWrite: async () => !disposed && !cancelled && await
|
|
22529
|
+
canWrite: async () => !disposed && !cancelled && await sourcesEligible(conversationId, ids) && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
22393
22530
|
}
|
|
22394
22531
|
},
|
|
22395
22532
|
extract: { ...options.extract, ...model !== void 0 && { model } },
|
|
@@ -22530,6 +22667,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22530
22667
|
wakeRequested = false;
|
|
22531
22668
|
let retry = false;
|
|
22532
22669
|
let scheduleAfterSuccess = false;
|
|
22670
|
+
let sourceWaiting = false;
|
|
22533
22671
|
try {
|
|
22534
22672
|
await writes;
|
|
22535
22673
|
const pending = await jobs.query(Q9.where("owner_key", owner), Q9.where("message_ids", Q9.notEq("[]"))).fetch();
|
|
@@ -22540,23 +22678,37 @@ function createDurableAutoExtractor(options) {
|
|
|
22540
22678
|
const attempted = attempts.get(job.id) ?? 0;
|
|
22541
22679
|
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id) || awaitingKey.has(job.id))
|
|
22542
22680
|
continue;
|
|
22681
|
+
const conversationId = String(job._getRaw("conversation_id"));
|
|
22682
|
+
const source = options.messageSource?.(conversationId);
|
|
22683
|
+
let sourceStatus;
|
|
22684
|
+
if (source) {
|
|
22685
|
+
try {
|
|
22686
|
+
sourceStatus = await fromSource(source.status(conversationId));
|
|
22687
|
+
} catch (error) {
|
|
22688
|
+
reportError(error, conversationId);
|
|
22689
|
+
sourceStatus = "later";
|
|
22690
|
+
}
|
|
22691
|
+
if (sourceStatus === "later") {
|
|
22692
|
+
sourceWaiting = true;
|
|
22693
|
+
continue;
|
|
22694
|
+
}
|
|
22695
|
+
}
|
|
22543
22696
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
22544
22697
|
scheduleAfterSuccess = true;
|
|
22545
22698
|
break;
|
|
22546
22699
|
}
|
|
22547
22700
|
processed++;
|
|
22548
|
-
const conversationId = String(job._getRaw("conversation_id"));
|
|
22549
22701
|
const epochAtRead = keyEpoch;
|
|
22550
22702
|
let ids = [];
|
|
22551
22703
|
let loaded = [];
|
|
22552
22704
|
try {
|
|
22553
|
-
const
|
|
22554
|
-
if (!
|
|
22705
|
+
const present = source ? sourceStatus === "ready" : await storage.conversationsCollection.query(Q9.where("conversation_id", conversationId), Q9.where("is_deleted", false)).fetchCount() > 0;
|
|
22706
|
+
if (!present) {
|
|
22555
22707
|
await database.write(() => job.destroyPermanently());
|
|
22556
22708
|
continue;
|
|
22557
22709
|
}
|
|
22558
22710
|
ids = idsOf(job).slice(0, 20);
|
|
22559
|
-
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
22711
|
+
loaded = source ? await loadFromSource(source, conversationId, ids) : await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
22560
22712
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
22561
22713
|
if (missing.length) {
|
|
22562
22714
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -22600,7 +22752,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22600
22752
|
);
|
|
22601
22753
|
continue;
|
|
22602
22754
|
}
|
|
22603
|
-
const locked = loaded.filter(
|
|
22755
|
+
const locked = source ? [] : loaded.filter(
|
|
22604
22756
|
(message) => !!message && isEncrypted(message.content)
|
|
22605
22757
|
);
|
|
22606
22758
|
if (locked.length) {
|
|
@@ -22688,6 +22840,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22688
22840
|
wakeRequested = false;
|
|
22689
22841
|
if (retry || scheduleAfterSuccess || woken)
|
|
22690
22842
|
schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
|
|
22843
|
+
else if (sourceWaiting) schedule(options.retryDelayMs ?? 3e4);
|
|
22691
22844
|
}
|
|
22692
22845
|
}
|
|
22693
22846
|
function dispose() {
|
|
@@ -22722,7 +22875,8 @@ function createDurableAutoExtractor(options) {
|
|
|
22722
22875
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
22723
22876
|
);
|
|
22724
22877
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
22725
|
-
const
|
|
22878
|
+
const fromSourceConversation = options.messageSource?.(conversationId) !== void 0;
|
|
22879
|
+
const watermarks = fromSourceConversation ? [] : existing.flatMap((prior) => {
|
|
22726
22880
|
const watermark = prior._getRaw("watermark");
|
|
22727
22881
|
return typeof watermark === "string" && watermark ? [watermark] : [];
|
|
22728
22882
|
});
|
|
@@ -22740,11 +22894,16 @@ function createDurableAutoExtractor(options) {
|
|
|
22740
22894
|
r._setRaw("watermark_seq", null);
|
|
22741
22895
|
});
|
|
22742
22896
|
}
|
|
22743
|
-
const rows = await storage.messagesCollection.query(Q9.where("id", Q9.oneOf(ids))).fetch();
|
|
22897
|
+
const rows = fromSourceConversation ? [] : await storage.messagesCollection.query(Q9.where("id", Q9.oneOf(ids))).fetch();
|
|
22744
22898
|
const foreignRows = new Set(
|
|
22745
22899
|
rows.filter((row) => row._getRaw("conversation_id") !== conversationId).map((row) => row.id)
|
|
22746
22900
|
);
|
|
22747
22901
|
const sequences = /* @__PURE__ */ new Map();
|
|
22902
|
+
if (fromSourceConversation) {
|
|
22903
|
+
for (const message of messages)
|
|
22904
|
+
if (message.seq !== void 0 && message.seq > 0)
|
|
22905
|
+
sequences.set(message.id, message.seq);
|
|
22906
|
+
}
|
|
22748
22907
|
for (const row of rows) {
|
|
22749
22908
|
if (foreignRows.has(row.id)) continue;
|
|
22750
22909
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -22777,14 +22936,17 @@ function createDurableAutoExtractor(options) {
|
|
|
22777
22936
|
reportError(error, conversationId);
|
|
22778
22937
|
}
|
|
22779
22938
|
}
|
|
22780
|
-
|
|
22939
|
+
const ordered = fromSourceConversation && ids.every((id) => sequences.has(id));
|
|
22940
|
+
if (boundary < 0 && !ordered && existing.some(
|
|
22941
|
+
(prior) => idsOf(prior).length > 0 || seqOf(prior) !== void 0 || fromSourceConversation && !!prior._getRaw("watermark")
|
|
22942
|
+
)) {
|
|
22781
22943
|
reportError(
|
|
22782
22944
|
new Error("Extraction boundary unresolved; skipped rather than re-observing"),
|
|
22783
22945
|
conversationId
|
|
22784
22946
|
);
|
|
22785
22947
|
return;
|
|
22786
22948
|
}
|
|
22787
|
-
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
22949
|
+
const start = boundary >= 0 ? boundary + 1 : fromSourceConversation ? 0 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
22788
22950
|
if (start >= ids.length) return;
|
|
22789
22951
|
const ownWatermark = job?._getRaw("watermark");
|
|
22790
22952
|
const atOwnWatermark = !!job && boundary >= 0 && failedSessionsOf(job, String(ownWatermark)) < MAX_FAILED_SESSIONS && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
package/dist/react/index.cjs
CHANGED
|
@@ -24639,6 +24639,8 @@ var MAX_QUERY_TOPICS = 100;
|
|
|
24639
24639
|
var MAX_QUERY_FILTER = 20;
|
|
24640
24640
|
var GRAPH_LANE_ROWS = 256;
|
|
24641
24641
|
var TEMPORAL_LANE_ROWS = 256;
|
|
24642
|
+
var REPAIR_ROWS = 50;
|
|
24643
|
+
var REPAIR_SCAN = 2e3;
|
|
24642
24644
|
var DECAY_TRANSITIONS_PER_SWEEP = 200;
|
|
24643
24645
|
var RemoteMemoryPartialCreateError = class extends Error {
|
|
24644
24646
|
constructor(created, cause) {
|
|
@@ -24648,6 +24650,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
|
|
|
24648
24650
|
this.name = "RemoteMemoryPartialCreateError";
|
|
24649
24651
|
}
|
|
24650
24652
|
};
|
|
24653
|
+
function rejectsInput(error) {
|
|
24654
|
+
return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
|
|
24655
|
+
}
|
|
24651
24656
|
function warnFailed(failed) {
|
|
24652
24657
|
if (failed.length)
|
|
24653
24658
|
getLogger().warn(
|
|
@@ -25264,9 +25269,104 @@ function createRemoteMemoryStore(options) {
|
|
|
25264
25269
|
polling = false;
|
|
25265
25270
|
});
|
|
25266
25271
|
};
|
|
25272
|
+
const unrepairable = /* @__PURE__ */ new Set();
|
|
25273
|
+
let repairCursor;
|
|
25274
|
+
const repairEmbeddings = async ({
|
|
25275
|
+
maxRows = REPAIR_ROWS,
|
|
25276
|
+
maxScan = REPAIR_SCAN,
|
|
25277
|
+
cursor: start = repairCursor
|
|
25278
|
+
} = {}) => {
|
|
25279
|
+
const scannedRows = [];
|
|
25280
|
+
let cursor2 = start;
|
|
25281
|
+
do {
|
|
25282
|
+
const page = await metadata2({
|
|
25283
|
+
include_deleted: true,
|
|
25284
|
+
include_archived: true,
|
|
25285
|
+
include_quarantined: true,
|
|
25286
|
+
include_superseded: true,
|
|
25287
|
+
limit: Math.min(200, Math.max(1, maxScan - scannedRows.length)),
|
|
25288
|
+
...cursor2 && { cursor: cursor2 }
|
|
25289
|
+
});
|
|
25290
|
+
scannedRows.push(...page.items);
|
|
25291
|
+
cursor2 = page.next_cursor;
|
|
25292
|
+
} while (cursor2 && scannedRows.length < maxScan);
|
|
25293
|
+
const allStale = scannedRows.filter(
|
|
25294
|
+
({ memory }) => memory.embedding_model !== model && !unrepairable.has(memory.memory_id)
|
|
25295
|
+
);
|
|
25296
|
+
const repaired = /* @__PURE__ */ new Set();
|
|
25297
|
+
const result = {
|
|
25298
|
+
scanned: scannedRows.length,
|
|
25299
|
+
reembedded: 0,
|
|
25300
|
+
failed: 0,
|
|
25301
|
+
skippedConflict: 0
|
|
25302
|
+
};
|
|
25303
|
+
const finish = () => {
|
|
25304
|
+
const settled = allStale.every(
|
|
25305
|
+
({ memory }) => repaired.has(memory.memory_id) || unrepairable.has(memory.memory_id)
|
|
25306
|
+
);
|
|
25307
|
+
repairCursor = settled ? cursor2 : start;
|
|
25308
|
+
return repairCursor ? { ...result, cursor: repairCursor } : result;
|
|
25309
|
+
};
|
|
25310
|
+
const stale = allStale.slice(0, maxRows).map(({ memory }) => memory.memory_id);
|
|
25311
|
+
if (stale.length === 0) return finish();
|
|
25312
|
+
const { records, unreadable } = await readEveryState(stale);
|
|
25313
|
+
result.failed += unreadable.size;
|
|
25314
|
+
for (const id of stale)
|
|
25315
|
+
if (unreadable.has(id) || !records.get(id)?.memory.content.trim()) unrepairable.add(id);
|
|
25316
|
+
const targets = stale.filter((id) => !unrepairable.has(id)).map((id) => records.get(id));
|
|
25317
|
+
if (targets.length === 0) return finish();
|
|
25318
|
+
const vectors = await embedForRepair(targets);
|
|
25319
|
+
if (!vectors) {
|
|
25320
|
+
result.failed += targets.length;
|
|
25321
|
+
return finish();
|
|
25322
|
+
}
|
|
25323
|
+
for (const [i, record2] of targets.entries()) {
|
|
25324
|
+
const vector = vectors[i];
|
|
25325
|
+
if (!vector) {
|
|
25326
|
+
result.failed++;
|
|
25327
|
+
continue;
|
|
25328
|
+
}
|
|
25329
|
+
await serialized(record2.memory.memory_id, async () => {
|
|
25330
|
+
try {
|
|
25331
|
+
const saved = await persistence.put(
|
|
25332
|
+
{ ...record2.memory, embedding: storedVector(vector), embedding_model: model },
|
|
25333
|
+
record2
|
|
25334
|
+
);
|
|
25335
|
+
notify("embedding", [saved]);
|
|
25336
|
+
repaired.add(record2.memory.memory_id);
|
|
25337
|
+
result.reembedded++;
|
|
25338
|
+
} catch (error) {
|
|
25339
|
+
if (error instanceof RemoteMemoryError && error.code === "version_conflict")
|
|
25340
|
+
result.skippedConflict++;
|
|
25341
|
+
else result.failed++;
|
|
25342
|
+
}
|
|
25343
|
+
});
|
|
25344
|
+
}
|
|
25345
|
+
return finish();
|
|
25346
|
+
};
|
|
25347
|
+
const embedForRepair = async (targets) => {
|
|
25348
|
+
const texts = targets.map(({ memory }) => memory.content);
|
|
25349
|
+
try {
|
|
25350
|
+
return await generateEmbeddings(texts, embeddingOptions);
|
|
25351
|
+
} catch (error) {
|
|
25352
|
+
getLogger().warn("[memory/remote-store] Failed to embed memories for repair:", error);
|
|
25353
|
+
if (!rejectsInput(error)) return null;
|
|
25354
|
+
}
|
|
25355
|
+
const vectors = [];
|
|
25356
|
+
for (const [i, text14] of texts.entries()) {
|
|
25357
|
+
try {
|
|
25358
|
+
[vectors[i]] = await generateEmbeddings([text14], embeddingOptions);
|
|
25359
|
+
} catch (error) {
|
|
25360
|
+
if (!rejectsInput(error)) return null;
|
|
25361
|
+
unrepairable.add(targets[i].memory.memory_id);
|
|
25362
|
+
}
|
|
25363
|
+
}
|
|
25364
|
+
return vectors;
|
|
25365
|
+
};
|
|
25267
25366
|
return {
|
|
25268
25367
|
masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
|
|
25269
25368
|
topicMaintenance,
|
|
25369
|
+
repairEmbeddings,
|
|
25270
25370
|
list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
|
|
25271
25371
|
(r) => stored(r.memory)
|
|
25272
25372
|
),
|
|
@@ -26331,6 +26431,43 @@ function createDurableAutoExtractor(options) {
|
|
|
26331
26431
|
return "private";
|
|
26332
26432
|
}
|
|
26333
26433
|
};
|
|
26434
|
+
async function fromSource(call) {
|
|
26435
|
+
let timeout;
|
|
26436
|
+
try {
|
|
26437
|
+
return await Promise.race([
|
|
26438
|
+
call,
|
|
26439
|
+
new Promise((_resolve, reject) => {
|
|
26440
|
+
timeout = setTimeout(
|
|
26441
|
+
() => reject(new Error("Message source did not answer in time")),
|
|
26442
|
+
options.sourceTimeoutMs ?? 3e4
|
|
26443
|
+
);
|
|
26444
|
+
})
|
|
26445
|
+
]);
|
|
26446
|
+
} finally {
|
|
26447
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
26448
|
+
}
|
|
26449
|
+
}
|
|
26450
|
+
async function loadFromSource(source, conversationId, ids) {
|
|
26451
|
+
const byId = new Map(
|
|
26452
|
+
(await fromSource(source.load(conversationId, ids))).map((m) => [m.id, m])
|
|
26453
|
+
);
|
|
26454
|
+
return ids.map((id) => {
|
|
26455
|
+
const message = byId.get(id);
|
|
26456
|
+
return message ? {
|
|
26457
|
+
uniqueId: message.id,
|
|
26458
|
+
messageId: message.seq,
|
|
26459
|
+
conversationId,
|
|
26460
|
+
role: message.role,
|
|
26461
|
+
content: message.content
|
|
26462
|
+
} : null;
|
|
26463
|
+
});
|
|
26464
|
+
}
|
|
26465
|
+
async function sourcesEligible(conversationId, ids) {
|
|
26466
|
+
const source = options.messageSource?.(conversationId);
|
|
26467
|
+
if (source)
|
|
26468
|
+
return await fromSource(source.status(conversationId)) === "ready" && (await loadFromSource(source, conversationId, ids)).every(Boolean);
|
|
26469
|
+
return await storage.conversationsCollection.query(import_watermelondb33.Q.where("conversation_id", conversationId), import_watermelondb33.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb33.Q.where("conversation_id", conversationId), import_watermelondb33.Q.where("id", import_watermelondb33.Q.oneOf(ids))).fetchCount() === ids.length;
|
|
26470
|
+
}
|
|
26334
26471
|
function schedule(delay) {
|
|
26335
26472
|
if (disposed) return;
|
|
26336
26473
|
if (running || timer !== void 0) {
|
|
@@ -26359,7 +26496,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26359
26496
|
...options.retainCtx,
|
|
26360
26497
|
vaultCtx: {
|
|
26361
26498
|
...vault,
|
|
26362
|
-
canWrite: async () => !disposed && !cancelled && await
|
|
26499
|
+
canWrite: async () => !disposed && !cancelled && await sourcesEligible(conversationId, ids) && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
26363
26500
|
}
|
|
26364
26501
|
},
|
|
26365
26502
|
extract: { ...options.extract, ...model !== void 0 && { model } },
|
|
@@ -26500,6 +26637,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26500
26637
|
wakeRequested = false;
|
|
26501
26638
|
let retry = false;
|
|
26502
26639
|
let scheduleAfterSuccess = false;
|
|
26640
|
+
let sourceWaiting = false;
|
|
26503
26641
|
try {
|
|
26504
26642
|
await writes;
|
|
26505
26643
|
const pending = await jobs.query(import_watermelondb33.Q.where("owner_key", owner), import_watermelondb33.Q.where("message_ids", import_watermelondb33.Q.notEq("[]"))).fetch();
|
|
@@ -26510,23 +26648,37 @@ function createDurableAutoExtractor(options) {
|
|
|
26510
26648
|
const attempted = attempts.get(job.id) ?? 0;
|
|
26511
26649
|
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id) || awaitingKey.has(job.id))
|
|
26512
26650
|
continue;
|
|
26651
|
+
const conversationId = String(job._getRaw("conversation_id"));
|
|
26652
|
+
const source = options.messageSource?.(conversationId);
|
|
26653
|
+
let sourceStatus;
|
|
26654
|
+
if (source) {
|
|
26655
|
+
try {
|
|
26656
|
+
sourceStatus = await fromSource(source.status(conversationId));
|
|
26657
|
+
} catch (error) {
|
|
26658
|
+
reportError(error, conversationId);
|
|
26659
|
+
sourceStatus = "later";
|
|
26660
|
+
}
|
|
26661
|
+
if (sourceStatus === "later") {
|
|
26662
|
+
sourceWaiting = true;
|
|
26663
|
+
continue;
|
|
26664
|
+
}
|
|
26665
|
+
}
|
|
26513
26666
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
26514
26667
|
scheduleAfterSuccess = true;
|
|
26515
26668
|
break;
|
|
26516
26669
|
}
|
|
26517
26670
|
processed++;
|
|
26518
|
-
const conversationId = String(job._getRaw("conversation_id"));
|
|
26519
26671
|
const epochAtRead = keyEpoch;
|
|
26520
26672
|
let ids = [];
|
|
26521
26673
|
let loaded = [];
|
|
26522
26674
|
try {
|
|
26523
|
-
const
|
|
26524
|
-
if (!
|
|
26675
|
+
const present = source ? sourceStatus === "ready" : await storage.conversationsCollection.query(import_watermelondb33.Q.where("conversation_id", conversationId), import_watermelondb33.Q.where("is_deleted", false)).fetchCount() > 0;
|
|
26676
|
+
if (!present) {
|
|
26525
26677
|
await database.write(() => job.destroyPermanently());
|
|
26526
26678
|
continue;
|
|
26527
26679
|
}
|
|
26528
26680
|
ids = idsOf(job).slice(0, 20);
|
|
26529
|
-
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
26681
|
+
loaded = source ? await loadFromSource(source, conversationId, ids) : await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
26530
26682
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
26531
26683
|
if (missing.length) {
|
|
26532
26684
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -26570,7 +26722,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26570
26722
|
);
|
|
26571
26723
|
continue;
|
|
26572
26724
|
}
|
|
26573
|
-
const locked = loaded.filter(
|
|
26725
|
+
const locked = source ? [] : loaded.filter(
|
|
26574
26726
|
(message) => !!message && isEncrypted(message.content)
|
|
26575
26727
|
);
|
|
26576
26728
|
if (locked.length) {
|
|
@@ -26658,6 +26810,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26658
26810
|
wakeRequested = false;
|
|
26659
26811
|
if (retry || scheduleAfterSuccess || woken)
|
|
26660
26812
|
schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
|
|
26813
|
+
else if (sourceWaiting) schedule(options.retryDelayMs ?? 3e4);
|
|
26661
26814
|
}
|
|
26662
26815
|
}
|
|
26663
26816
|
function dispose() {
|
|
@@ -26692,7 +26845,8 @@ function createDurableAutoExtractor(options) {
|
|
|
26692
26845
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
26693
26846
|
);
|
|
26694
26847
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
26695
|
-
const
|
|
26848
|
+
const fromSourceConversation = options.messageSource?.(conversationId) !== void 0;
|
|
26849
|
+
const watermarks = fromSourceConversation ? [] : existing.flatMap((prior) => {
|
|
26696
26850
|
const watermark = prior._getRaw("watermark");
|
|
26697
26851
|
return typeof watermark === "string" && watermark ? [watermark] : [];
|
|
26698
26852
|
});
|
|
@@ -26710,11 +26864,16 @@ function createDurableAutoExtractor(options) {
|
|
|
26710
26864
|
r._setRaw("watermark_seq", null);
|
|
26711
26865
|
});
|
|
26712
26866
|
}
|
|
26713
|
-
const rows = await storage.messagesCollection.query(import_watermelondb33.Q.where("id", import_watermelondb33.Q.oneOf(ids))).fetch();
|
|
26867
|
+
const rows = fromSourceConversation ? [] : await storage.messagesCollection.query(import_watermelondb33.Q.where("id", import_watermelondb33.Q.oneOf(ids))).fetch();
|
|
26714
26868
|
const foreignRows = new Set(
|
|
26715
26869
|
rows.filter((row) => row._getRaw("conversation_id") !== conversationId).map((row) => row.id)
|
|
26716
26870
|
);
|
|
26717
26871
|
const sequences = /* @__PURE__ */ new Map();
|
|
26872
|
+
if (fromSourceConversation) {
|
|
26873
|
+
for (const message of messages)
|
|
26874
|
+
if (message.seq !== void 0 && message.seq > 0)
|
|
26875
|
+
sequences.set(message.id, message.seq);
|
|
26876
|
+
}
|
|
26718
26877
|
for (const row of rows) {
|
|
26719
26878
|
if (foreignRows.has(row.id)) continue;
|
|
26720
26879
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -26747,14 +26906,17 @@ function createDurableAutoExtractor(options) {
|
|
|
26747
26906
|
reportError(error, conversationId);
|
|
26748
26907
|
}
|
|
26749
26908
|
}
|
|
26750
|
-
|
|
26909
|
+
const ordered = fromSourceConversation && ids.every((id) => sequences.has(id));
|
|
26910
|
+
if (boundary < 0 && !ordered && existing.some(
|
|
26911
|
+
(prior) => idsOf(prior).length > 0 || seqOf(prior) !== void 0 || fromSourceConversation && !!prior._getRaw("watermark")
|
|
26912
|
+
)) {
|
|
26751
26913
|
reportError(
|
|
26752
26914
|
new Error("Extraction boundary unresolved; skipped rather than re-observing"),
|
|
26753
26915
|
conversationId
|
|
26754
26916
|
);
|
|
26755
26917
|
return;
|
|
26756
26918
|
}
|
|
26757
|
-
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
26919
|
+
const start = boundary >= 0 ? boundary + 1 : fromSourceConversation ? 0 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
26758
26920
|
if (start >= ids.length) return;
|
|
26759
26921
|
const ownWatermark = job?._getRaw("watermark");
|
|
26760
26922
|
const atOwnWatermark = !!job && boundary >= 0 && failedSessionsOf(job, String(ownWatermark)) < MAX_FAILED_SESSIONS && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|