@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/react/index.mjs
CHANGED
|
@@ -2681,8 +2681,9 @@ async function getConversationsByProjectOp(ctx, projectId) {
|
|
|
2681
2681
|
)
|
|
2682
2682
|
);
|
|
2683
2683
|
}
|
|
2684
|
-
async function getMessagesOp(ctx, convId) {
|
|
2685
|
-
const
|
|
2684
|
+
async function getMessagesOp(ctx, convId, opts) {
|
|
2685
|
+
const fetched = await ctx.messagesCollection.query(Q.where("conversation_id", convId), Q.sortBy("message_id", Q.asc)).unsafeFetchRaw();
|
|
2686
|
+
const results = opts?.rawFilter ? fetched.filter(opts.rawFilter) : fetched;
|
|
2686
2687
|
return Promise.all(
|
|
2687
2688
|
results.map(
|
|
2688
2689
|
(raw) => messageRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
@@ -4927,6 +4928,37 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
|
|
|
4927
4928
|
}));
|
|
4928
4929
|
return updateMessageChunksOp(ctx, messageId, messageChunks, embeddingModel);
|
|
4929
4930
|
}
|
|
4931
|
+
var MIN_SEALED_EMBEDDING_HEX = 256;
|
|
4932
|
+
function rawHasEmbedding(value) {
|
|
4933
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
4934
|
+
if (typeof value !== "string" || value.length === 0) return false;
|
|
4935
|
+
if (isEncrypted(value)) {
|
|
4936
|
+
return value.length - value.indexOf(":", 4) - 1 >= MIN_SEALED_EMBEDDING_HEX;
|
|
4937
|
+
}
|
|
4938
|
+
try {
|
|
4939
|
+
const parsed = JSON.parse(value);
|
|
4940
|
+
return Array.isArray(parsed) && parsed.length > 0;
|
|
4941
|
+
} catch {
|
|
4942
|
+
return false;
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
function sealedVersion(value) {
|
|
4946
|
+
if (typeof value !== "string" || !isEncrypted(value)) return null;
|
|
4947
|
+
return value.startsWith("enc:v2:") ? "v2" : "v3";
|
|
4948
|
+
}
|
|
4949
|
+
function mayNeedChunkEmbedding(raw, embeddingModel, filter) {
|
|
4950
|
+
const role = raw.role;
|
|
4951
|
+
if (role === "system") return false;
|
|
4952
|
+
if (filter?.roles && !filter.roles.includes(role ?? "")) return false;
|
|
4953
|
+
if (isNonEmbeddableOrigin(raw.origin, filter?.reembedDiscarded)) {
|
|
4954
|
+
return false;
|
|
4955
|
+
}
|
|
4956
|
+
const model = raw.embedding_model;
|
|
4957
|
+
if (typeof model === "string" && model !== embeddingModel) return true;
|
|
4958
|
+
if (rawHasEmbedding(raw.chunks)) return false;
|
|
4959
|
+
if (rawHasEmbedding(raw.vector) && !filter?.rechunkExisting) return false;
|
|
4960
|
+
return true;
|
|
4961
|
+
}
|
|
4930
4962
|
async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
4931
4963
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
4932
4964
|
const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
|
|
@@ -4939,11 +4971,31 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4939
4971
|
let considered = 0;
|
|
4940
4972
|
let sealedRowsSeen = 0;
|
|
4941
4973
|
let rowsSeen = 0;
|
|
4974
|
+
const keptSealed = /* @__PURE__ */ new Map();
|
|
4975
|
+
const candidatesStillSealed = /* @__PURE__ */ new Map();
|
|
4976
|
+
const droppedSealed = /* @__PURE__ */ new Map();
|
|
4977
|
+
const rawFilter = (raw) => {
|
|
4978
|
+
rowsSeen++;
|
|
4979
|
+
const keep = mayNeedChunkEmbedding(raw, embeddingModel, filter);
|
|
4980
|
+
const version = sealedVersion(raw.content);
|
|
4981
|
+
if (!version) return keep;
|
|
4982
|
+
if (keep) {
|
|
4983
|
+
keptSealed.set(version, (keptSealed.get(version) ?? 0) + 1);
|
|
4984
|
+
} else {
|
|
4985
|
+
const dropped = droppedSealed.get(version);
|
|
4986
|
+
if (dropped) dropped.count++;
|
|
4987
|
+
else droppedSealed.set(version, { count: 1, probeId: raw.id });
|
|
4988
|
+
}
|
|
4989
|
+
return keep;
|
|
4990
|
+
};
|
|
4942
4991
|
for (const conv of targetConversations) {
|
|
4943
|
-
const messages = await getMessagesOp(ctx, conv.conversationId);
|
|
4992
|
+
const messages = await getMessagesOp(ctx, conv.conversationId, { rawFilter });
|
|
4944
4993
|
for (const message of messages) {
|
|
4945
|
-
|
|
4946
|
-
if (
|
|
4994
|
+
const stillSealed = sealedVersion(message.content);
|
|
4995
|
+
if (stillSealed) {
|
|
4996
|
+
sealedRowsSeen++;
|
|
4997
|
+
candidatesStillSealed.set(stillSealed, (candidatesStillSealed.get(stillSealed) ?? 0) + 1);
|
|
4998
|
+
}
|
|
4947
4999
|
const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
|
|
4948
5000
|
if (message.chunks && message.chunks.length > 0 && !isStale) continue;
|
|
4949
5001
|
const hasVector = message.vector && message.vector.length > 0;
|
|
@@ -4956,6 +5008,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4956
5008
|
stillEncrypted++;
|
|
4957
5009
|
continue;
|
|
4958
5010
|
}
|
|
5011
|
+
if (isToolResultsRow(message)) continue;
|
|
4959
5012
|
if (message.content.length < minLength) continue;
|
|
4960
5013
|
if (shouldChunkMessage(message.content, chunkSize)) {
|
|
4961
5014
|
longMessages.push({
|
|
@@ -4967,6 +5020,12 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4967
5020
|
}
|
|
4968
5021
|
}
|
|
4969
5022
|
}
|
|
5023
|
+
for (const [version, dropped] of droppedSealed) {
|
|
5024
|
+
const keyOpenedACandidate = (keptSealed.get(version) ?? 0) > (candidatesStillSealed.get(version) ?? 0);
|
|
5025
|
+
if (keyOpenedACandidate) continue;
|
|
5026
|
+
const probe = await getMessageOp(ctx, dropped.probeId);
|
|
5027
|
+
if (!probe || isEncrypted(probe.content)) sealedRowsSeen += dropped.count;
|
|
5028
|
+
}
|
|
4970
5029
|
if (stillEncrypted > 0 || sealedRowsSeen > 0) {
|
|
4971
5030
|
getLogger().error(
|
|
4972
5031
|
"memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
|
|
@@ -10414,6 +10473,11 @@ function parseTopics(value) {
|
|
|
10414
10473
|
}
|
|
10415
10474
|
|
|
10416
10475
|
// src/lib/db/entities/operations.ts
|
|
10476
|
+
async function assertCanWrite(ctx) {
|
|
10477
|
+
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
10478
|
+
throw new Error("Memory source is no longer eligible");
|
|
10479
|
+
}
|
|
10480
|
+
}
|
|
10417
10481
|
function entityToStored(e) {
|
|
10418
10482
|
return {
|
|
10419
10483
|
uniqueId: e.id,
|
|
@@ -10554,6 +10618,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
10554
10618
|
let skipped = false;
|
|
10555
10619
|
let entities = [];
|
|
10556
10620
|
await ctx.database.write(async () => {
|
|
10621
|
+
await assertCanWrite(ctx);
|
|
10557
10622
|
const {
|
|
10558
10623
|
entities: byName,
|
|
10559
10624
|
operations: entityOps,
|
|
@@ -10629,6 +10694,7 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
10629
10694
|
let skipped = false;
|
|
10630
10695
|
let entities = [];
|
|
10631
10696
|
await ctx.database.write(async () => {
|
|
10697
|
+
await assertCanWrite(ctx);
|
|
10632
10698
|
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
10633
10699
|
if (options.guarded && autoLinkBlocked(vaultRow)) {
|
|
10634
10700
|
skipped = true;
|
|
@@ -10689,6 +10755,7 @@ async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
|
|
|
10689
10755
|
const links = await ctx.memoryEntityCollection.query(Q5.where("memory_id", Q5.oneOf(Array.from(memoryIds)))).fetch();
|
|
10690
10756
|
if (links.length === 0) return;
|
|
10691
10757
|
await ctx.database.write(async () => {
|
|
10758
|
+
await assertCanWrite(ctx);
|
|
10692
10759
|
await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
|
|
10693
10760
|
});
|
|
10694
10761
|
}
|
|
@@ -10697,6 +10764,7 @@ async function unlinkAllMemoryEntitiesForUserOp(ctx, userId) {
|
|
|
10697
10764
|
const links = await ctx.memoryEntityCollection.query(Q5.where("user_id", userId)).fetch();
|
|
10698
10765
|
if (links.length === 0) return;
|
|
10699
10766
|
await ctx.database.write(async () => {
|
|
10767
|
+
await assertCanWrite(ctx);
|
|
10700
10768
|
await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
|
|
10701
10769
|
});
|
|
10702
10770
|
}
|
|
@@ -10716,6 +10784,7 @@ async function backfillMemoryEntityUserIdsOp(ctx, vaultMemoryCollection) {
|
|
|
10716
10784
|
}
|
|
10717
10785
|
if (toUpdate.length === 0) return 0;
|
|
10718
10786
|
await ctx.database.write(async () => {
|
|
10787
|
+
await assertCanWrite(ctx);
|
|
10719
10788
|
await ctx.database.batch(
|
|
10720
10789
|
...toUpdate.map(({ link, userId }) => link.prepareUpdate((r) => r._setRaw("user_id", userId)))
|
|
10721
10790
|
);
|
|
@@ -13109,6 +13178,11 @@ function visibilityConditions(requested) {
|
|
|
13109
13178
|
function isKinded(record2) {
|
|
13110
13179
|
return record2.kind !== null && record2.kind !== void 0;
|
|
13111
13180
|
}
|
|
13181
|
+
async function assertCanWrite2(ctx) {
|
|
13182
|
+
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
13183
|
+
throw new Error("Memory source is no longer eligible");
|
|
13184
|
+
}
|
|
13185
|
+
}
|
|
13112
13186
|
function assertValidKindLevel(kind, level) {
|
|
13113
13187
|
const hasKind = kind !== null && kind !== void 0;
|
|
13114
13188
|
if (hasKind && !MEMORY_KINDS.includes(kind)) {
|
|
@@ -13289,8 +13363,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
13289
13363
|
ctx.embeddedWalletSigner
|
|
13290
13364
|
) : opts.content;
|
|
13291
13365
|
const created = await ctx.database.write(async () => {
|
|
13292
|
-
|
|
13293
|
-
throw new Error("Memory source is no longer eligible");
|
|
13366
|
+
await assertCanWrite2(ctx);
|
|
13294
13367
|
return ctx.vaultMemoryCollection.create(
|
|
13295
13368
|
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
13296
13369
|
);
|
|
@@ -13309,8 +13382,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
13309
13382
|
) : opts.content;
|
|
13310
13383
|
let createdRecord = null;
|
|
13311
13384
|
await ctx.database.write(async () => {
|
|
13312
|
-
|
|
13313
|
-
throw new Error("Memory source is no longer eligible");
|
|
13385
|
+
await assertCanWrite2(ctx);
|
|
13314
13386
|
let target;
|
|
13315
13387
|
try {
|
|
13316
13388
|
target = await ctx.vaultMemoryCollection.find(targetId);
|
|
@@ -13402,8 +13474,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
13402
13474
|
})
|
|
13403
13475
|
);
|
|
13404
13476
|
const created = await ctx.database.write(async () => {
|
|
13405
|
-
|
|
13406
|
-
throw new Error("Memory source is no longer eligible");
|
|
13477
|
+
await assertCanWrite2(ctx);
|
|
13407
13478
|
const prepared = optionsArray.map(
|
|
13408
13479
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
13409
13480
|
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
@@ -13708,8 +13779,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
13708
13779
|
const record2 = probe;
|
|
13709
13780
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13710
13781
|
await ctx.database.write(async () => {
|
|
13711
|
-
|
|
13712
|
-
throw new Error("Memory source is no longer eligible");
|
|
13782
|
+
await assertCanWrite2(ctx);
|
|
13713
13783
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
13714
13784
|
stale = true;
|
|
13715
13785
|
return;
|
|
@@ -13820,6 +13890,7 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
13820
13890
|
let stale = false;
|
|
13821
13891
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13822
13892
|
await ctx.database.write(async (writer) => {
|
|
13893
|
+
await assertCanWrite2(ctx);
|
|
13823
13894
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13824
13895
|
stale = true;
|
|
13825
13896
|
return;
|
|
@@ -13861,6 +13932,7 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
13861
13932
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13862
13933
|
let cleared = false;
|
|
13863
13934
|
await ctx.database.write(async () => {
|
|
13935
|
+
await assertCanWrite2(ctx);
|
|
13864
13936
|
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
13865
13937
|
cleared = true;
|
|
13866
13938
|
await record2.update((r) => {
|
|
@@ -13884,6 +13956,7 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
13884
13956
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
13885
13957
|
let stale = false;
|
|
13886
13958
|
await ctx.database.write(async () => {
|
|
13959
|
+
await assertCanWrite2(ctx);
|
|
13887
13960
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13888
13961
|
stale = true;
|
|
13889
13962
|
return;
|
|
@@ -13912,6 +13985,7 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
13912
13985
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13913
13986
|
let stale = false;
|
|
13914
13987
|
await ctx.database.write(async () => {
|
|
13988
|
+
await assertCanWrite2(ctx);
|
|
13915
13989
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13916
13990
|
stale = true;
|
|
13917
13991
|
return;
|
|
@@ -13949,8 +14023,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
13949
14023
|
}
|
|
13950
14024
|
let stale = false;
|
|
13951
14025
|
await ctx.database.write(async () => {
|
|
13952
|
-
|
|
13953
|
-
throw new Error("Memory source is no longer eligible");
|
|
14026
|
+
await assertCanWrite2(ctx);
|
|
13954
14027
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
13955
14028
|
stale = true;
|
|
13956
14029
|
return;
|
|
@@ -14112,6 +14185,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
14112
14185
|
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
14113
14186
|
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
14114
14187
|
await ctx.database.write(async () => {
|
|
14188
|
+
await assertCanWrite2(ctx);
|
|
14115
14189
|
const records = [];
|
|
14116
14190
|
for (const id of chunkIds) {
|
|
14117
14191
|
try {
|
|
@@ -14145,6 +14219,7 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
14145
14219
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
14146
14220
|
try {
|
|
14147
14221
|
await ctx.database.write(async (writer) => {
|
|
14222
|
+
await assertCanWrite2(ctx);
|
|
14148
14223
|
let record2;
|
|
14149
14224
|
try {
|
|
14150
14225
|
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
@@ -14175,6 +14250,7 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
14175
14250
|
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
14176
14251
|
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
14177
14252
|
await ctx.database.write(async () => {
|
|
14253
|
+
await assertCanWrite2(ctx);
|
|
14178
14254
|
const writes = [];
|
|
14179
14255
|
for (const id of chunkIds) {
|
|
14180
14256
|
let record2;
|
|
@@ -14207,6 +14283,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
14207
14283
|
const records = await ctx.vaultMemoryCollection.query(Q8.where("user_id", userId), Q8.where("is_deleted", false)).fetch();
|
|
14208
14284
|
if (records.length === 0) return 0;
|
|
14209
14285
|
await ctx.database.write(async () => {
|
|
14286
|
+
await assertCanWrite2(ctx);
|
|
14210
14287
|
const prepared = records.map(
|
|
14211
14288
|
(record2) => record2.prepareUpdate((r) => {
|
|
14212
14289
|
r._setRaw("is_deleted", true);
|
|
@@ -14261,6 +14338,7 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
14261
14338
|
let stale = false;
|
|
14262
14339
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
14263
14340
|
await ctx.database.write(async () => {
|
|
14341
|
+
await assertCanWrite2(ctx);
|
|
14264
14342
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
14265
14343
|
stale = true;
|
|
14266
14344
|
return;
|
|
@@ -14284,6 +14362,7 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
14284
14362
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
14285
14363
|
let stale = false;
|
|
14286
14364
|
await ctx.database.write(async () => {
|
|
14365
|
+
await assertCanWrite2(ctx);
|
|
14287
14366
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
14288
14367
|
stale = true;
|
|
14289
14368
|
return;
|
|
@@ -14304,6 +14383,7 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
14304
14383
|
const now = opts.now ?? Date.now();
|
|
14305
14384
|
let stale = false;
|
|
14306
14385
|
await ctx.database.write(async () => {
|
|
14386
|
+
await assertCanWrite2(ctx);
|
|
14307
14387
|
const archivedAt = record2.archivedAt;
|
|
14308
14388
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
14309
14389
|
stale = true;
|
|
@@ -14343,6 +14423,7 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding2, embeddingModel,
|
|
|
14343
14423
|
}
|
|
14344
14424
|
let written = false;
|
|
14345
14425
|
await ctx.database.write(async () => {
|
|
14426
|
+
await assertCanWrite2(ctx);
|
|
14346
14427
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
14347
14428
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
14348
14429
|
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
@@ -18312,6 +18393,13 @@ function restoreCandidates(candidates, redactor, ownNames) {
|
|
|
18312
18393
|
).map((c) => c.candidate);
|
|
18313
18394
|
}
|
|
18314
18395
|
async function extractAndRetain(messages, retainCtx, options) {
|
|
18396
|
+
const { memoryStore, signal } = options;
|
|
18397
|
+
if (memoryStore === null) throw new Error("Memory store is not ready");
|
|
18398
|
+
if (memoryStore && options.folderId !== void 0 && options.folderId !== null)
|
|
18399
|
+
throw new Error("Remote memory extraction does not support folders");
|
|
18400
|
+
if (memoryStore && options.extract.piiRedaction && !memoryStore.masksEmbeddingInput)
|
|
18401
|
+
throw new Error("PII-redacted extraction requires a memory store that masks embedding inputs");
|
|
18402
|
+
signal?.throwIfAborted();
|
|
18315
18403
|
const minConfidence = options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
|
|
18316
18404
|
const resolvedConsolidatePii = options.consolidateOptions?.piiRedaction ?? options.extract.piiRedaction;
|
|
18317
18405
|
const consolidateOptions = options.consolidateOptions !== void 0 ? {
|
|
@@ -18345,6 +18433,7 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
18345
18433
|
}
|
|
18346
18434
|
});
|
|
18347
18435
|
const extractMs = Date.now() - tExtract;
|
|
18436
|
+
signal?.throwIfAborted();
|
|
18348
18437
|
const filtered = candidates.filter((c) => c.confidence >= minConfidence);
|
|
18349
18438
|
const log = getLogger();
|
|
18350
18439
|
const screened = screenCandidatesForInjection(filtered);
|
|
@@ -18392,16 +18481,33 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
18392
18481
|
const results = [];
|
|
18393
18482
|
const quarantinedInfo = [];
|
|
18394
18483
|
let failedWrites = 0;
|
|
18484
|
+
let auditRows;
|
|
18395
18485
|
const tRetain = Date.now();
|
|
18396
18486
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
18397
18487
|
try {
|
|
18488
|
+
signal?.throwIfAborted();
|
|
18398
18489
|
if (isQuarantined) {
|
|
18399
|
-
|
|
18400
|
-
|
|
18401
|
-
|
|
18402
|
-
|
|
18403
|
-
|
|
18404
|
-
|
|
18490
|
+
let existingId;
|
|
18491
|
+
if (memoryStore) {
|
|
18492
|
+
auditRows ?? (auditRows = memoryStore.list({
|
|
18493
|
+
scopes: [options.scope ?? "private"],
|
|
18494
|
+
includeArchived: true,
|
|
18495
|
+
includeQuarantined: true,
|
|
18496
|
+
includeSuperseded: true
|
|
18497
|
+
}));
|
|
18498
|
+
const sourceKey = [...new Set(candidate.sourceMessageIds)].sort().join("\0");
|
|
18499
|
+
const normalize = (value) => value.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
18500
|
+
existingId = (await auditRows).find(
|
|
18501
|
+
(row) => row.trustTier === "quarantined" && row.scope === (options.scope ?? "private") && [...new Set(row.sourceChunkIds ?? [])].sort().join("\0") === sourceKey && normalize(row.content) === normalize(candidate.content)
|
|
18502
|
+
)?.uniqueId ?? null;
|
|
18503
|
+
} else {
|
|
18504
|
+
existingId = await findQuarantinedDuplicateOp(
|
|
18505
|
+
retainCtx.vaultCtx,
|
|
18506
|
+
candidate.content,
|
|
18507
|
+
candidate.sourceMessageIds,
|
|
18508
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
18509
|
+
).catch(() => null);
|
|
18510
|
+
}
|
|
18405
18511
|
if (existingId) {
|
|
18406
18512
|
quarantinedInfo.push({
|
|
18407
18513
|
candidate,
|
|
@@ -18412,18 +18518,26 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
18412
18518
|
continue;
|
|
18413
18519
|
}
|
|
18414
18520
|
}
|
|
18415
|
-
const
|
|
18521
|
+
const retainOptions = {
|
|
18416
18522
|
source: "auto-extracted",
|
|
18417
18523
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
18418
18524
|
respectTombstones: true,
|
|
18419
18525
|
...options.scope !== void 0 && { scope: options.scope },
|
|
18420
|
-
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
18421
18526
|
...consolidateOptions !== void 0 && { consolidateOptions },
|
|
18422
18527
|
...candidate.eventTime !== null && { eventTime: candidate.eventTime },
|
|
18423
18528
|
factType: candidate.type,
|
|
18424
18529
|
...isQuarantined && { trustTier: "quarantined", enableAutoMerge: false }
|
|
18530
|
+
};
|
|
18531
|
+
const result = memoryStore ? await memoryStore.retain(candidate.content, {
|
|
18532
|
+
...retainOptions,
|
|
18533
|
+
canWrite: retainCtx.vaultCtx.canWrite,
|
|
18534
|
+
signal
|
|
18535
|
+
}) : await retain(candidate.content, retainCtx, {
|
|
18536
|
+
...retainOptions,
|
|
18537
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
18425
18538
|
});
|
|
18426
18539
|
if (isQuarantined) {
|
|
18540
|
+
auditRows = void 0;
|
|
18427
18541
|
const info = {
|
|
18428
18542
|
candidate,
|
|
18429
18543
|
memoryId: result.memoryId,
|
|
@@ -18442,9 +18556,16 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
18442
18556
|
}
|
|
18443
18557
|
succeededCandidates.push(candidate);
|
|
18444
18558
|
results.push(result);
|
|
18445
|
-
if (result.action !== "suppressed" &&
|
|
18559
|
+
if (result.action !== "suppressed" && candidate.entities.length > 0) {
|
|
18446
18560
|
try {
|
|
18447
|
-
|
|
18561
|
+
signal?.throwIfAborted();
|
|
18562
|
+
if (memoryStore) {
|
|
18563
|
+
await memoryStore.addTopics(result.memoryId, candidate.entities, {
|
|
18564
|
+
unlessUserManaged: true,
|
|
18565
|
+
canWrite: retainCtx.vaultCtx.canWrite,
|
|
18566
|
+
signal
|
|
18567
|
+
});
|
|
18568
|
+
} else if (options.entityCtx && !await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
|
|
18448
18569
|
await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
|
|
18449
18570
|
unlessTopicsUserManaged: true
|
|
18450
18571
|
});
|
|
@@ -18692,7 +18813,7 @@ function createAutoExtractor(options) {
|
|
|
18692
18813
|
};
|
|
18693
18814
|
const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
|
|
18694
18815
|
const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
|
|
18695
|
-
if (options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
|
|
18816
|
+
if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
|
|
18696
18817
|
getLogger().warn(
|
|
18697
18818
|
"[memory/extract] retainCtx.vaultCtx.entityCtx is set but extractor was created without `entityCtx` \u2014 W5 graph lane will receive no writes"
|
|
18698
18819
|
);
|
|
@@ -18737,6 +18858,8 @@ function createAutoExtractor(options) {
|
|
|
18737
18858
|
try {
|
|
18738
18859
|
const { candidates, results, failedCount, outcome: outcome2, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
|
|
18739
18860
|
extract,
|
|
18861
|
+
memoryStore: options.memoryStore,
|
|
18862
|
+
signal: options.signal,
|
|
18740
18863
|
...options.minConfidence !== void 0 && { minConfidence: options.minConfidence },
|
|
18741
18864
|
...options.entityCtx !== void 0 && { entityCtx: options.entityCtx },
|
|
18742
18865
|
...options.scope !== void 0 && { scope: options.scope },
|
|
@@ -20845,6 +20968,7 @@ function createLocalMemoryStore(options) {
|
|
|
20845
20968
|
database,
|
|
20846
20969
|
entityCollection: database.get("entity"),
|
|
20847
20970
|
memoryEntityCollection: database.get("memory_entity"),
|
|
20971
|
+
canWrite: options.canWrite,
|
|
20848
20972
|
...userId !== void 0 && { userId },
|
|
20849
20973
|
...options.allowUnscopedRows !== void 0 && {
|
|
20850
20974
|
allowUnscopedRows: options.allowUnscopedRows
|
|
@@ -20856,10 +20980,21 @@ function createLocalMemoryStore(options) {
|
|
|
20856
20980
|
walletAddress: options.walletAddress,
|
|
20857
20981
|
signMessage: options.signMessage,
|
|
20858
20982
|
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
20983
|
+
canWrite: options.canWrite,
|
|
20859
20984
|
...userId !== void 0 && { userId },
|
|
20860
20985
|
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
20861
20986
|
entityCtx
|
|
20862
20987
|
};
|
|
20988
|
+
const assertWrite = async (writeOptions) => {
|
|
20989
|
+
writeOptions?.signal?.throwIfAborted();
|
|
20990
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
|
|
20991
|
+
throw new Error("Memory source is no longer eligible");
|
|
20992
|
+
}
|
|
20993
|
+
if (options.canWrite && !await options.canWrite()) {
|
|
20994
|
+
throw new Error("Memory source is no longer eligible");
|
|
20995
|
+
}
|
|
20996
|
+
writeOptions?.signal?.throwIfAborted();
|
|
20997
|
+
};
|
|
20863
20998
|
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
20864
20999
|
const ownedBy = userId !== void 0 ? [Q15.where("user_id", userId)] : [];
|
|
20865
21000
|
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [Q15.or(Q15.where("user_id", userId), Q15.where("user_id", null))] : [Q15.where("user_id", userId)];
|
|
@@ -20971,9 +21106,25 @@ function createLocalMemoryStore(options) {
|
|
|
20971
21106
|
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
20972
21107
|
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
20973
21108
|
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
20974
|
-
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
21109
|
+
addTopics: (memoryId, topics, writeOptions) => database.write(async (writer) => {
|
|
21110
|
+
await assertWrite(writeOptions);
|
|
20975
21111
|
const owned = await vaultCtx.vaultMemoryCollection.query(Q15.where("id", memoryId), Q15.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
20976
|
-
return owned > 0 ? writer.callWriter(
|
|
21112
|
+
return owned > 0 ? writer.callWriter(
|
|
21113
|
+
() => linkMemoryEntitiesOp(
|
|
21114
|
+
{
|
|
21115
|
+
...entityCtx,
|
|
21116
|
+
canWrite: async () => {
|
|
21117
|
+
await assertWrite(writeOptions);
|
|
21118
|
+
return true;
|
|
21119
|
+
}
|
|
21120
|
+
},
|
|
21121
|
+
memoryId,
|
|
21122
|
+
topics,
|
|
21123
|
+
{
|
|
21124
|
+
unlessTopicsUserManaged: writeOptions?.unlessUserManaged
|
|
21125
|
+
}
|
|
21126
|
+
)
|
|
21127
|
+
) : [];
|
|
20977
21128
|
}),
|
|
20978
21129
|
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
20979
21130
|
recall: (query, recallOptions) => recall(
|
|
@@ -20983,7 +21134,17 @@ function createLocalMemoryStore(options) {
|
|
|
20983
21134
|
),
|
|
20984
21135
|
retain: (content, retainOptions) => retain(
|
|
20985
21136
|
content,
|
|
20986
|
-
{
|
|
21137
|
+
{
|
|
21138
|
+
vaultCtx: {
|
|
21139
|
+
...vaultCtx,
|
|
21140
|
+
canWrite: async () => {
|
|
21141
|
+
await assertWrite(retainOptions);
|
|
21142
|
+
return true;
|
|
21143
|
+
}
|
|
21144
|
+
},
|
|
21145
|
+
embeddingOptions: options.embeddingOptions,
|
|
21146
|
+
vaultCache
|
|
21147
|
+
},
|
|
20987
21148
|
retainOptions
|
|
20988
21149
|
),
|
|
20989
21150
|
factSource: {
|
|
@@ -21620,7 +21781,14 @@ function stored(row) {
|
|
|
21620
21781
|
function createRemoteMemoryPipeline(options) {
|
|
21621
21782
|
const { persistence, embeddingOptions } = options;
|
|
21622
21783
|
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
21623
|
-
const operation = (mode) => {
|
|
21784
|
+
const operation = (mode, writeOptions) => {
|
|
21785
|
+
const signal = writeOptions?.signal;
|
|
21786
|
+
const assertWrite = async () => {
|
|
21787
|
+
signal?.throwIfAborted();
|
|
21788
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
21789
|
+
throw new Error("Memory source is no longer eligible");
|
|
21790
|
+
signal?.throwIfAborted();
|
|
21791
|
+
};
|
|
21624
21792
|
const rejectUndecryptable = (failed) => {
|
|
21625
21793
|
if (!failed.length) return;
|
|
21626
21794
|
if (mode === "retain")
|
|
@@ -21638,7 +21806,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21638
21806
|
return items.map((item) => stored(item.memory));
|
|
21639
21807
|
};
|
|
21640
21808
|
const get = async (id) => {
|
|
21641
|
-
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
21809
|
+
const snapshot = snapshots.get(id) ?? await (signal ? persistence.get(id, signal) : persistence.get(id));
|
|
21642
21810
|
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
21643
21811
|
snapshots.set(id, snapshot);
|
|
21644
21812
|
return stored(snapshot.memory);
|
|
@@ -21684,7 +21852,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21684
21852
|
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
21685
21853
|
}
|
|
21686
21854
|
const forceIds = [...forced];
|
|
21687
|
-
const windowOptions = (i,
|
|
21855
|
+
const windowOptions = (i, signal2) => ({
|
|
21688
21856
|
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
21689
21857
|
force_ids: i === 0 ? forceIds : [],
|
|
21690
21858
|
...search.scopes && { scopes: search.scopes },
|
|
@@ -21692,13 +21860,15 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21692
21860
|
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
21693
21861
|
include_archived: search.includeArchived,
|
|
21694
21862
|
embedding_model: model,
|
|
21695
|
-
...
|
|
21863
|
+
...signal2 && { signal: signal2 }
|
|
21696
21864
|
});
|
|
21697
21865
|
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
21698
21866
|
let windows;
|
|
21699
21867
|
if (mode === "retain") {
|
|
21700
21868
|
windows = await Promise.all(
|
|
21701
|
-
vectors.map(
|
|
21869
|
+
vectors.map(
|
|
21870
|
+
(embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i, signal))
|
|
21871
|
+
)
|
|
21702
21872
|
);
|
|
21703
21873
|
} else {
|
|
21704
21874
|
const deadline = new AbortController();
|
|
@@ -21786,12 +21956,15 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21786
21956
|
twin_opt_in: false
|
|
21787
21957
|
};
|
|
21788
21958
|
};
|
|
21789
|
-
const write = async (memory, snapshot) =>
|
|
21959
|
+
const write = async (memory, snapshot) => {
|
|
21960
|
+
await assertWrite();
|
|
21961
|
+
return remember([await persistence.put(memory, snapshot, signal)])[0];
|
|
21962
|
+
};
|
|
21790
21963
|
const port = {
|
|
21791
21964
|
prepare,
|
|
21792
21965
|
get,
|
|
21793
21966
|
getFresh: async (id) => {
|
|
21794
|
-
const current = await persistence.get(id);
|
|
21967
|
+
const current = await (signal ? persistence.get(id, signal) : persistence.get(id));
|
|
21795
21968
|
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
21796
21969
|
},
|
|
21797
21970
|
tombstones: async (embedding2, embeddingModel, scope, folderId) => {
|
|
@@ -21802,7 +21975,8 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21802
21975
|
embedding_model: embeddingModel,
|
|
21803
21976
|
strict_model: true,
|
|
21804
21977
|
include_deleted: true,
|
|
21805
|
-
deleted_only: true
|
|
21978
|
+
deleted_only: true,
|
|
21979
|
+
signal
|
|
21806
21980
|
});
|
|
21807
21981
|
rejectUndecryptable(window2.failed);
|
|
21808
21982
|
return remember(window2.items);
|
|
@@ -21858,14 +22032,18 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21858
22032
|
if (!target || !newer || id === successor) return false;
|
|
21859
22033
|
const old = snapshots.get(id);
|
|
21860
22034
|
const next = snapshots.get(successor);
|
|
22035
|
+
await assertWrite();
|
|
21861
22036
|
remember(
|
|
21862
|
-
await persistence.putMany(
|
|
21863
|
-
|
|
21864
|
-
|
|
21865
|
-
|
|
21866
|
-
|
|
21867
|
-
|
|
21868
|
-
|
|
22037
|
+
await persistence.putMany(
|
|
22038
|
+
[
|
|
22039
|
+
{
|
|
22040
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
22041
|
+
expectedVersion: old
|
|
22042
|
+
},
|
|
22043
|
+
{ memory: next.memory, expectedVersion: next }
|
|
22044
|
+
],
|
|
22045
|
+
signal
|
|
22046
|
+
)
|
|
21869
22047
|
);
|
|
21870
22048
|
return true;
|
|
21871
22049
|
},
|
|
@@ -21874,18 +22052,22 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21874
22052
|
if (!target) return { created: null, retired: false };
|
|
21875
22053
|
const snapshot = snapshots.get(targetId);
|
|
21876
22054
|
const successor = createRow(input);
|
|
22055
|
+
await assertWrite();
|
|
21877
22056
|
const rows = remember(
|
|
21878
|
-
await persistence.putMany(
|
|
21879
|
-
|
|
21880
|
-
|
|
21881
|
-
|
|
21882
|
-
|
|
21883
|
-
|
|
21884
|
-
|
|
21885
|
-
|
|
21886
|
-
|
|
21887
|
-
|
|
21888
|
-
|
|
22057
|
+
await persistence.putMany(
|
|
22058
|
+
[
|
|
22059
|
+
{ memory: successor, expectedVersion: 0 },
|
|
22060
|
+
{
|
|
22061
|
+
memory: {
|
|
22062
|
+
...snapshot.memory,
|
|
22063
|
+
superseded_by: successor.memory_id,
|
|
22064
|
+
superseded_at: Date.now()
|
|
22065
|
+
},
|
|
22066
|
+
expectedVersion: snapshot
|
|
22067
|
+
}
|
|
22068
|
+
],
|
|
22069
|
+
signal
|
|
22070
|
+
)
|
|
21889
22071
|
);
|
|
21890
22072
|
return { created: rows[0], retired: true };
|
|
21891
22073
|
}
|
|
@@ -21918,7 +22100,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
21918
22100
|
factSource,
|
|
21919
22101
|
recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
|
|
21920
22102
|
retain: async (content, retainOptions) => {
|
|
21921
|
-
const { port } = operation("retain");
|
|
22103
|
+
const { port } = operation("retain", retainOptions);
|
|
21922
22104
|
return retainWithPersistence(
|
|
21923
22105
|
content,
|
|
21924
22106
|
{
|
|
@@ -22500,16 +22682,21 @@ function createRemoteMemoryStore(options) {
|
|
|
22500
22682
|
const record2 = await persistence.get(id);
|
|
22501
22683
|
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
22502
22684
|
};
|
|
22503
|
-
const mutateLocked = async (id, change, edit) => {
|
|
22504
|
-
|
|
22685
|
+
const mutateLocked = async (id, change, edit, writeOptions) => {
|
|
22686
|
+
writeOptions?.signal?.throwIfAborted();
|
|
22687
|
+
const record2 = writeOptions?.signal ? await persistence.get(id, writeOptions.signal) : await live(id);
|
|
22505
22688
|
if (!record2) return null;
|
|
22689
|
+
if (record2.memory.is_deleted) return null;
|
|
22690
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
22691
|
+
throw new Error("Memory source is no longer eligible");
|
|
22692
|
+
writeOptions?.signal?.throwIfAborted();
|
|
22506
22693
|
const next = edit(structuredClone(record2.memory));
|
|
22507
22694
|
if (!next) return null;
|
|
22508
|
-
const saved = await persistence.put(next, record2);
|
|
22695
|
+
const saved = writeOptions?.signal ? await persistence.put(next, record2, writeOptions.signal) : await persistence.put(next, record2);
|
|
22509
22696
|
notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
|
|
22510
22697
|
return saved;
|
|
22511
22698
|
};
|
|
22512
|
-
const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
|
|
22699
|
+
const mutate = (id, change, edit, writeOptions) => serialized(id, () => mutateLocked(id, change, edit, writeOptions));
|
|
22513
22700
|
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
|
|
22514
22701
|
const mutateMany = async (ids, change, edit) => {
|
|
22515
22702
|
const saved = /* @__PURE__ */ new Map();
|
|
@@ -23022,13 +23209,21 @@ function createRemoteMemoryStore(options) {
|
|
|
23022
23209
|
}))
|
|
23023
23210
|
);
|
|
23024
23211
|
},
|
|
23025
|
-
addTopics: async (memoryId, topics) => {
|
|
23212
|
+
addTopics: async (memoryId, topics, writeOptions) => {
|
|
23026
23213
|
const added = await withKnownKinds(topicInputs(topics, "auto"));
|
|
23027
|
-
const saved = await mutate(
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
|
|
23031
|
-
|
|
23214
|
+
const saved = await mutate(
|
|
23215
|
+
memoryId,
|
|
23216
|
+
"edit",
|
|
23217
|
+
(memory) => {
|
|
23218
|
+
if (writeOptions?.unlessUserManaged && memory.topics_user_managed) return null;
|
|
23219
|
+
return {
|
|
23220
|
+
...memory,
|
|
23221
|
+
topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
|
|
23222
|
+
topics_updated_at: Date.now()
|
|
23223
|
+
};
|
|
23224
|
+
},
|
|
23225
|
+
writeOptions
|
|
23226
|
+
);
|
|
23032
23227
|
if (!saved) return [];
|
|
23033
23228
|
const now = /* @__PURE__ */ new Date();
|
|
23034
23229
|
return mergeTopics([], added).map(
|
|
@@ -23879,6 +24074,7 @@ function createDurableAutoExtractor(options) {
|
|
|
23879
24074
|
};
|
|
23880
24075
|
const folderId = options.folderId ?? null;
|
|
23881
24076
|
let disposed = false;
|
|
24077
|
+
let activeBatch = null;
|
|
23882
24078
|
let running = false;
|
|
23883
24079
|
let wakeRequested = false;
|
|
23884
24080
|
let timer;
|
|
@@ -23915,14 +24111,18 @@ function createDurableAutoExtractor(options) {
|
|
|
23915
24111
|
}, delay);
|
|
23916
24112
|
}
|
|
23917
24113
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
24114
|
+
if (disposed) throw new Error("Extraction session was disposed");
|
|
23918
24115
|
let watchdog;
|
|
23919
24116
|
let cancelled = false;
|
|
24117
|
+
const controller = new AbortController();
|
|
24118
|
+
activeBatch = controller;
|
|
23920
24119
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
23921
24120
|
try {
|
|
23922
24121
|
return await Promise.race([
|
|
23923
24122
|
new Promise((resolve, reject) => {
|
|
23924
24123
|
const worker = createAutoExtractor({
|
|
23925
24124
|
...options,
|
|
24125
|
+
signal: controller.signal,
|
|
23926
24126
|
retainCtx: {
|
|
23927
24127
|
...options.retainCtx,
|
|
23928
24128
|
vaultCtx: {
|
|
@@ -23951,6 +24151,8 @@ function createDurableAutoExtractor(options) {
|
|
|
23951
24151
|
]);
|
|
23952
24152
|
} finally {
|
|
23953
24153
|
cancelled = true;
|
|
24154
|
+
controller.abort();
|
|
24155
|
+
if (activeBatch === controller) activeBatch = null;
|
|
23954
24156
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
23955
24157
|
}
|
|
23956
24158
|
}
|
|
@@ -23962,6 +24164,7 @@ function createDurableAutoExtractor(options) {
|
|
|
23962
24164
|
for (const message of loaded)
|
|
23963
24165
|
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
23964
24166
|
await database.write(async () => {
|
|
24167
|
+
if (disposed) return;
|
|
23965
24168
|
const current = idsOf(job);
|
|
23966
24169
|
const acknowledged = ids.filter((id) => current.includes(id));
|
|
23967
24170
|
if (!acknowledged.length) return;
|
|
@@ -24134,6 +24337,7 @@ function createDurableAutoExtractor(options) {
|
|
|
24134
24337
|
jobScope,
|
|
24135
24338
|
jobFolderId
|
|
24136
24339
|
);
|
|
24340
|
+
if (disposed) throw new Error("Extraction session was disposed");
|
|
24137
24341
|
options.onTurnComplete?.(result);
|
|
24138
24342
|
return result;
|
|
24139
24343
|
};
|
|
@@ -24170,6 +24374,7 @@ function createDurableAutoExtractor(options) {
|
|
|
24170
24374
|
);
|
|
24171
24375
|
scheduleAfterSuccess = true;
|
|
24172
24376
|
} catch (error) {
|
|
24377
|
+
if (disposed) break;
|
|
24173
24378
|
attempts.set(job.id, attempted + 1);
|
|
24174
24379
|
retry = true;
|
|
24175
24380
|
reportError(error, conversationId);
|
|
@@ -24192,6 +24397,14 @@ function createDurableAutoExtractor(options) {
|
|
|
24192
24397
|
schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
|
|
24193
24398
|
}
|
|
24194
24399
|
}
|
|
24400
|
+
function dispose() {
|
|
24401
|
+
disposed = true;
|
|
24402
|
+
activeBatch?.abort(options.signal?.reason);
|
|
24403
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
24404
|
+
options.signal?.removeEventListener("abort", dispose);
|
|
24405
|
+
}
|
|
24406
|
+
if (options.signal?.aborted) dispose();
|
|
24407
|
+
else options.signal?.addEventListener("abort", dispose, { once: true });
|
|
24195
24408
|
schedule(0);
|
|
24196
24409
|
return {
|
|
24197
24410
|
processTurn(messages, conversationId) {
|
|
@@ -24271,10 +24484,7 @@ function createDurableAutoExtractor(options) {
|
|
|
24271
24484
|
return true;
|
|
24272
24485
|
},
|
|
24273
24486
|
isProcessing: () => running,
|
|
24274
|
-
dispose
|
|
24275
|
-
disposed = true;
|
|
24276
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
24277
|
-
}
|
|
24487
|
+
dispose
|
|
24278
24488
|
};
|
|
24279
24489
|
}
|
|
24280
24490
|
|
|
@@ -30535,6 +30745,7 @@ var CONVERSATION_REDACTOR_LIMIT = 50;
|
|
|
30535
30745
|
var NO_CONVERSATION_KEY = "__no_conversation__";
|
|
30536
30746
|
var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
|
|
30537
30747
|
var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
|
|
30748
|
+
var MEMORY_STORE_NOT_READY = "Memory store is not ready";
|
|
30538
30749
|
var conversationRedactors = /* @__PURE__ */ new Map();
|
|
30539
30750
|
function getConversationRedactor(conversationId, nerDetector) {
|
|
30540
30751
|
const key = conversationId ?? NO_CONVERSATION_KEY;
|
|
@@ -30625,7 +30836,7 @@ function useChatStorage(options) {
|
|
|
30625
30836
|
() => ({ getToken, baseUrl, model: embeddingModel, maskInput: maskEmbeddingInput }),
|
|
30626
30837
|
[getToken, baseUrl, embeddingModel, maskEmbeddingInput]
|
|
30627
30838
|
);
|
|
30628
|
-
const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
|
|
30839
|
+
const storeMaskMissing = memoryStore !== void 0 && memoryStore !== null && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
|
|
30629
30840
|
const blobManagerRef = useRef4(new BlobUrlManager());
|
|
30630
30841
|
useEffect4(() => {
|
|
30631
30842
|
const manager = blobManagerRef.current;
|
|
@@ -30902,6 +31113,7 @@ function useChatStorage(options) {
|
|
|
30902
31113
|
);
|
|
30903
31114
|
const retainVaultMemory = useCallback5(
|
|
30904
31115
|
async (input) => {
|
|
31116
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
30905
31117
|
if (memoryStore) {
|
|
30906
31118
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
30907
31119
|
if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
|
|
@@ -30933,6 +31145,7 @@ function useChatStorage(options) {
|
|
|
30933
31145
|
);
|
|
30934
31146
|
const createMemoryVaultTool2 = useCallback5(
|
|
30935
31147
|
(options2) => {
|
|
31148
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
30936
31149
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
30937
31150
|
const embOpts = getToken ? vaultEmbeddingOptions : void 0;
|
|
30938
31151
|
return createMemoryVaultTool(
|
|
@@ -30954,6 +31167,7 @@ function useChatStorage(options) {
|
|
|
30954
31167
|
);
|
|
30955
31168
|
const getVaultMemories = useCallback5(
|
|
30956
31169
|
(options2) => {
|
|
31170
|
+
if (memoryStore === null) return Promise.resolve([]);
|
|
30957
31171
|
if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
|
|
30958
31172
|
const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
|
|
30959
31173
|
if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
|
|
@@ -30965,6 +31179,7 @@ function useChatStorage(options) {
|
|
|
30965
31179
|
);
|
|
30966
31180
|
const createVaultMemory = useCallback5(
|
|
30967
31181
|
async (content, scope) => {
|
|
31182
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
30968
31183
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
30969
31184
|
if (memoryStore) return memoryStore.create({ content, scope });
|
|
30970
31185
|
const result = await createVaultMemoryOp(vaultCtx, { content, scope });
|
|
@@ -30986,6 +31201,7 @@ function useChatStorage(options) {
|
|
|
30986
31201
|
);
|
|
30987
31202
|
const updateVaultMemory = useCallback5(
|
|
30988
31203
|
async (id, content, scope) => {
|
|
31204
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
30989
31205
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
30990
31206
|
if (memoryStore) return memoryStore.update(id, { content, scope });
|
|
30991
31207
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
@@ -31011,6 +31227,7 @@ function useChatStorage(options) {
|
|
|
31011
31227
|
);
|
|
31012
31228
|
const deleteVaultMemory = useCallback5(
|
|
31013
31229
|
async (id) => {
|
|
31230
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
31014
31231
|
if (memoryStore) return memoryStore.delete(id);
|
|
31015
31232
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
31016
31233
|
const result = await deleteVaultMemoryOp(vaultCtx, id);
|
|
@@ -31024,7 +31241,7 @@ function useChatStorage(options) {
|
|
|
31024
31241
|
const chunkVectorCacheRef = useRef4(createChunkVectorCache());
|
|
31025
31242
|
const clientToolEmbeddingsCacheRef = useRef4(/* @__PURE__ */ new Map());
|
|
31026
31243
|
useEffect4(() => {
|
|
31027
|
-
if (!getToken || memoryStore) return;
|
|
31244
|
+
if (!getToken || memoryStore !== void 0) return;
|
|
31028
31245
|
void (async () => {
|
|
31029
31246
|
try {
|
|
31030
31247
|
await preEmbedVaultMemories(vaultCtx, vaultEmbeddingOptions, vaultEmbeddingCache);
|
|
@@ -31040,6 +31257,7 @@ function useChatStorage(options) {
|
|
|
31040
31257
|
}, [vaultEmbeddingCache]);
|
|
31041
31258
|
const createMemoryVaultSearchTool2 = useCallback5(
|
|
31042
31259
|
(searchOptions) => {
|
|
31260
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
31043
31261
|
if (!getToken && !memoryStore) {
|
|
31044
31262
|
throw new Error("getToken is required for memory vault search tool");
|
|
31045
31263
|
}
|
|
@@ -31055,6 +31273,7 @@ function useChatStorage(options) {
|
|
|
31055
31273
|
);
|
|
31056
31274
|
const createRecallTool2 = useCallback5(
|
|
31057
31275
|
(toolOptions, callbacks) => {
|
|
31276
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
31058
31277
|
if (!getToken && !memoryStore) {
|
|
31059
31278
|
throw new Error("getToken is required for recall tool");
|
|
31060
31279
|
}
|
|
@@ -31094,6 +31313,7 @@ function useChatStorage(options) {
|
|
|
31094
31313
|
);
|
|
31095
31314
|
const searchVaultMemoriesFn = useCallback5(
|
|
31096
31315
|
async (query, searchOptions) => {
|
|
31316
|
+
if (memoryStore === null) return [];
|
|
31097
31317
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
31098
31318
|
if (memoryStore) return (await memoryStore.factSource.search(query, searchOptions)).results;
|
|
31099
31319
|
if (!getToken) return [];
|
|
@@ -31109,7 +31329,7 @@ function useChatStorage(options) {
|
|
|
31109
31329
|
);
|
|
31110
31330
|
const recallFn = useCallback5(
|
|
31111
31331
|
async (query, options2) => {
|
|
31112
|
-
if (!getToken && !memoryStore) {
|
|
31332
|
+
if (memoryStore === null || !getToken && !memoryStore) {
|
|
31113
31333
|
return {
|
|
31114
31334
|
memories: [],
|
|
31115
31335
|
usedBudget: options2?.budget ?? "low",
|