@anuma/sdk 7.0.3 → 7.0.4-next.20261015010856
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 +288 -73
- package/dist/expo/index.d.mts +24 -4
- package/dist/expo/index.d.ts +24 -4
- package/dist/expo/index.mjs +288 -73
- package/dist/memory/context.d.mts +1 -0
- package/dist/memory/context.d.ts +1 -0
- package/dist/react/index.cjs +293 -73
- package/dist/react/index.d.mts +24 -4
- package/dist/react/index.d.ts +24 -4
- package/dist/react/index.mjs +293 -73
- package/dist/server/index.cjs +237 -33
- package/dist/server/index.d.mts +26 -3
- package/dist/server/index.d.ts +26 -3
- package/dist/server/index.mjs +237 -33
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -2158,8 +2158,9 @@ async function updateConversationPinnedOp(ctx, id, pinned) {
|
|
|
2158
2158
|
}
|
|
2159
2159
|
return false;
|
|
2160
2160
|
}
|
|
2161
|
-
async function getMessagesOp(ctx, convId) {
|
|
2162
|
-
const
|
|
2161
|
+
async function getMessagesOp(ctx, convId, opts) {
|
|
2162
|
+
const fetched = await ctx.messagesCollection.query(Q.where("conversation_id", convId), Q.sortBy("message_id", Q.asc)).unsafeFetchRaw();
|
|
2163
|
+
const results = opts?.rawFilter ? fetched.filter(opts.rawFilter) : fetched;
|
|
2163
2164
|
return Promise.all(
|
|
2164
2165
|
results.map(
|
|
2165
2166
|
(raw) => messageRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
@@ -4306,6 +4307,37 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
|
|
|
4306
4307
|
}));
|
|
4307
4308
|
return updateMessageChunksOp(ctx, messageId, messageChunks, embeddingModel);
|
|
4308
4309
|
}
|
|
4310
|
+
var MIN_SEALED_EMBEDDING_HEX = 256;
|
|
4311
|
+
function rawHasEmbedding(value) {
|
|
4312
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
4313
|
+
if (typeof value !== "string" || value.length === 0) return false;
|
|
4314
|
+
if (isEncrypted(value)) {
|
|
4315
|
+
return value.length - value.indexOf(":", 4) - 1 >= MIN_SEALED_EMBEDDING_HEX;
|
|
4316
|
+
}
|
|
4317
|
+
try {
|
|
4318
|
+
const parsed = JSON.parse(value);
|
|
4319
|
+
return Array.isArray(parsed) && parsed.length > 0;
|
|
4320
|
+
} catch {
|
|
4321
|
+
return false;
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
function sealedVersion(value) {
|
|
4325
|
+
if (typeof value !== "string" || !isEncrypted(value)) return null;
|
|
4326
|
+
return value.startsWith("enc:v2:") ? "v2" : "v3";
|
|
4327
|
+
}
|
|
4328
|
+
function mayNeedChunkEmbedding(raw, embeddingModel, filter) {
|
|
4329
|
+
const role = raw.role;
|
|
4330
|
+
if (role === "system") return false;
|
|
4331
|
+
if (filter?.roles && !filter.roles.includes(role ?? "")) return false;
|
|
4332
|
+
if (isNonEmbeddableOrigin(raw.origin, filter?.reembedDiscarded)) {
|
|
4333
|
+
return false;
|
|
4334
|
+
}
|
|
4335
|
+
const model = raw.embedding_model;
|
|
4336
|
+
if (typeof model === "string" && model !== embeddingModel) return true;
|
|
4337
|
+
if (rawHasEmbedding(raw.chunks)) return false;
|
|
4338
|
+
if (rawHasEmbedding(raw.vector) && !filter?.rechunkExisting) return false;
|
|
4339
|
+
return true;
|
|
4340
|
+
}
|
|
4309
4341
|
async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
4310
4342
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
4311
4343
|
const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
|
|
@@ -4318,11 +4350,31 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4318
4350
|
let considered = 0;
|
|
4319
4351
|
let sealedRowsSeen = 0;
|
|
4320
4352
|
let rowsSeen = 0;
|
|
4353
|
+
const keptSealed = /* @__PURE__ */ new Map();
|
|
4354
|
+
const candidatesStillSealed = /* @__PURE__ */ new Map();
|
|
4355
|
+
const droppedSealed = /* @__PURE__ */ new Map();
|
|
4356
|
+
const rawFilter = (raw) => {
|
|
4357
|
+
rowsSeen++;
|
|
4358
|
+
const keep = mayNeedChunkEmbedding(raw, embeddingModel, filter);
|
|
4359
|
+
const version = sealedVersion(raw.content);
|
|
4360
|
+
if (!version) return keep;
|
|
4361
|
+
if (keep) {
|
|
4362
|
+
keptSealed.set(version, (keptSealed.get(version) ?? 0) + 1);
|
|
4363
|
+
} else {
|
|
4364
|
+
const dropped = droppedSealed.get(version);
|
|
4365
|
+
if (dropped) dropped.count++;
|
|
4366
|
+
else droppedSealed.set(version, { count: 1, probeId: raw.id });
|
|
4367
|
+
}
|
|
4368
|
+
return keep;
|
|
4369
|
+
};
|
|
4321
4370
|
for (const conv of targetConversations) {
|
|
4322
|
-
const messages = await getMessagesOp(ctx, conv.conversationId);
|
|
4371
|
+
const messages = await getMessagesOp(ctx, conv.conversationId, { rawFilter });
|
|
4323
4372
|
for (const message of messages) {
|
|
4324
|
-
|
|
4325
|
-
if (
|
|
4373
|
+
const stillSealed = sealedVersion(message.content);
|
|
4374
|
+
if (stillSealed) {
|
|
4375
|
+
sealedRowsSeen++;
|
|
4376
|
+
candidatesStillSealed.set(stillSealed, (candidatesStillSealed.get(stillSealed) ?? 0) + 1);
|
|
4377
|
+
}
|
|
4326
4378
|
const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
|
|
4327
4379
|
if (message.chunks && message.chunks.length > 0 && !isStale) continue;
|
|
4328
4380
|
const hasVector = message.vector && message.vector.length > 0;
|
|
@@ -4335,6 +4387,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4335
4387
|
stillEncrypted++;
|
|
4336
4388
|
continue;
|
|
4337
4389
|
}
|
|
4390
|
+
if (isToolResultsRow(message)) continue;
|
|
4338
4391
|
if (message.content.length < minLength) continue;
|
|
4339
4392
|
if (shouldChunkMessage(message.content, chunkSize)) {
|
|
4340
4393
|
longMessages.push({
|
|
@@ -4346,6 +4399,12 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4346
4399
|
}
|
|
4347
4400
|
}
|
|
4348
4401
|
}
|
|
4402
|
+
for (const [version, dropped] of droppedSealed) {
|
|
4403
|
+
const keyOpenedACandidate = (keptSealed.get(version) ?? 0) > (candidatesStillSealed.get(version) ?? 0);
|
|
4404
|
+
if (keyOpenedACandidate) continue;
|
|
4405
|
+
const probe = await getMessageOp(ctx, dropped.probeId);
|
|
4406
|
+
if (!probe || isEncrypted(probe.content)) sealedRowsSeen += dropped.count;
|
|
4407
|
+
}
|
|
4349
4408
|
if (stillEncrypted > 0 || sealedRowsSeen > 0) {
|
|
4350
4409
|
getLogger().error(
|
|
4351
4410
|
"memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
|
|
@@ -11050,6 +11109,11 @@ import { Q as Q5 } from "@nozbe/watermelondb";
|
|
|
11050
11109
|
|
|
11051
11110
|
// src/lib/db/entities/operations.ts
|
|
11052
11111
|
import { Q as Q4 } from "@nozbe/watermelondb";
|
|
11112
|
+
async function assertCanWrite(ctx) {
|
|
11113
|
+
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
11114
|
+
throw new Error("Memory source is no longer eligible");
|
|
11115
|
+
}
|
|
11116
|
+
}
|
|
11053
11117
|
function entityToStored(e) {
|
|
11054
11118
|
return {
|
|
11055
11119
|
uniqueId: e.id,
|
|
@@ -11190,6 +11254,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
11190
11254
|
let skipped = false;
|
|
11191
11255
|
let entities = [];
|
|
11192
11256
|
await ctx.database.write(async () => {
|
|
11257
|
+
await assertCanWrite(ctx);
|
|
11193
11258
|
const {
|
|
11194
11259
|
entities: byName,
|
|
11195
11260
|
operations: entityOps,
|
|
@@ -11265,6 +11330,7 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
11265
11330
|
let skipped = false;
|
|
11266
11331
|
let entities = [];
|
|
11267
11332
|
await ctx.database.write(async () => {
|
|
11333
|
+
await assertCanWrite(ctx);
|
|
11268
11334
|
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
11269
11335
|
if (options.guarded && autoLinkBlocked(vaultRow)) {
|
|
11270
11336
|
skipped = true;
|
|
@@ -11325,6 +11391,7 @@ async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
|
|
|
11325
11391
|
const links = await ctx.memoryEntityCollection.query(Q4.where("memory_id", Q4.oneOf(Array.from(memoryIds)))).fetch();
|
|
11326
11392
|
if (links.length === 0) return;
|
|
11327
11393
|
await ctx.database.write(async () => {
|
|
11394
|
+
await assertCanWrite(ctx);
|
|
11328
11395
|
await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
|
|
11329
11396
|
});
|
|
11330
11397
|
}
|
|
@@ -11333,6 +11400,7 @@ async function unlinkAllMemoryEntitiesForUserOp(ctx, userId) {
|
|
|
11333
11400
|
const links = await ctx.memoryEntityCollection.query(Q4.where("user_id", userId)).fetch();
|
|
11334
11401
|
if (links.length === 0) return;
|
|
11335
11402
|
await ctx.database.write(async () => {
|
|
11403
|
+
await assertCanWrite(ctx);
|
|
11336
11404
|
await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
|
|
11337
11405
|
});
|
|
11338
11406
|
}
|
|
@@ -11496,6 +11564,11 @@ function visibilityConditions(requested) {
|
|
|
11496
11564
|
function isKinded(record2) {
|
|
11497
11565
|
return record2.kind !== null && record2.kind !== void 0;
|
|
11498
11566
|
}
|
|
11567
|
+
async function assertCanWrite2(ctx) {
|
|
11568
|
+
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
11569
|
+
throw new Error("Memory source is no longer eligible");
|
|
11570
|
+
}
|
|
11571
|
+
}
|
|
11499
11572
|
function assertValidKindLevel(kind, level) {
|
|
11500
11573
|
const hasKind = kind !== null && kind !== void 0;
|
|
11501
11574
|
if (hasKind && !MEMORY_KINDS.includes(kind)) {
|
|
@@ -11676,8 +11749,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
11676
11749
|
ctx.embeddedWalletSigner
|
|
11677
11750
|
) : opts.content;
|
|
11678
11751
|
const created = await ctx.database.write(async () => {
|
|
11679
|
-
|
|
11680
|
-
throw new Error("Memory source is no longer eligible");
|
|
11752
|
+
await assertCanWrite2(ctx);
|
|
11681
11753
|
return ctx.vaultMemoryCollection.create(
|
|
11682
11754
|
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
11683
11755
|
);
|
|
@@ -11696,8 +11768,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
11696
11768
|
) : opts.content;
|
|
11697
11769
|
let createdRecord = null;
|
|
11698
11770
|
await ctx.database.write(async () => {
|
|
11699
|
-
|
|
11700
|
-
throw new Error("Memory source is no longer eligible");
|
|
11771
|
+
await assertCanWrite2(ctx);
|
|
11701
11772
|
let target;
|
|
11702
11773
|
try {
|
|
11703
11774
|
target = await ctx.vaultMemoryCollection.find(targetId);
|
|
@@ -11789,8 +11860,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11789
11860
|
})
|
|
11790
11861
|
);
|
|
11791
11862
|
const created = await ctx.database.write(async () => {
|
|
11792
|
-
|
|
11793
|
-
throw new Error("Memory source is no longer eligible");
|
|
11863
|
+
await assertCanWrite2(ctx);
|
|
11794
11864
|
const prepared = optionsArray.map(
|
|
11795
11865
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11796
11866
|
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
@@ -12095,8 +12165,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12095
12165
|
const record2 = probe;
|
|
12096
12166
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12097
12167
|
await ctx.database.write(async () => {
|
|
12098
|
-
|
|
12099
|
-
throw new Error("Memory source is no longer eligible");
|
|
12168
|
+
await assertCanWrite2(ctx);
|
|
12100
12169
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
12101
12170
|
stale = true;
|
|
12102
12171
|
return;
|
|
@@ -12207,6 +12276,7 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
12207
12276
|
let stale = false;
|
|
12208
12277
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12209
12278
|
await ctx.database.write(async (writer) => {
|
|
12279
|
+
await assertCanWrite2(ctx);
|
|
12210
12280
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
12211
12281
|
stale = true;
|
|
12212
12282
|
return;
|
|
@@ -12248,6 +12318,7 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
12248
12318
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12249
12319
|
let cleared = false;
|
|
12250
12320
|
await ctx.database.write(async () => {
|
|
12321
|
+
await assertCanWrite2(ctx);
|
|
12251
12322
|
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
12252
12323
|
cleared = true;
|
|
12253
12324
|
await record2.update((r) => {
|
|
@@ -12271,6 +12342,7 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
12271
12342
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
12272
12343
|
let stale = false;
|
|
12273
12344
|
await ctx.database.write(async () => {
|
|
12345
|
+
await assertCanWrite2(ctx);
|
|
12274
12346
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
12275
12347
|
stale = true;
|
|
12276
12348
|
return;
|
|
@@ -12299,6 +12371,7 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
12299
12371
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
12300
12372
|
let stale = false;
|
|
12301
12373
|
await ctx.database.write(async () => {
|
|
12374
|
+
await assertCanWrite2(ctx);
|
|
12302
12375
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
12303
12376
|
stale = true;
|
|
12304
12377
|
return;
|
|
@@ -12336,8 +12409,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
12336
12409
|
}
|
|
12337
12410
|
let stale = false;
|
|
12338
12411
|
await ctx.database.write(async () => {
|
|
12339
|
-
|
|
12340
|
-
throw new Error("Memory source is no longer eligible");
|
|
12412
|
+
await assertCanWrite2(ctx);
|
|
12341
12413
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
12342
12414
|
stale = true;
|
|
12343
12415
|
return;
|
|
@@ -12499,6 +12571,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
12499
12571
|
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
12500
12572
|
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
12501
12573
|
await ctx.database.write(async () => {
|
|
12574
|
+
await assertCanWrite2(ctx);
|
|
12502
12575
|
const records = [];
|
|
12503
12576
|
for (const id of chunkIds) {
|
|
12504
12577
|
try {
|
|
@@ -12532,6 +12605,7 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
12532
12605
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
12533
12606
|
try {
|
|
12534
12607
|
await ctx.database.write(async (writer) => {
|
|
12608
|
+
await assertCanWrite2(ctx);
|
|
12535
12609
|
let record2;
|
|
12536
12610
|
try {
|
|
12537
12611
|
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
@@ -12562,6 +12636,7 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
12562
12636
|
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
12563
12637
|
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
12564
12638
|
await ctx.database.write(async () => {
|
|
12639
|
+
await assertCanWrite2(ctx);
|
|
12565
12640
|
const writes = [];
|
|
12566
12641
|
for (const id of chunkIds) {
|
|
12567
12642
|
let record2;
|
|
@@ -12594,6 +12669,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
12594
12669
|
const records = await ctx.vaultMemoryCollection.query(Q5.where("user_id", userId), Q5.where("is_deleted", false)).fetch();
|
|
12595
12670
|
if (records.length === 0) return 0;
|
|
12596
12671
|
await ctx.database.write(async () => {
|
|
12672
|
+
await assertCanWrite2(ctx);
|
|
12597
12673
|
const prepared = records.map(
|
|
12598
12674
|
(record2) => record2.prepareUpdate((r) => {
|
|
12599
12675
|
r._setRaw("is_deleted", true);
|
|
@@ -12648,6 +12724,7 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
12648
12724
|
let stale = false;
|
|
12649
12725
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
12650
12726
|
await ctx.database.write(async () => {
|
|
12727
|
+
await assertCanWrite2(ctx);
|
|
12651
12728
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
12652
12729
|
stale = true;
|
|
12653
12730
|
return;
|
|
@@ -12671,6 +12748,7 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
12671
12748
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
12672
12749
|
let stale = false;
|
|
12673
12750
|
await ctx.database.write(async () => {
|
|
12751
|
+
await assertCanWrite2(ctx);
|
|
12674
12752
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
12675
12753
|
stale = true;
|
|
12676
12754
|
return;
|
|
@@ -12691,6 +12769,7 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
12691
12769
|
const now = opts.now ?? Date.now();
|
|
12692
12770
|
let stale = false;
|
|
12693
12771
|
await ctx.database.write(async () => {
|
|
12772
|
+
await assertCanWrite2(ctx);
|
|
12694
12773
|
const archivedAt = record2.archivedAt;
|
|
12695
12774
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
12696
12775
|
stale = true;
|
|
@@ -12730,6 +12809,7 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding2, embeddingModel,
|
|
|
12730
12809
|
}
|
|
12731
12810
|
let written = false;
|
|
12732
12811
|
await ctx.database.write(async () => {
|
|
12812
|
+
await assertCanWrite2(ctx);
|
|
12733
12813
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
12734
12814
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12735
12815
|
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
@@ -16242,6 +16322,13 @@ function restoreCandidates(candidates, redactor, ownNames) {
|
|
|
16242
16322
|
).map((c) => c.candidate);
|
|
16243
16323
|
}
|
|
16244
16324
|
async function extractAndRetain(messages, retainCtx, options) {
|
|
16325
|
+
const { memoryStore, signal } = options;
|
|
16326
|
+
if (memoryStore === null) throw new Error("Memory store is not ready");
|
|
16327
|
+
if (memoryStore && options.folderId !== void 0 && options.folderId !== null)
|
|
16328
|
+
throw new Error("Remote memory extraction does not support folders");
|
|
16329
|
+
if (memoryStore && options.extract.piiRedaction && !memoryStore.masksEmbeddingInput)
|
|
16330
|
+
throw new Error("PII-redacted extraction requires a memory store that masks embedding inputs");
|
|
16331
|
+
signal?.throwIfAborted();
|
|
16245
16332
|
const minConfidence = options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
|
|
16246
16333
|
const resolvedConsolidatePii = options.consolidateOptions?.piiRedaction ?? options.extract.piiRedaction;
|
|
16247
16334
|
const consolidateOptions = options.consolidateOptions !== void 0 ? {
|
|
@@ -16275,6 +16362,7 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
16275
16362
|
}
|
|
16276
16363
|
});
|
|
16277
16364
|
const extractMs = Date.now() - tExtract;
|
|
16365
|
+
signal?.throwIfAborted();
|
|
16278
16366
|
const filtered = candidates.filter((c) => c.confidence >= minConfidence);
|
|
16279
16367
|
const log = getLogger();
|
|
16280
16368
|
const screened = screenCandidatesForInjection(filtered);
|
|
@@ -16322,16 +16410,33 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
16322
16410
|
const results = [];
|
|
16323
16411
|
const quarantinedInfo = [];
|
|
16324
16412
|
let failedWrites = 0;
|
|
16413
|
+
let auditRows;
|
|
16325
16414
|
const tRetain = Date.now();
|
|
16326
16415
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
16327
16416
|
try {
|
|
16417
|
+
signal?.throwIfAborted();
|
|
16328
16418
|
if (isQuarantined) {
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16419
|
+
let existingId;
|
|
16420
|
+
if (memoryStore) {
|
|
16421
|
+
auditRows ?? (auditRows = memoryStore.list({
|
|
16422
|
+
scopes: [options.scope ?? "private"],
|
|
16423
|
+
includeArchived: true,
|
|
16424
|
+
includeQuarantined: true,
|
|
16425
|
+
includeSuperseded: true
|
|
16426
|
+
}));
|
|
16427
|
+
const sourceKey = [...new Set(candidate.sourceMessageIds)].sort().join("\0");
|
|
16428
|
+
const normalize = (value) => value.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
16429
|
+
existingId = (await auditRows).find(
|
|
16430
|
+
(row) => row.trustTier === "quarantined" && row.scope === (options.scope ?? "private") && [...new Set(row.sourceChunkIds ?? [])].sort().join("\0") === sourceKey && normalize(row.content) === normalize(candidate.content)
|
|
16431
|
+
)?.uniqueId ?? null;
|
|
16432
|
+
} else {
|
|
16433
|
+
existingId = await findQuarantinedDuplicateOp(
|
|
16434
|
+
retainCtx.vaultCtx,
|
|
16435
|
+
candidate.content,
|
|
16436
|
+
candidate.sourceMessageIds,
|
|
16437
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
16438
|
+
).catch(() => null);
|
|
16439
|
+
}
|
|
16335
16440
|
if (existingId) {
|
|
16336
16441
|
quarantinedInfo.push({
|
|
16337
16442
|
candidate,
|
|
@@ -16342,18 +16447,26 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
16342
16447
|
continue;
|
|
16343
16448
|
}
|
|
16344
16449
|
}
|
|
16345
|
-
const
|
|
16450
|
+
const retainOptions = {
|
|
16346
16451
|
source: "auto-extracted",
|
|
16347
16452
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
16348
16453
|
respectTombstones: true,
|
|
16349
16454
|
...options.scope !== void 0 && { scope: options.scope },
|
|
16350
|
-
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
16351
16455
|
...consolidateOptions !== void 0 && { consolidateOptions },
|
|
16352
16456
|
...candidate.eventTime !== null && { eventTime: candidate.eventTime },
|
|
16353
16457
|
factType: candidate.type,
|
|
16354
16458
|
...isQuarantined && { trustTier: "quarantined", enableAutoMerge: false }
|
|
16459
|
+
};
|
|
16460
|
+
const result = memoryStore ? await memoryStore.retain(candidate.content, {
|
|
16461
|
+
...retainOptions,
|
|
16462
|
+
canWrite: retainCtx.vaultCtx.canWrite,
|
|
16463
|
+
signal
|
|
16464
|
+
}) : await retain(candidate.content, retainCtx, {
|
|
16465
|
+
...retainOptions,
|
|
16466
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
16355
16467
|
});
|
|
16356
16468
|
if (isQuarantined) {
|
|
16469
|
+
auditRows = void 0;
|
|
16357
16470
|
const info = {
|
|
16358
16471
|
candidate,
|
|
16359
16472
|
memoryId: result.memoryId,
|
|
@@ -16372,9 +16485,16 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
16372
16485
|
}
|
|
16373
16486
|
succeededCandidates.push(candidate);
|
|
16374
16487
|
results.push(result);
|
|
16375
|
-
if (result.action !== "suppressed" &&
|
|
16488
|
+
if (result.action !== "suppressed" && candidate.entities.length > 0) {
|
|
16376
16489
|
try {
|
|
16377
|
-
|
|
16490
|
+
signal?.throwIfAborted();
|
|
16491
|
+
if (memoryStore) {
|
|
16492
|
+
await memoryStore.addTopics(result.memoryId, candidate.entities, {
|
|
16493
|
+
unlessUserManaged: true,
|
|
16494
|
+
canWrite: retainCtx.vaultCtx.canWrite,
|
|
16495
|
+
signal
|
|
16496
|
+
});
|
|
16497
|
+
} else if (options.entityCtx && !await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
|
|
16378
16498
|
await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
|
|
16379
16499
|
unlessTopicsUserManaged: true
|
|
16380
16500
|
});
|
|
@@ -16622,7 +16742,7 @@ function createAutoExtractor(options) {
|
|
|
16622
16742
|
};
|
|
16623
16743
|
const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
|
|
16624
16744
|
const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
|
|
16625
|
-
if (options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
|
|
16745
|
+
if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
|
|
16626
16746
|
getLogger().warn(
|
|
16627
16747
|
"[memory/extract] retainCtx.vaultCtx.entityCtx is set but extractor was created without `entityCtx` \u2014 W5 graph lane will receive no writes"
|
|
16628
16748
|
);
|
|
@@ -16667,6 +16787,8 @@ function createAutoExtractor(options) {
|
|
|
16667
16787
|
try {
|
|
16668
16788
|
const { candidates, results, failedCount, outcome: outcome2, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
|
|
16669
16789
|
extract,
|
|
16790
|
+
memoryStore: options.memoryStore,
|
|
16791
|
+
signal: options.signal,
|
|
16670
16792
|
...options.minConfidence !== void 0 && { minConfidence: options.minConfidence },
|
|
16671
16793
|
...options.entityCtx !== void 0 && { entityCtx: options.entityCtx },
|
|
16672
16794
|
...options.scope !== void 0 && { scope: options.scope },
|
|
@@ -18749,6 +18871,7 @@ function createLocalMemoryStore(options) {
|
|
|
18749
18871
|
database,
|
|
18750
18872
|
entityCollection: database.get("entity"),
|
|
18751
18873
|
memoryEntityCollection: database.get("memory_entity"),
|
|
18874
|
+
canWrite: options.canWrite,
|
|
18752
18875
|
...userId !== void 0 && { userId },
|
|
18753
18876
|
...options.allowUnscopedRows !== void 0 && {
|
|
18754
18877
|
allowUnscopedRows: options.allowUnscopedRows
|
|
@@ -18760,10 +18883,21 @@ function createLocalMemoryStore(options) {
|
|
|
18760
18883
|
walletAddress: options.walletAddress,
|
|
18761
18884
|
signMessage: options.signMessage,
|
|
18762
18885
|
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
18886
|
+
canWrite: options.canWrite,
|
|
18763
18887
|
...userId !== void 0 && { userId },
|
|
18764
18888
|
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
18765
18889
|
entityCtx
|
|
18766
18890
|
};
|
|
18891
|
+
const assertWrite = async (writeOptions) => {
|
|
18892
|
+
writeOptions?.signal?.throwIfAborted();
|
|
18893
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
|
|
18894
|
+
throw new Error("Memory source is no longer eligible");
|
|
18895
|
+
}
|
|
18896
|
+
if (options.canWrite && !await options.canWrite()) {
|
|
18897
|
+
throw new Error("Memory source is no longer eligible");
|
|
18898
|
+
}
|
|
18899
|
+
writeOptions?.signal?.throwIfAborted();
|
|
18900
|
+
};
|
|
18767
18901
|
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
18768
18902
|
const ownedBy = userId !== void 0 ? [Q8.where("user_id", userId)] : [];
|
|
18769
18903
|
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [Q8.or(Q8.where("user_id", userId), Q8.where("user_id", null))] : [Q8.where("user_id", userId)];
|
|
@@ -18875,9 +19009,25 @@ function createLocalMemoryStore(options) {
|
|
|
18875
19009
|
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
18876
19010
|
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
18877
19011
|
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
18878
|
-
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
19012
|
+
addTopics: (memoryId, topics, writeOptions) => database.write(async (writer) => {
|
|
19013
|
+
await assertWrite(writeOptions);
|
|
18879
19014
|
const owned = await vaultCtx.vaultMemoryCollection.query(Q8.where("id", memoryId), Q8.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
18880
|
-
return owned > 0 ? writer.callWriter(
|
|
19015
|
+
return owned > 0 ? writer.callWriter(
|
|
19016
|
+
() => linkMemoryEntitiesOp(
|
|
19017
|
+
{
|
|
19018
|
+
...entityCtx,
|
|
19019
|
+
canWrite: async () => {
|
|
19020
|
+
await assertWrite(writeOptions);
|
|
19021
|
+
return true;
|
|
19022
|
+
}
|
|
19023
|
+
},
|
|
19024
|
+
memoryId,
|
|
19025
|
+
topics,
|
|
19026
|
+
{
|
|
19027
|
+
unlessTopicsUserManaged: writeOptions?.unlessUserManaged
|
|
19028
|
+
}
|
|
19029
|
+
)
|
|
19030
|
+
) : [];
|
|
18881
19031
|
}),
|
|
18882
19032
|
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
18883
19033
|
recall: (query, recallOptions) => recall(
|
|
@@ -18887,7 +19037,17 @@ function createLocalMemoryStore(options) {
|
|
|
18887
19037
|
),
|
|
18888
19038
|
retain: (content, retainOptions) => retain(
|
|
18889
19039
|
content,
|
|
18890
|
-
{
|
|
19040
|
+
{
|
|
19041
|
+
vaultCtx: {
|
|
19042
|
+
...vaultCtx,
|
|
19043
|
+
canWrite: async () => {
|
|
19044
|
+
await assertWrite(retainOptions);
|
|
19045
|
+
return true;
|
|
19046
|
+
}
|
|
19047
|
+
},
|
|
19048
|
+
embeddingOptions: options.embeddingOptions,
|
|
19049
|
+
vaultCache
|
|
19050
|
+
},
|
|
18891
19051
|
retainOptions
|
|
18892
19052
|
),
|
|
18893
19053
|
factSource: {
|
|
@@ -19524,7 +19684,14 @@ function stored(row) {
|
|
|
19524
19684
|
function createRemoteMemoryPipeline(options) {
|
|
19525
19685
|
const { persistence, embeddingOptions } = options;
|
|
19526
19686
|
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
19527
|
-
const operation = (mode) => {
|
|
19687
|
+
const operation = (mode, writeOptions) => {
|
|
19688
|
+
const signal = writeOptions?.signal;
|
|
19689
|
+
const assertWrite = async () => {
|
|
19690
|
+
signal?.throwIfAborted();
|
|
19691
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
19692
|
+
throw new Error("Memory source is no longer eligible");
|
|
19693
|
+
signal?.throwIfAborted();
|
|
19694
|
+
};
|
|
19528
19695
|
const rejectUndecryptable = (failed) => {
|
|
19529
19696
|
if (!failed.length) return;
|
|
19530
19697
|
if (mode === "retain")
|
|
@@ -19542,7 +19709,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19542
19709
|
return items.map((item) => stored(item.memory));
|
|
19543
19710
|
};
|
|
19544
19711
|
const get = async (id) => {
|
|
19545
|
-
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
19712
|
+
const snapshot = snapshots.get(id) ?? await (signal ? persistence.get(id, signal) : persistence.get(id));
|
|
19546
19713
|
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
19547
19714
|
snapshots.set(id, snapshot);
|
|
19548
19715
|
return stored(snapshot.memory);
|
|
@@ -19588,7 +19755,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19588
19755
|
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
19589
19756
|
}
|
|
19590
19757
|
const forceIds = [...forced];
|
|
19591
|
-
const windowOptions = (i,
|
|
19758
|
+
const windowOptions = (i, signal2) => ({
|
|
19592
19759
|
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
19593
19760
|
force_ids: i === 0 ? forceIds : [],
|
|
19594
19761
|
...search.scopes && { scopes: search.scopes },
|
|
@@ -19596,13 +19763,15 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19596
19763
|
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
19597
19764
|
include_archived: search.includeArchived,
|
|
19598
19765
|
embedding_model: model,
|
|
19599
|
-
...
|
|
19766
|
+
...signal2 && { signal: signal2 }
|
|
19600
19767
|
});
|
|
19601
19768
|
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
19602
19769
|
let windows;
|
|
19603
19770
|
if (mode === "retain") {
|
|
19604
19771
|
windows = await Promise.all(
|
|
19605
|
-
vectors.map(
|
|
19772
|
+
vectors.map(
|
|
19773
|
+
(embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i, signal))
|
|
19774
|
+
)
|
|
19606
19775
|
);
|
|
19607
19776
|
} else {
|
|
19608
19777
|
const deadline = new AbortController();
|
|
@@ -19690,12 +19859,15 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19690
19859
|
twin_opt_in: false
|
|
19691
19860
|
};
|
|
19692
19861
|
};
|
|
19693
|
-
const write = async (memory, snapshot) =>
|
|
19862
|
+
const write = async (memory, snapshot) => {
|
|
19863
|
+
await assertWrite();
|
|
19864
|
+
return remember([await persistence.put(memory, snapshot, signal)])[0];
|
|
19865
|
+
};
|
|
19694
19866
|
const port = {
|
|
19695
19867
|
prepare,
|
|
19696
19868
|
get,
|
|
19697
19869
|
getFresh: async (id) => {
|
|
19698
|
-
const current = await persistence.get(id);
|
|
19870
|
+
const current = await (signal ? persistence.get(id, signal) : persistence.get(id));
|
|
19699
19871
|
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
19700
19872
|
},
|
|
19701
19873
|
tombstones: async (embedding2, embeddingModel, scope, folderId) => {
|
|
@@ -19706,7 +19878,8 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19706
19878
|
embedding_model: embeddingModel,
|
|
19707
19879
|
strict_model: true,
|
|
19708
19880
|
include_deleted: true,
|
|
19709
|
-
deleted_only: true
|
|
19881
|
+
deleted_only: true,
|
|
19882
|
+
signal
|
|
19710
19883
|
});
|
|
19711
19884
|
rejectUndecryptable(window2.failed);
|
|
19712
19885
|
return remember(window2.items);
|
|
@@ -19762,14 +19935,18 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19762
19935
|
if (!target || !newer || id === successor) return false;
|
|
19763
19936
|
const old = snapshots.get(id);
|
|
19764
19937
|
const next = snapshots.get(successor);
|
|
19938
|
+
await assertWrite();
|
|
19765
19939
|
remember(
|
|
19766
|
-
await persistence.putMany(
|
|
19767
|
-
|
|
19768
|
-
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
19772
|
-
|
|
19940
|
+
await persistence.putMany(
|
|
19941
|
+
[
|
|
19942
|
+
{
|
|
19943
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
19944
|
+
expectedVersion: old
|
|
19945
|
+
},
|
|
19946
|
+
{ memory: next.memory, expectedVersion: next }
|
|
19947
|
+
],
|
|
19948
|
+
signal
|
|
19949
|
+
)
|
|
19773
19950
|
);
|
|
19774
19951
|
return true;
|
|
19775
19952
|
},
|
|
@@ -19778,18 +19955,22 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19778
19955
|
if (!target) return { created: null, retired: false };
|
|
19779
19956
|
const snapshot = snapshots.get(targetId);
|
|
19780
19957
|
const successor = createRow(input);
|
|
19958
|
+
await assertWrite();
|
|
19781
19959
|
const rows = remember(
|
|
19782
|
-
await persistence.putMany(
|
|
19783
|
-
|
|
19784
|
-
|
|
19785
|
-
|
|
19786
|
-
|
|
19787
|
-
|
|
19788
|
-
|
|
19789
|
-
|
|
19790
|
-
|
|
19791
|
-
|
|
19792
|
-
|
|
19960
|
+
await persistence.putMany(
|
|
19961
|
+
[
|
|
19962
|
+
{ memory: successor, expectedVersion: 0 },
|
|
19963
|
+
{
|
|
19964
|
+
memory: {
|
|
19965
|
+
...snapshot.memory,
|
|
19966
|
+
superseded_by: successor.memory_id,
|
|
19967
|
+
superseded_at: Date.now()
|
|
19968
|
+
},
|
|
19969
|
+
expectedVersion: snapshot
|
|
19970
|
+
}
|
|
19971
|
+
],
|
|
19972
|
+
signal
|
|
19973
|
+
)
|
|
19793
19974
|
);
|
|
19794
19975
|
return { created: rows[0], retired: true };
|
|
19795
19976
|
}
|
|
@@ -19822,7 +20003,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
19822
20003
|
factSource,
|
|
19823
20004
|
recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
|
|
19824
20005
|
retain: async (content, retainOptions) => {
|
|
19825
|
-
const { port } = operation("retain");
|
|
20006
|
+
const { port } = operation("retain", retainOptions);
|
|
19826
20007
|
return retainWithPersistence(
|
|
19827
20008
|
content,
|
|
19828
20009
|
{
|
|
@@ -20404,16 +20585,21 @@ function createRemoteMemoryStore(options) {
|
|
|
20404
20585
|
const record2 = await persistence.get(id);
|
|
20405
20586
|
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
20406
20587
|
};
|
|
20407
|
-
const mutateLocked = async (id, change, edit) => {
|
|
20408
|
-
|
|
20588
|
+
const mutateLocked = async (id, change, edit, writeOptions) => {
|
|
20589
|
+
writeOptions?.signal?.throwIfAborted();
|
|
20590
|
+
const record2 = writeOptions?.signal ? await persistence.get(id, writeOptions.signal) : await live(id);
|
|
20409
20591
|
if (!record2) return null;
|
|
20592
|
+
if (record2.memory.is_deleted) return null;
|
|
20593
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
20594
|
+
throw new Error("Memory source is no longer eligible");
|
|
20595
|
+
writeOptions?.signal?.throwIfAborted();
|
|
20410
20596
|
const next = edit(structuredClone(record2.memory));
|
|
20411
20597
|
if (!next) return null;
|
|
20412
|
-
const saved = await persistence.put(next, record2);
|
|
20598
|
+
const saved = writeOptions?.signal ? await persistence.put(next, record2, writeOptions.signal) : await persistence.put(next, record2);
|
|
20413
20599
|
notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
|
|
20414
20600
|
return saved;
|
|
20415
20601
|
};
|
|
20416
|
-
const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
|
|
20602
|
+
const mutate = (id, change, edit, writeOptions) => serialized(id, () => mutateLocked(id, change, edit, writeOptions));
|
|
20417
20603
|
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
|
|
20418
20604
|
const mutateMany = async (ids, change, edit) => {
|
|
20419
20605
|
const saved = /* @__PURE__ */ new Map();
|
|
@@ -20926,13 +21112,21 @@ function createRemoteMemoryStore(options) {
|
|
|
20926
21112
|
}))
|
|
20927
21113
|
);
|
|
20928
21114
|
},
|
|
20929
|
-
addTopics: async (memoryId, topics) => {
|
|
21115
|
+
addTopics: async (memoryId, topics, writeOptions) => {
|
|
20930
21116
|
const added = await withKnownKinds(topicInputs(topics, "auto"));
|
|
20931
|
-
const saved = await mutate(
|
|
20932
|
-
|
|
20933
|
-
|
|
20934
|
-
|
|
20935
|
-
|
|
21117
|
+
const saved = await mutate(
|
|
21118
|
+
memoryId,
|
|
21119
|
+
"edit",
|
|
21120
|
+
(memory) => {
|
|
21121
|
+
if (writeOptions?.unlessUserManaged && memory.topics_user_managed) return null;
|
|
21122
|
+
return {
|
|
21123
|
+
...memory,
|
|
21124
|
+
topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
|
|
21125
|
+
topics_updated_at: Date.now()
|
|
21126
|
+
};
|
|
21127
|
+
},
|
|
21128
|
+
writeOptions
|
|
21129
|
+
);
|
|
20936
21130
|
if (!saved) return [];
|
|
20937
21131
|
const now = /* @__PURE__ */ new Date();
|
|
20938
21132
|
return mergeTopics([], added).map(
|
|
@@ -21783,6 +21977,7 @@ function createDurableAutoExtractor(options) {
|
|
|
21783
21977
|
};
|
|
21784
21978
|
const folderId = options.folderId ?? null;
|
|
21785
21979
|
let disposed = false;
|
|
21980
|
+
let activeBatch = null;
|
|
21786
21981
|
let running = false;
|
|
21787
21982
|
let wakeRequested = false;
|
|
21788
21983
|
let timer;
|
|
@@ -21819,14 +22014,18 @@ function createDurableAutoExtractor(options) {
|
|
|
21819
22014
|
}, delay);
|
|
21820
22015
|
}
|
|
21821
22016
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
22017
|
+
if (disposed) throw new Error("Extraction session was disposed");
|
|
21822
22018
|
let watchdog;
|
|
21823
22019
|
let cancelled = false;
|
|
22020
|
+
const controller = new AbortController();
|
|
22021
|
+
activeBatch = controller;
|
|
21824
22022
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
21825
22023
|
try {
|
|
21826
22024
|
return await Promise.race([
|
|
21827
22025
|
new Promise((resolve, reject) => {
|
|
21828
22026
|
const worker = createAutoExtractor({
|
|
21829
22027
|
...options,
|
|
22028
|
+
signal: controller.signal,
|
|
21830
22029
|
retainCtx: {
|
|
21831
22030
|
...options.retainCtx,
|
|
21832
22031
|
vaultCtx: {
|
|
@@ -21855,6 +22054,8 @@ function createDurableAutoExtractor(options) {
|
|
|
21855
22054
|
]);
|
|
21856
22055
|
} finally {
|
|
21857
22056
|
cancelled = true;
|
|
22057
|
+
controller.abort();
|
|
22058
|
+
if (activeBatch === controller) activeBatch = null;
|
|
21858
22059
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
21859
22060
|
}
|
|
21860
22061
|
}
|
|
@@ -21866,6 +22067,7 @@ function createDurableAutoExtractor(options) {
|
|
|
21866
22067
|
for (const message of loaded)
|
|
21867
22068
|
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
21868
22069
|
await database.write(async () => {
|
|
22070
|
+
if (disposed) return;
|
|
21869
22071
|
const current = idsOf(job);
|
|
21870
22072
|
const acknowledged = ids.filter((id) => current.includes(id));
|
|
21871
22073
|
if (!acknowledged.length) return;
|
|
@@ -22038,6 +22240,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22038
22240
|
jobScope,
|
|
22039
22241
|
jobFolderId
|
|
22040
22242
|
);
|
|
22243
|
+
if (disposed) throw new Error("Extraction session was disposed");
|
|
22041
22244
|
options.onTurnComplete?.(result);
|
|
22042
22245
|
return result;
|
|
22043
22246
|
};
|
|
@@ -22074,6 +22277,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22074
22277
|
);
|
|
22075
22278
|
scheduleAfterSuccess = true;
|
|
22076
22279
|
} catch (error) {
|
|
22280
|
+
if (disposed) break;
|
|
22077
22281
|
attempts.set(job.id, attempted + 1);
|
|
22078
22282
|
retry = true;
|
|
22079
22283
|
reportError(error, conversationId);
|
|
@@ -22096,6 +22300,14 @@ function createDurableAutoExtractor(options) {
|
|
|
22096
22300
|
schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
|
|
22097
22301
|
}
|
|
22098
22302
|
}
|
|
22303
|
+
function dispose() {
|
|
22304
|
+
disposed = true;
|
|
22305
|
+
activeBatch?.abort(options.signal?.reason);
|
|
22306
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
22307
|
+
options.signal?.removeEventListener("abort", dispose);
|
|
22308
|
+
}
|
|
22309
|
+
if (options.signal?.aborted) dispose();
|
|
22310
|
+
else options.signal?.addEventListener("abort", dispose, { once: true });
|
|
22099
22311
|
schedule(0);
|
|
22100
22312
|
return {
|
|
22101
22313
|
processTurn(messages, conversationId) {
|
|
@@ -22175,10 +22387,7 @@ function createDurableAutoExtractor(options) {
|
|
|
22175
22387
|
return true;
|
|
22176
22388
|
},
|
|
22177
22389
|
isProcessing: () => running,
|
|
22178
|
-
dispose
|
|
22179
|
-
disposed = true;
|
|
22180
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
22181
|
-
}
|
|
22390
|
+
dispose
|
|
22182
22391
|
};
|
|
22183
22392
|
}
|
|
22184
22393
|
|
|
@@ -25427,6 +25636,7 @@ var CONVERSATION_REDACTOR_LIMIT = 50;
|
|
|
25427
25636
|
var NO_CONVERSATION_KEY = "__no_conversation__";
|
|
25428
25637
|
var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
|
|
25429
25638
|
var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
|
|
25639
|
+
var MEMORY_STORE_NOT_READY = "Memory store is not ready";
|
|
25430
25640
|
var conversationRedactors = /* @__PURE__ */ new Map();
|
|
25431
25641
|
var clientToolFilterCache = /* @__PURE__ */ new Map();
|
|
25432
25642
|
function getConversationRedactor(conversationId, nerDetector) {
|
|
@@ -25571,7 +25781,7 @@ function useChatStorage(options) {
|
|
|
25571
25781
|
[resolvedPiiRedaction]
|
|
25572
25782
|
);
|
|
25573
25783
|
const maskEmbeddingInput = isPiiRedactor(resolvedPiiRedaction) ? maskForEmbedding : void 0;
|
|
25574
|
-
const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
|
|
25784
|
+
const storeMaskMissing = memoryStore !== void 0 && memoryStore !== null && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
|
|
25575
25785
|
const messagesCollection = useMemo(() => database.get("history"), [database]);
|
|
25576
25786
|
const conversationsCollection = useMemo(
|
|
25577
25787
|
() => database.get("conversations"),
|
|
@@ -25820,6 +26030,7 @@ function useChatStorage(options) {
|
|
|
25820
26030
|
}, [vaultEmbeddingCache]);
|
|
25821
26031
|
const retainVaultMemory = useCallback4(
|
|
25822
26032
|
async (input) => {
|
|
26033
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
25823
26034
|
if (memoryStore) {
|
|
25824
26035
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
25825
26036
|
if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
|
|
@@ -25865,6 +26076,7 @@ function useChatStorage(options) {
|
|
|
25865
26076
|
);
|
|
25866
26077
|
const createMemoryVaultTool2 = useCallback4(
|
|
25867
26078
|
(options2) => {
|
|
26079
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
25868
26080
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
25869
26081
|
return createMemoryVaultTool(
|
|
25870
26082
|
memoryStore ?? vaultCtx,
|
|
@@ -25875,6 +26087,7 @@ function useChatStorage(options) {
|
|
|
25875
26087
|
);
|
|
25876
26088
|
const createRecallTool2 = useCallback4(
|
|
25877
26089
|
(toolOptions, callbacks) => {
|
|
26090
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
25878
26091
|
if (!getToken && !memoryStore) {
|
|
25879
26092
|
throw new Error("getToken is required for recall tool");
|
|
25880
26093
|
}
|
|
@@ -25920,7 +26133,7 @@ function useChatStorage(options) {
|
|
|
25920
26133
|
);
|
|
25921
26134
|
const recallFn = useCallback4(
|
|
25922
26135
|
async (query, options2) => {
|
|
25923
|
-
if (!getToken && !memoryStore) {
|
|
26136
|
+
if (memoryStore === null || !getToken && !memoryStore) {
|
|
25924
26137
|
return {
|
|
25925
26138
|
memories: [],
|
|
25926
26139
|
usedBudget: options2?.budget ?? "low",
|
|
@@ -25969,6 +26182,7 @@ function useChatStorage(options) {
|
|
|
25969
26182
|
);
|
|
25970
26183
|
const getVaultMemories = useCallback4(
|
|
25971
26184
|
(options2) => {
|
|
26185
|
+
if (memoryStore === null) return Promise.resolve([]);
|
|
25972
26186
|
if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
|
|
25973
26187
|
const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
|
|
25974
26188
|
if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
|
|
@@ -25979,7 +26193,8 @@ function useChatStorage(options) {
|
|
|
25979
26193
|
[vaultCtx, memoryStore]
|
|
25980
26194
|
);
|
|
25981
26195
|
const deleteVaultMemory = useCallback4(
|
|
25982
|
-
(id) => {
|
|
26196
|
+
async (id) => {
|
|
26197
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
25983
26198
|
return memoryStore ? memoryStore.delete(id) : deleteVaultMemoryOp(vaultCtx, id);
|
|
25984
26199
|
},
|
|
25985
26200
|
[vaultCtx, memoryStore]
|