@anuma/sdk 6.33.2 → 6.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +1304 -300
- package/dist/expo/index.d.mts +278 -11
- package/dist/expo/index.d.ts +278 -11
- package/dist/expo/index.mjs +1297 -300
- package/dist/index.cjs +18 -6
- package/dist/index.mjs +18 -6
- package/dist/memory/context.d.mts +21 -1
- package/dist/memory/context.d.ts +21 -1
- package/dist/react/index.cjs +1385 -381
- package/dist/react/index.d.mts +311 -11
- package/dist/react/index.d.ts +311 -11
- package/dist/react/index.mjs +1378 -381
- package/dist/server/index.cjs +319 -99
- package/dist/server/index.d.mts +138 -11
- package/dist/server/index.d.ts +138 -11
- package/dist/server/index.mjs +316 -99
- package/dist/telemetry/index.d.mts +3 -4
- package/dist/telemetry/index.d.ts +3 -4
- package/dist/tools/selection/index.cjs +18 -6
- package/dist/tools/selection/index.mjs +18 -6
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -2622,13 +2622,13 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2622
2622
|
const storedById = new Map(
|
|
2623
2623
|
await Promise.all(
|
|
2624
2624
|
Array.from(uniqueMessages, async ([id, m]) => {
|
|
2625
|
-
const
|
|
2625
|
+
const stored2 = await messageRawToStored(
|
|
2626
2626
|
m,
|
|
2627
2627
|
ctx.walletAddress,
|
|
2628
2628
|
ctx.signMessage,
|
|
2629
2629
|
ctx.embeddedWalletSigner
|
|
2630
2630
|
);
|
|
2631
|
-
return [id,
|
|
2631
|
+
return [id, stored2];
|
|
2632
2632
|
})
|
|
2633
2633
|
)
|
|
2634
2634
|
);
|
|
@@ -2646,18 +2646,18 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2646
2646
|
})
|
|
2647
2647
|
);
|
|
2648
2648
|
return topK.map(({ message, similarity, chunkTextSource }) => {
|
|
2649
|
-
const
|
|
2649
|
+
const stored2 = { ...storedById.get(message.id) };
|
|
2650
2650
|
let chunkText2;
|
|
2651
2651
|
if (chunkTextSource.kind === "chunk") {
|
|
2652
|
-
chunkText2 = resolveChunkText(
|
|
2652
|
+
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
2653
2653
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
2654
2654
|
const state = chunkStateByMsgId.get(message.id);
|
|
2655
2655
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
2656
|
-
chunkText2 = resolveChunkText(
|
|
2656
|
+
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
2657
2657
|
} else {
|
|
2658
|
-
chunkText2 =
|
|
2658
|
+
chunkText2 = stored2.content;
|
|
2659
2659
|
}
|
|
2660
|
-
return { chunkText: chunkText2, message:
|
|
2660
|
+
return { chunkText: chunkText2, message: stored2, similarity };
|
|
2661
2661
|
});
|
|
2662
2662
|
}
|
|
2663
2663
|
function makeSyntheticStoredMessage(opts) {
|
|
@@ -3776,7 +3776,7 @@ async function embedOne(text12, options, outer) {
|
|
|
3776
3776
|
}
|
|
3777
3777
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
3778
3778
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
3779
|
-
async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs) {
|
|
3779
|
+
async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs, outer) {
|
|
3780
3780
|
const response = await withEmbeddingRetry(
|
|
3781
3781
|
() => withDeadline(
|
|
3782
3782
|
(signal) => postApiV1Embeddings({
|
|
@@ -3786,8 +3786,10 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
|
|
|
3786
3786
|
...signal && { signal }
|
|
3787
3787
|
}),
|
|
3788
3788
|
timeoutMs,
|
|
3789
|
-
"embedding batch request"
|
|
3790
|
-
|
|
3789
|
+
"embedding batch request",
|
|
3790
|
+
outer
|
|
3791
|
+
),
|
|
3792
|
+
outer
|
|
3791
3793
|
);
|
|
3792
3794
|
if (response.error) {
|
|
3793
3795
|
throw embeddingErrorFrom(response);
|
|
@@ -3805,6 +3807,11 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
|
|
|
3805
3807
|
}
|
|
3806
3808
|
async function generateEmbeddings(texts, options) {
|
|
3807
3809
|
if (texts.length === 0) return [];
|
|
3810
|
+
const total = options.totalTimeoutMs;
|
|
3811
|
+
if (total === void 0) return embedMany(texts, options, void 0);
|
|
3812
|
+
return withDeadline((signal) => embedMany(texts, options, signal), total, "embedding batch");
|
|
3813
|
+
}
|
|
3814
|
+
async function embedMany(texts, options, outer) {
|
|
3808
3815
|
const { baseUrl = BASE_URL, model, batchSize, cache } = options;
|
|
3809
3816
|
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
3810
3817
|
const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
|
|
@@ -3825,7 +3832,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
3825
3832
|
if (uncachedTexts.length === 0) {
|
|
3826
3833
|
return results;
|
|
3827
3834
|
}
|
|
3828
|
-
const headers = await resolveAuthHeaders(options);
|
|
3835
|
+
const headers = await resolveAuthHeaders(options, outer);
|
|
3836
|
+
if (outer?.aborted) throw outer.reason;
|
|
3829
3837
|
const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
3830
3838
|
let newEmbeddings;
|
|
3831
3839
|
if (uncachedTexts.length <= chunkSize) {
|
|
@@ -3836,7 +3844,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
3836
3844
|
embeddingModel,
|
|
3837
3845
|
options.onUsage,
|
|
3838
3846
|
options.maskInput,
|
|
3839
|
-
timeoutMs
|
|
3847
|
+
timeoutMs,
|
|
3848
|
+
outer
|
|
3840
3849
|
);
|
|
3841
3850
|
} else {
|
|
3842
3851
|
const chunks = [];
|
|
@@ -3847,6 +3856,7 @@ async function generateEmbeddings(texts, options) {
|
|
|
3847
3856
|
let nextIndex = 0;
|
|
3848
3857
|
const worker = async () => {
|
|
3849
3858
|
while (nextIndex < chunks.length) {
|
|
3859
|
+
if (outer?.aborted) throw outer.reason;
|
|
3850
3860
|
const idx = nextIndex++;
|
|
3851
3861
|
allEmbeddings[idx] = await generateEmbeddingsBatch(
|
|
3852
3862
|
chunks[idx],
|
|
@@ -3855,7 +3865,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
3855
3865
|
embeddingModel,
|
|
3856
3866
|
options.onUsage,
|
|
3857
3867
|
options.maskInput,
|
|
3858
|
-
timeoutMs
|
|
3868
|
+
timeoutMs,
|
|
3869
|
+
outer
|
|
3859
3870
|
);
|
|
3860
3871
|
}
|
|
3861
3872
|
};
|
|
@@ -3866,6 +3877,7 @@ async function generateEmbeddings(texts, options) {
|
|
|
3866
3877
|
await Promise.all(workers);
|
|
3867
3878
|
newEmbeddings = allEmbeddings.flat();
|
|
3868
3879
|
}
|
|
3880
|
+
if (outer?.aborted) throw outer.reason;
|
|
3869
3881
|
for (let i = 0; i < uncachedIndices.length; i++) {
|
|
3870
3882
|
const f32Embedding = Float32Array.from(newEmbeddings[i]);
|
|
3871
3883
|
results[uncachedIndices[i]] = Array.from(f32Embedding);
|
|
@@ -8940,15 +8952,15 @@ function createSummaryContext(database) {
|
|
|
8940
8952
|
summariesCollection: database.get("conversation_summaries")
|
|
8941
8953
|
};
|
|
8942
8954
|
}
|
|
8943
|
-
function modelToStored(
|
|
8955
|
+
function modelToStored(record2) {
|
|
8944
8956
|
return {
|
|
8945
|
-
uniqueId:
|
|
8946
|
-
conversationId:
|
|
8947
|
-
summary:
|
|
8948
|
-
summarizedUpTo:
|
|
8949
|
-
tokenCount:
|
|
8950
|
-
createdAt:
|
|
8951
|
-
updatedAt:
|
|
8957
|
+
uniqueId: record2.id,
|
|
8958
|
+
conversationId: record2.conversationId,
|
|
8959
|
+
summary: record2.summary,
|
|
8960
|
+
summarizedUpTo: record2.summarizedUpTo,
|
|
8961
|
+
tokenCount: record2.tokenCount,
|
|
8962
|
+
createdAt: record2.createdAt,
|
|
8963
|
+
updatedAt: record2.updatedAt
|
|
8952
8964
|
};
|
|
8953
8965
|
}
|
|
8954
8966
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
@@ -8957,17 +8969,17 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
8957
8969
|
return modelToStored(results[0]);
|
|
8958
8970
|
}
|
|
8959
8971
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
8960
|
-
let
|
|
8972
|
+
let record2;
|
|
8961
8973
|
await ctx.database.write(async () => {
|
|
8962
8974
|
const existing = await ctx.summariesCollection.query(Q2.where("conversation_id", conversationId)).fetch();
|
|
8963
8975
|
if (existing.length > 0) {
|
|
8964
|
-
|
|
8976
|
+
record2 = await existing[0].update((rec) => {
|
|
8965
8977
|
rec.summary = summary;
|
|
8966
8978
|
rec.summarizedUpTo = summarizedUpTo;
|
|
8967
8979
|
rec.tokenCount = tokenCount;
|
|
8968
8980
|
});
|
|
8969
8981
|
} else {
|
|
8970
|
-
|
|
8982
|
+
record2 = await ctx.summariesCollection.create((rec) => {
|
|
8971
8983
|
rec.conversationId = conversationId;
|
|
8972
8984
|
rec.summary = summary;
|
|
8973
8985
|
rec.summarizedUpTo = summarizedUpTo;
|
|
@@ -8975,13 +8987,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
|
|
|
8975
8987
|
});
|
|
8976
8988
|
}
|
|
8977
8989
|
});
|
|
8978
|
-
return modelToStored(
|
|
8990
|
+
return modelToStored(record2);
|
|
8979
8991
|
}
|
|
8980
8992
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
8981
8993
|
await ctx.database.write(async () => {
|
|
8982
8994
|
const existing = await ctx.summariesCollection.query(Q2.where("conversation_id", conversationId)).fetch();
|
|
8983
|
-
for (const
|
|
8984
|
-
await
|
|
8995
|
+
for (const record2 of existing) {
|
|
8996
|
+
await record2.destroyPermanently();
|
|
8985
8997
|
}
|
|
8986
8998
|
});
|
|
8987
8999
|
}
|
|
@@ -9234,6 +9246,15 @@ __decorateClass([
|
|
|
9234
9246
|
__decorateClass([
|
|
9235
9247
|
text6("scope")
|
|
9236
9248
|
], VaultMemory.prototype, "scope", 2);
|
|
9249
|
+
__decorateClass([
|
|
9250
|
+
field5("kind")
|
|
9251
|
+
], VaultMemory.prototype, "kind", 2);
|
|
9252
|
+
__decorateClass([
|
|
9253
|
+
field5("kind_value")
|
|
9254
|
+
], VaultMemory.prototype, "kindValue", 2);
|
|
9255
|
+
__decorateClass([
|
|
9256
|
+
field5("level")
|
|
9257
|
+
], VaultMemory.prototype, "level", 2);
|
|
9237
9258
|
__decorateClass([
|
|
9238
9259
|
field5("folder_id")
|
|
9239
9260
|
], VaultMemory.prototype, "folderId", 2);
|
|
@@ -9459,7 +9480,7 @@ __decorateClass([
|
|
|
9459
9480
|
], VaultFolder.prototype, "context", 2);
|
|
9460
9481
|
|
|
9461
9482
|
// src/lib/db/schema.ts
|
|
9462
|
-
var SDK_SCHEMA_VERSION =
|
|
9483
|
+
var SDK_SCHEMA_VERSION = 48;
|
|
9463
9484
|
var sdkSchema = appSchema2({
|
|
9464
9485
|
version: SDK_SCHEMA_VERSION,
|
|
9465
9486
|
tables: [
|
|
@@ -9554,6 +9575,9 @@ var sdkSchema = appSchema2({
|
|
|
9554
9575
|
columns: [
|
|
9555
9576
|
{ name: "content", type: "string" },
|
|
9556
9577
|
{ name: "scope", type: "string", isIndexed: true },
|
|
9578
|
+
{ name: "kind", type: "string", isOptional: true, isIndexed: true },
|
|
9579
|
+
{ name: "kind_value", type: "string", isOptional: true },
|
|
9580
|
+
{ name: "level", type: "string", isOptional: true, isIndexed: true },
|
|
9557
9581
|
{ name: "folder_id", type: "string", isOptional: true, isIndexed: true },
|
|
9558
9582
|
{ name: "created_at", type: "number", isIndexed: true },
|
|
9559
9583
|
{ name: "updated_at", type: "number", isIndexed: true },
|
|
@@ -10230,6 +10254,22 @@ var sdkMigrations = schemaMigrations2({
|
|
|
10230
10254
|
]
|
|
10231
10255
|
})
|
|
10232
10256
|
]
|
|
10257
|
+
},
|
|
10258
|
+
{
|
|
10259
|
+
toVersion: 48,
|
|
10260
|
+
steps: [
|
|
10261
|
+
addColumns2({
|
|
10262
|
+
table: "memory_vault",
|
|
10263
|
+
columns: [
|
|
10264
|
+
{ name: "kind", type: "string", isOptional: true, isIndexed: true },
|
|
10265
|
+
{ name: "kind_value", type: "string", isOptional: true },
|
|
10266
|
+
{ name: "level", type: "string", isOptional: true, isIndexed: true }
|
|
10267
|
+
]
|
|
10268
|
+
}),
|
|
10269
|
+
unsafeExecuteSql(
|
|
10270
|
+
"UPDATE memory_vault SET level = CASE WHEN scope IN ('shared', 'public') THEN 'matching' ELSE 'private' END WHERE level IS NULL;"
|
|
10271
|
+
)
|
|
10272
|
+
]
|
|
10233
10273
|
}
|
|
10234
10274
|
]
|
|
10235
10275
|
});
|
|
@@ -10486,25 +10526,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
10486
10526
|
const kindBackfills = existing.filter((e) => {
|
|
10487
10527
|
const incoming = kindByName.get(e.canonicalName);
|
|
10488
10528
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
10489
|
-
}).map((
|
|
10529
|
+
}).map((record2) => ({ record: record2, kind: kindByName.get(record2.canonicalName) }));
|
|
10490
10530
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
10491
10531
|
const created = missing.map(
|
|
10492
|
-
(name) => ctx.entityCollection.prepareCreate((
|
|
10493
|
-
|
|
10532
|
+
(name) => ctx.entityCollection.prepareCreate((record2) => {
|
|
10533
|
+
record2._setRaw("canonical_name", name);
|
|
10494
10534
|
const kind = kindByName.get(name);
|
|
10495
|
-
if (kind !== void 0)
|
|
10535
|
+
if (kind !== void 0) record2._setRaw("kind", kind);
|
|
10496
10536
|
})
|
|
10497
10537
|
);
|
|
10498
10538
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
10499
|
-
for (const
|
|
10500
|
-
for (const { record, kind } of kindBackfills) {
|
|
10501
|
-
out.set(
|
|
10539
|
+
for (const record2 of created) out.set(record2.canonicalName, entityToStored(record2));
|
|
10540
|
+
for (const { record: record2, kind } of kindBackfills) {
|
|
10541
|
+
out.set(record2.canonicalName, { ...entityToStored(record2), kind });
|
|
10502
10542
|
}
|
|
10503
10543
|
return { entities: out, operations: created, kindBackfills };
|
|
10504
10544
|
}
|
|
10505
10545
|
function prepareKindBackfills(backfills) {
|
|
10506
10546
|
return backfills.map(
|
|
10507
|
-
({ record, kind }) =>
|
|
10547
|
+
({ record: record2, kind }) => record2.prepareUpdate((r) => {
|
|
10508
10548
|
r._setRaw("kind", kind);
|
|
10509
10549
|
})
|
|
10510
10550
|
);
|
|
@@ -10535,10 +10575,10 @@ function displayNamesOf(entities) {
|
|
|
10535
10575
|
}
|
|
10536
10576
|
return out;
|
|
10537
10577
|
}
|
|
10538
|
-
function topicsEqual(
|
|
10539
|
-
if (
|
|
10578
|
+
function topicsEqual(stored2, computed) {
|
|
10579
|
+
if (stored2 === null || stored2.length !== computed.length) return false;
|
|
10540
10580
|
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
10541
|
-
const storedKeys =
|
|
10581
|
+
const storedKeys = stored2.map(key).sort();
|
|
10542
10582
|
const computedKeys = computed.map(key).sort();
|
|
10543
10583
|
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
10544
10584
|
}
|
|
@@ -10604,10 +10644,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
10604
10644
|
return;
|
|
10605
10645
|
}
|
|
10606
10646
|
const linkOps = toCreate.map(
|
|
10607
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
if (userId !== void 0)
|
|
10647
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
10648
|
+
record2._setRaw("memory_id", memoryId);
|
|
10649
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
10650
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
10611
10651
|
})
|
|
10612
10652
|
);
|
|
10613
10653
|
await ctx.database.batch(
|
|
@@ -10675,10 +10715,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
10675
10715
|
...entityOps,
|
|
10676
10716
|
...prepareKindBackfills(kindBackfills),
|
|
10677
10717
|
...toCreate.map(
|
|
10678
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
if (userId !== void 0)
|
|
10718
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
10719
|
+
record2._setRaw("memory_id", memoryId);
|
|
10720
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
10721
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
10682
10722
|
})
|
|
10683
10723
|
),
|
|
10684
10724
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
@@ -10795,13 +10835,54 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
|
|
|
10795
10835
|
}
|
|
10796
10836
|
}
|
|
10797
10837
|
const decryptedContent = await decryptField(memory.content, address);
|
|
10838
|
+
const decryptedKindValue = typeof memory.kindValue === "string" ? await decryptField(memory.kindValue, address) : memory.kindValue;
|
|
10798
10839
|
return {
|
|
10799
10840
|
...memory,
|
|
10800
|
-
content: decryptedContent
|
|
10841
|
+
content: decryptedContent,
|
|
10842
|
+
...decryptedKindValue !== void 0 && { kindValue: decryptedKindValue }
|
|
10801
10843
|
};
|
|
10802
10844
|
}
|
|
10803
10845
|
|
|
10804
10846
|
// src/lib/db/memoryVault/types.ts
|
|
10847
|
+
var MEMORY_KINDS = [
|
|
10848
|
+
"display_name",
|
|
10849
|
+
"birth_date",
|
|
10850
|
+
"bio",
|
|
10851
|
+
"occupation",
|
|
10852
|
+
"interest",
|
|
10853
|
+
"gender",
|
|
10854
|
+
"height_cm",
|
|
10855
|
+
"looking_for",
|
|
10856
|
+
"politics",
|
|
10857
|
+
"religion",
|
|
10858
|
+
"ethnicity",
|
|
10859
|
+
"smoking",
|
|
10860
|
+
"drinking",
|
|
10861
|
+
"exercise",
|
|
10862
|
+
"sexuality",
|
|
10863
|
+
"prompt"
|
|
10864
|
+
];
|
|
10865
|
+
var MEMORY_LEVELS = ["private", "matching", "profile"];
|
|
10866
|
+
var MemoryLevelError = class extends Error {
|
|
10867
|
+
constructor(message) {
|
|
10868
|
+
super(message);
|
|
10869
|
+
this.name = "MemoryLevelError";
|
|
10870
|
+
}
|
|
10871
|
+
};
|
|
10872
|
+
var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
|
|
10873
|
+
function levelFromScope(scope) {
|
|
10874
|
+
return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
|
|
10875
|
+
}
|
|
10876
|
+
function scopeForLevel(level) {
|
|
10877
|
+
return level === "private" ? "private" : "shared";
|
|
10878
|
+
}
|
|
10879
|
+
function resolveMemoryLevel(level, scope) {
|
|
10880
|
+
return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
|
|
10881
|
+
}
|
|
10882
|
+
function levelForScopeChange(current, nextScope) {
|
|
10883
|
+
const implied = levelFromScope(nextScope);
|
|
10884
|
+
return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
|
|
10885
|
+
}
|
|
10805
10886
|
function parseMedia(value) {
|
|
10806
10887
|
if (typeof value !== "string" || value === "") return null;
|
|
10807
10888
|
try {
|
|
@@ -10831,8 +10912,58 @@ function visibilityConditions(requested) {
|
|
|
10831
10912
|
if (excluded.length === 0) return [];
|
|
10832
10913
|
return [Q5.or(Q5.where("visibility", null), Q5.where("visibility", Q5.notIn(excluded)))];
|
|
10833
10914
|
}
|
|
10834
|
-
function
|
|
10835
|
-
return
|
|
10915
|
+
function isKinded(record2) {
|
|
10916
|
+
return record2.kind !== null && record2.kind !== void 0;
|
|
10917
|
+
}
|
|
10918
|
+
function assertValidKindLevel(kind, level) {
|
|
10919
|
+
const hasKind = kind !== null && kind !== void 0;
|
|
10920
|
+
if (hasKind && !MEMORY_KINDS.includes(kind)) {
|
|
10921
|
+
throw new MemoryLevelError(`Unknown memory kind: ${kind}`);
|
|
10922
|
+
}
|
|
10923
|
+
if (level !== void 0 && !MEMORY_LEVELS.includes(level)) {
|
|
10924
|
+
throw new MemoryLevelError(`Unknown memory level: ${level}`);
|
|
10925
|
+
}
|
|
10926
|
+
if (level === "profile" && !hasKind) {
|
|
10927
|
+
throw new MemoryLevelError("Only a memory with a kind can be at level 'profile'");
|
|
10928
|
+
}
|
|
10929
|
+
}
|
|
10930
|
+
function resolveCreateLevel(opts) {
|
|
10931
|
+
if (opts.level !== void 0) return { level: opts.level, scope: scopeForLevel(opts.level) };
|
|
10932
|
+
if (opts.scope !== void 0) return { level: levelFromScope(opts.scope), scope: opts.scope };
|
|
10933
|
+
return { level: "private", scope: "private" };
|
|
10934
|
+
}
|
|
10935
|
+
async function encryptKindValue(ctx, value) {
|
|
10936
|
+
if (typeof value !== "string" || !ctx.walletAddress || !ctx.signMessage) return value;
|
|
10937
|
+
return encryptVaultMemoryContent(
|
|
10938
|
+
value,
|
|
10939
|
+
ctx.walletAddress,
|
|
10940
|
+
ctx.signMessage,
|
|
10941
|
+
ctx.embeddedWalletSigner
|
|
10942
|
+
);
|
|
10943
|
+
}
|
|
10944
|
+
function levelConditions(requested) {
|
|
10945
|
+
if (!requested?.length) return [];
|
|
10946
|
+
const published = ["shared", "public"];
|
|
10947
|
+
const wantsMatching = requested.includes("matching");
|
|
10948
|
+
const wantsPrivate = requested.includes("private");
|
|
10949
|
+
const unresolved = Q5.or(Q5.where("level", null), Q5.where("level", Q5.notIn([...MEMORY_LEVELS])));
|
|
10950
|
+
const byLevel = Q5.where("level", Q5.oneOf([...requested]));
|
|
10951
|
+
if (wantsMatching && wantsPrivate) return [Q5.or(byLevel, unresolved)];
|
|
10952
|
+
if (wantsMatching) {
|
|
10953
|
+
return [Q5.or(byLevel, Q5.and(unresolved, Q5.where("scope", Q5.oneOf(published))))];
|
|
10954
|
+
}
|
|
10955
|
+
if (wantsPrivate) {
|
|
10956
|
+
return [
|
|
10957
|
+
Q5.or(
|
|
10958
|
+
byLevel,
|
|
10959
|
+
Q5.and(unresolved, Q5.or(Q5.where("scope", null), Q5.where("scope", Q5.notIn(published))))
|
|
10960
|
+
)
|
|
10961
|
+
];
|
|
10962
|
+
}
|
|
10963
|
+
return [byLevel];
|
|
10964
|
+
}
|
|
10965
|
+
function isOwnedByCtxUser(ctx, record2) {
|
|
10966
|
+
return ctx.userId === void 0 || record2.userId === ctx.userId;
|
|
10836
10967
|
}
|
|
10837
10968
|
function baseVaultConditions(ctx, options) {
|
|
10838
10969
|
return [
|
|
@@ -10874,6 +11005,9 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
10874
11005
|
uniqueId: memory.id,
|
|
10875
11006
|
content: memory.content,
|
|
10876
11007
|
scope: memory.scope,
|
|
11008
|
+
kind: memory.kind ?? null,
|
|
11009
|
+
kindValue: memory.kindValue ?? null,
|
|
11010
|
+
level: resolveMemoryLevel(memory.level, memory.scope),
|
|
10877
11011
|
folderId: memory.folderId ?? null,
|
|
10878
11012
|
userId: memory.userId ?? null,
|
|
10879
11013
|
embedding: memory.embedding ?? null,
|
|
@@ -10912,42 +11046,48 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
10912
11046
|
}
|
|
10913
11047
|
return raw;
|
|
10914
11048
|
}
|
|
10915
|
-
function populateNewVaultMemory(
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
11049
|
+
function populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue) {
|
|
11050
|
+
const { level, scope } = resolveCreateLevel(opts);
|
|
11051
|
+
record2._setRaw("content", encryptedContent);
|
|
11052
|
+
record2._setRaw("scope", scope);
|
|
11053
|
+
record2._setRaw("level", level);
|
|
11054
|
+
record2._setRaw("kind", opts.kind ?? null);
|
|
11055
|
+
record2._setRaw("kind_value", encryptedKindValue ?? null);
|
|
11056
|
+
record2._setRaw("folder_id", opts.folderId ?? null);
|
|
11057
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
11058
|
+
record2._setRaw("is_deleted", false);
|
|
10921
11059
|
if (opts.embedding !== void 0) {
|
|
10922
|
-
|
|
10923
|
-
|
|
11060
|
+
record2._setRaw("embedding", opts.embedding);
|
|
11061
|
+
record2._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
10924
11062
|
}
|
|
10925
11063
|
if (opts.sourceChunkIds !== void 0) {
|
|
10926
|
-
|
|
11064
|
+
record2._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
10927
11065
|
}
|
|
10928
|
-
|
|
10929
|
-
|
|
11066
|
+
record2._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11067
|
+
record2._setRaw("source", opts.source ?? "manual");
|
|
10930
11068
|
if (opts.eventTime) {
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
11069
|
+
record2._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11070
|
+
record2._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11071
|
+
record2._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
10934
11072
|
}
|
|
10935
11073
|
if (opts.factType !== void 0) {
|
|
10936
|
-
|
|
11074
|
+
record2._setRaw("fact_type", opts.factType);
|
|
10937
11075
|
}
|
|
10938
11076
|
if (opts.trustTier !== void 0) {
|
|
10939
|
-
|
|
11077
|
+
record2._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
10940
11078
|
}
|
|
10941
|
-
|
|
10942
|
-
|
|
11079
|
+
record2._setRaw("visibility", opts.visibility ?? "private");
|
|
11080
|
+
record2._setRaw(
|
|
10943
11081
|
"published_at",
|
|
10944
11082
|
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
10945
11083
|
);
|
|
10946
11084
|
if (opts.geohash !== void 0) {
|
|
10947
|
-
|
|
11085
|
+
record2._setRaw("geohash", opts.geohash);
|
|
10948
11086
|
}
|
|
10949
11087
|
}
|
|
10950
11088
|
async function createVaultMemoryOp(ctx, opts) {
|
|
11089
|
+
assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
11090
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
10951
11091
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
10952
11092
|
opts.content,
|
|
10953
11093
|
ctx.walletAddress,
|
|
@@ -10958,13 +11098,15 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
10958
11098
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
10959
11099
|
throw new Error("Memory source is no longer eligible");
|
|
10960
11100
|
return ctx.vaultMemoryCollection.create(
|
|
10961
|
-
(
|
|
11101
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
10962
11102
|
);
|
|
10963
11103
|
});
|
|
10964
11104
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
10965
11105
|
}
|
|
10966
11106
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
10967
11107
|
if (!targetId) return { created: null, retired: false };
|
|
11108
|
+
assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
11109
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
10968
11110
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
10969
11111
|
opts.content,
|
|
10970
11112
|
ctx.walletAddress,
|
|
@@ -10981,9 +11123,10 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
10981
11123
|
} catch {
|
|
10982
11124
|
return;
|
|
10983
11125
|
}
|
|
10984
|
-
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target))
|
|
11126
|
+
if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
|
|
11127
|
+
return;
|
|
10985
11128
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
10986
|
-
(
|
|
11129
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
10987
11130
|
);
|
|
10988
11131
|
await target.update((r) => {
|
|
10989
11132
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -11047,6 +11190,10 @@ async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
|
|
|
11047
11190
|
}
|
|
11048
11191
|
async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
11049
11192
|
if (optionsArray.length === 0) return [];
|
|
11193
|
+
for (const opts of optionsArray) assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
11194
|
+
const encryptedKindValues = await Promise.all(
|
|
11195
|
+
optionsArray.map((opts) => encryptKindValue(ctx, opts.kindValue))
|
|
11196
|
+
);
|
|
11050
11197
|
const encryptedContents = await Promise.all(
|
|
11051
11198
|
optionsArray.map(async (opts) => {
|
|
11052
11199
|
if (ctx.walletAddress && ctx.signMessage) {
|
|
@@ -11065,7 +11212,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11065
11212
|
throw new Error("Memory source is no longer eligible");
|
|
11066
11213
|
const prepared = optionsArray.map(
|
|
11067
11214
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11068
|
-
(
|
|
11215
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
11069
11216
|
)
|
|
11070
11217
|
);
|
|
11071
11218
|
await ctx.database.batch(...prepared);
|
|
@@ -11073,16 +11220,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11073
11220
|
});
|
|
11074
11221
|
return Promise.all(
|
|
11075
11222
|
created.map(
|
|
11076
|
-
(
|
|
11223
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
11077
11224
|
)
|
|
11078
11225
|
);
|
|
11079
11226
|
}
|
|
11080
11227
|
async function getVaultMemoryOp(ctx, id) {
|
|
11081
11228
|
try {
|
|
11082
|
-
const
|
|
11083
|
-
if (
|
|
11229
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11230
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
11084
11231
|
return vaultMemoryToStored(
|
|
11085
|
-
|
|
11232
|
+
record2,
|
|
11086
11233
|
ctx.walletAddress,
|
|
11087
11234
|
ctx.signMessage,
|
|
11088
11235
|
ctx.embeddedWalletSigner
|
|
@@ -11108,6 +11255,9 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
11108
11255
|
uniqueId: raw.id,
|
|
11109
11256
|
content: raw.content ?? "",
|
|
11110
11257
|
scope: raw.scope ?? "",
|
|
11258
|
+
kind: raw.kind ?? null,
|
|
11259
|
+
kindValue: raw.kind_value ?? null,
|
|
11260
|
+
level: resolveMemoryLevel(raw.level, raw.scope),
|
|
11111
11261
|
folderId: raw.folder_id ?? null,
|
|
11112
11262
|
userId: raw.user_id ?? null,
|
|
11113
11263
|
embedding: raw.embedding ?? null,
|
|
@@ -11140,17 +11290,19 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
11140
11290
|
};
|
|
11141
11291
|
}
|
|
11142
11292
|
async function vaultMemoryRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner) {
|
|
11143
|
-
const
|
|
11293
|
+
const stored2 = vaultMemoryRawToStoredRaw(raw);
|
|
11144
11294
|
if (walletAddress) {
|
|
11145
|
-
return decryptVaultMemoryFields(
|
|
11295
|
+
return decryptVaultMemoryFields(stored2, walletAddress, signMessage, embeddedWalletSigner);
|
|
11146
11296
|
}
|
|
11147
|
-
return
|
|
11297
|
+
return stored2;
|
|
11148
11298
|
}
|
|
11149
11299
|
async function getAllVaultMemoriesOp(ctx, options) {
|
|
11150
11300
|
const conditions = [
|
|
11151
11301
|
...baseVaultConditions(ctx, options),
|
|
11152
11302
|
...options?.scopes?.length ? [Q5.where("scope", Q5.oneOf(options.scopes))] : [],
|
|
11153
11303
|
...visibilityConditions(options?.visibility),
|
|
11304
|
+
...levelConditions(options?.levels),
|
|
11305
|
+
...options?.kinds?.length ? [Q5.where("kind", Q5.oneOf(options.kinds))] : [],
|
|
11154
11306
|
...options?.folderId !== void 0 ? [Q5.where("folder_id", options.folderId)] : [],
|
|
11155
11307
|
...options?.factTypes?.length ? [Q5.where("fact_type", Q5.oneOf(options.factTypes))] : [],
|
|
11156
11308
|
Q5.sortBy(options?.since ? "updated_at" : "created_at", Q5.desc),
|
|
@@ -11296,13 +11448,13 @@ async function getVaultMemoriesByIdsOp(ctx, ids, options) {
|
|
|
11296
11448
|
async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
11297
11449
|
const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, options)).unsafeFetchRaw();
|
|
11298
11450
|
return mapInBatches(results, async (raw) => {
|
|
11299
|
-
const
|
|
11451
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
11300
11452
|
raw,
|
|
11301
11453
|
ctx.walletAddress,
|
|
11302
11454
|
ctx.signMessage,
|
|
11303
11455
|
ctx.embeddedWalletSigner
|
|
11304
11456
|
);
|
|
11305
|
-
return
|
|
11457
|
+
return stored2.content;
|
|
11306
11458
|
});
|
|
11307
11459
|
}
|
|
11308
11460
|
async function countActiveVaultMemoriesOp(ctx) {
|
|
@@ -11317,6 +11469,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11317
11469
|
try {
|
|
11318
11470
|
const probe = await ctx.vaultMemoryCollection.find(id);
|
|
11319
11471
|
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
11472
|
+
if (opts.freeFormOnly && isKinded(probe)) return null;
|
|
11473
|
+
const levelAfter = (current) => {
|
|
11474
|
+
if (opts.level !== void 0) return opts.level;
|
|
11475
|
+
if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
|
|
11476
|
+
return levelForScopeChange(current, opts.scope);
|
|
11477
|
+
};
|
|
11478
|
+
assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
|
|
11479
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
11320
11480
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
11321
11481
|
opts.content,
|
|
11322
11482
|
ctx.walletAddress,
|
|
@@ -11324,30 +11484,43 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11324
11484
|
ctx.embeddedWalletSigner
|
|
11325
11485
|
) : opts.content;
|
|
11326
11486
|
let stale = false;
|
|
11327
|
-
const
|
|
11328
|
-
const originalUpdatedAt =
|
|
11487
|
+
const record2 = probe;
|
|
11488
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11329
11489
|
await ctx.database.write(async () => {
|
|
11330
11490
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11331
11491
|
throw new Error("Memory source is no longer eligible");
|
|
11332
|
-
if (
|
|
11492
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
11333
11493
|
stale = true;
|
|
11334
11494
|
return;
|
|
11335
11495
|
}
|
|
11496
|
+
const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
|
|
11497
|
+
const nextLevel = levelAfter(record2);
|
|
11498
|
+
assertValidKindLevel(nextKind, nextLevel);
|
|
11336
11499
|
let observedSources = [];
|
|
11337
11500
|
let replayedObservation = false;
|
|
11338
11501
|
if (opts.observationSourceIds?.length) {
|
|
11339
11502
|
try {
|
|
11340
|
-
const parsed = JSON.parse(
|
|
11503
|
+
const parsed = JSON.parse(record2.sourceChunkIds ?? "[]");
|
|
11341
11504
|
if (Array.isArray(parsed))
|
|
11342
11505
|
observedSources = parsed.filter((id2) => typeof id2 === "string");
|
|
11343
11506
|
} catch {
|
|
11344
11507
|
}
|
|
11345
11508
|
replayedObservation = opts.observationSourceIds.every((id2) => observedSources.includes(id2));
|
|
11346
11509
|
}
|
|
11347
|
-
await
|
|
11510
|
+
await record2.update((r) => {
|
|
11348
11511
|
r._setRaw("content", encryptedContent);
|
|
11349
|
-
if (opts.
|
|
11512
|
+
if (opts.level !== void 0) {
|
|
11513
|
+
r._setRaw("level", nextLevel);
|
|
11514
|
+
r._setRaw("scope", scopeForLevel(nextLevel));
|
|
11515
|
+
} else if (opts.scope !== void 0) {
|
|
11350
11516
|
r._setRaw("scope", opts.scope);
|
|
11517
|
+
r._setRaw("level", nextLevel);
|
|
11518
|
+
}
|
|
11519
|
+
if (opts.kind !== void 0) {
|
|
11520
|
+
r._setRaw("kind", opts.kind);
|
|
11521
|
+
}
|
|
11522
|
+
if (encryptedKindValue !== void 0) {
|
|
11523
|
+
r._setRaw("kind_value", encryptedKindValue);
|
|
11351
11524
|
}
|
|
11352
11525
|
if (opts.folderId !== void 0) {
|
|
11353
11526
|
r._setRaw("folder_id", opts.folderId);
|
|
@@ -11401,12 +11574,13 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11401
11574
|
});
|
|
11402
11575
|
if (stale) return null;
|
|
11403
11576
|
return vaultMemoryToStored(
|
|
11404
|
-
|
|
11577
|
+
record2,
|
|
11405
11578
|
ctx.walletAddress,
|
|
11406
11579
|
ctx.signMessage,
|
|
11407
11580
|
ctx.embeddedWalletSigner
|
|
11408
11581
|
);
|
|
11409
|
-
} catch {
|
|
11582
|
+
} catch (err) {
|
|
11583
|
+
if (err instanceof MemoryLevelError) throw err;
|
|
11410
11584
|
return null;
|
|
11411
11585
|
}
|
|
11412
11586
|
}
|
|
@@ -11415,21 +11589,21 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
11415
11589
|
if (!entityCtx) {
|
|
11416
11590
|
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
11417
11591
|
}
|
|
11418
|
-
let
|
|
11592
|
+
let record2;
|
|
11419
11593
|
try {
|
|
11420
|
-
|
|
11594
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
11421
11595
|
} catch {
|
|
11422
11596
|
return null;
|
|
11423
11597
|
}
|
|
11424
|
-
if (
|
|
11598
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
11425
11599
|
let stale = false;
|
|
11426
|
-
const originalUpdatedAt =
|
|
11600
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11427
11601
|
await ctx.database.write(async (writer) => {
|
|
11428
|
-
if (
|
|
11602
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11429
11603
|
stale = true;
|
|
11430
11604
|
return;
|
|
11431
11605
|
}
|
|
11432
|
-
await
|
|
11606
|
+
await record2.update((r) => {
|
|
11433
11607
|
r._setRaw("topics_user_managed", true);
|
|
11434
11608
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
11435
11609
|
});
|
|
@@ -11453,25 +11627,25 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
11453
11627
|
);
|
|
11454
11628
|
});
|
|
11455
11629
|
if (stale) return null;
|
|
11456
|
-
return vaultMemoryToStored(
|
|
11630
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11457
11631
|
}
|
|
11458
11632
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
11459
|
-
let
|
|
11633
|
+
let record2;
|
|
11460
11634
|
try {
|
|
11461
|
-
|
|
11635
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
11462
11636
|
} catch {
|
|
11463
11637
|
return false;
|
|
11464
11638
|
}
|
|
11465
|
-
if (
|
|
11466
|
-
const originalUpdatedAt =
|
|
11639
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11640
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11467
11641
|
let cleared = false;
|
|
11468
11642
|
await ctx.database.write(async () => {
|
|
11469
|
-
if (options?.unlessTopicsRecorded && parseTopics(
|
|
11643
|
+
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
11470
11644
|
cleared = true;
|
|
11471
|
-
await
|
|
11645
|
+
await record2.update((r) => {
|
|
11472
11646
|
r._setRaw("topics_user_managed", false);
|
|
11473
11647
|
r._setRaw("topics_extracted_version", null);
|
|
11474
|
-
if (
|
|
11648
|
+
if (record2.topicsExtractedAt === null) {
|
|
11475
11649
|
r._setRaw("topics_extracted_at", originalUpdatedAt);
|
|
11476
11650
|
}
|
|
11477
11651
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -11480,22 +11654,22 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
11480
11654
|
return cleared;
|
|
11481
11655
|
}
|
|
11482
11656
|
async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
11483
|
-
let
|
|
11657
|
+
let record2;
|
|
11484
11658
|
try {
|
|
11485
|
-
|
|
11659
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11486
11660
|
} catch {
|
|
11487
11661
|
return null;
|
|
11488
11662
|
}
|
|
11489
|
-
if (
|
|
11663
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
11490
11664
|
let stale = false;
|
|
11491
11665
|
await ctx.database.write(async () => {
|
|
11492
|
-
if (
|
|
11666
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11493
11667
|
stale = true;
|
|
11494
11668
|
return;
|
|
11495
11669
|
}
|
|
11496
|
-
const currentUpdatedAt =
|
|
11497
|
-
const currentPublishedAt =
|
|
11498
|
-
await
|
|
11670
|
+
const currentUpdatedAt = record2.updatedAt.getTime();
|
|
11671
|
+
const currentPublishedAt = record2.publishedAt ?? null;
|
|
11672
|
+
await record2.update((r) => {
|
|
11499
11673
|
r._setRaw("visibility", opts.visibility);
|
|
11500
11674
|
if (opts.visibility === "private") {
|
|
11501
11675
|
r._setRaw("published_at", null);
|
|
@@ -11509,19 +11683,19 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
11509
11683
|
});
|
|
11510
11684
|
});
|
|
11511
11685
|
if (stale) return null;
|
|
11512
|
-
return vaultMemoryToStored(
|
|
11686
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11513
11687
|
}
|
|
11514
11688
|
async function deleteVaultMemoryOp(ctx, id) {
|
|
11515
11689
|
try {
|
|
11516
|
-
const
|
|
11517
|
-
if (
|
|
11690
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11691
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11518
11692
|
let stale = false;
|
|
11519
11693
|
await ctx.database.write(async () => {
|
|
11520
|
-
if (
|
|
11694
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11521
11695
|
stale = true;
|
|
11522
11696
|
return;
|
|
11523
11697
|
}
|
|
11524
|
-
await
|
|
11698
|
+
await record2.update((r) => {
|
|
11525
11699
|
r._setRaw("is_deleted", true);
|
|
11526
11700
|
});
|
|
11527
11701
|
});
|
|
@@ -11540,8 +11714,9 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
11540
11714
|
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
11541
11715
|
if (id === supersededById) return false;
|
|
11542
11716
|
try {
|
|
11543
|
-
const
|
|
11544
|
-
if (
|
|
11717
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11718
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11719
|
+
if (isKinded(record2)) return false;
|
|
11545
11720
|
let successor;
|
|
11546
11721
|
try {
|
|
11547
11722
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -11555,7 +11730,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
11555
11730
|
await ctx.database.write(async () => {
|
|
11556
11731
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11557
11732
|
throw new Error("Memory source is no longer eligible");
|
|
11558
|
-
if (
|
|
11733
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
11559
11734
|
stale = true;
|
|
11560
11735
|
return;
|
|
11561
11736
|
}
|
|
@@ -11563,7 +11738,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
11563
11738
|
stale = true;
|
|
11564
11739
|
return;
|
|
11565
11740
|
}
|
|
11566
|
-
await
|
|
11741
|
+
await record2.update((r) => {
|
|
11567
11742
|
r._setRaw("superseded_by", supersededById);
|
|
11568
11743
|
r._setRaw("superseded_at", Date.now());
|
|
11569
11744
|
});
|
|
@@ -11582,7 +11757,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
11582
11757
|
const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
|
|
11583
11758
|
return mapInBatches(
|
|
11584
11759
|
results,
|
|
11585
|
-
(
|
|
11760
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
11586
11761
|
);
|
|
11587
11762
|
}
|
|
11588
11763
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
@@ -11724,17 +11899,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
11724
11899
|
}
|
|
11725
11900
|
}
|
|
11726
11901
|
const eligible = records.filter(
|
|
11727
|
-
(
|
|
11902
|
+
(record2) => !record2.isDeleted && isOwnedByCtxUser(ctx, record2) && !record2.topicsUserManaged
|
|
11728
11903
|
);
|
|
11729
|
-
const prepared = eligible.map((
|
|
11730
|
-
const originalUpdatedAt =
|
|
11731
|
-
return
|
|
11904
|
+
const prepared = eligible.map((record2) => {
|
|
11905
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11906
|
+
return record2.prepareUpdate((r) => {
|
|
11732
11907
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
11733
11908
|
r._setRaw("topics_extracted_version", version);
|
|
11734
11909
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
11735
11910
|
});
|
|
11736
11911
|
});
|
|
11737
|
-
for (const
|
|
11912
|
+
for (const record2 of eligible) stamped.push(record2.id);
|
|
11738
11913
|
if (prepared.length > 0) await ctx.database.batch(...prepared);
|
|
11739
11914
|
});
|
|
11740
11915
|
}
|
|
@@ -11749,14 +11924,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
11749
11924
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
11750
11925
|
try {
|
|
11751
11926
|
await ctx.database.write(async (writer) => {
|
|
11752
|
-
let
|
|
11927
|
+
let record2;
|
|
11753
11928
|
try {
|
|
11754
|
-
|
|
11929
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11755
11930
|
} catch {
|
|
11756
11931
|
return;
|
|
11757
11932
|
}
|
|
11758
|
-
if (
|
|
11759
|
-
const topics = parseTopics(
|
|
11933
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
11934
|
+
const topics = parseTopics(record2.topics);
|
|
11760
11935
|
if (topics === null) return;
|
|
11761
11936
|
await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics));
|
|
11762
11937
|
relinked.push(id);
|
|
@@ -11781,20 +11956,20 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
11781
11956
|
await ctx.database.write(async () => {
|
|
11782
11957
|
const writes = [];
|
|
11783
11958
|
for (const id of chunkIds) {
|
|
11784
|
-
let
|
|
11959
|
+
let record2;
|
|
11785
11960
|
try {
|
|
11786
|
-
|
|
11961
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11787
11962
|
} catch {
|
|
11788
11963
|
continue;
|
|
11789
11964
|
}
|
|
11790
|
-
if (
|
|
11791
|
-
if (parseTopics(
|
|
11965
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) continue;
|
|
11966
|
+
if (parseTopics(record2.topics) !== null) continue;
|
|
11792
11967
|
const links = await entityCtx.memoryEntityCollection.query(Q5.where("memory_id", id)).unsafeFetchRaw();
|
|
11793
11968
|
const entityIds = links.map((l) => String(l.entity_id));
|
|
11794
11969
|
if (entityIds.length === 0) continue;
|
|
11795
11970
|
const entities = await entityCtx.entityCollection.query(Q5.where("id", Q5.oneOf(entityIds))).fetch();
|
|
11796
11971
|
if (entities.length === 0) continue;
|
|
11797
|
-
const source =
|
|
11972
|
+
const source = record2.topicsUserManaged ? "user" : "auto";
|
|
11798
11973
|
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
11799
11974
|
if (write) writes.push(write);
|
|
11800
11975
|
}
|
|
@@ -11812,7 +11987,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
11812
11987
|
if (records.length === 0) return 0;
|
|
11813
11988
|
await ctx.database.write(async () => {
|
|
11814
11989
|
const prepared = records.map(
|
|
11815
|
-
(
|
|
11990
|
+
(record2) => record2.prepareUpdate((r) => {
|
|
11816
11991
|
r._setRaw("is_deleted", true);
|
|
11817
11992
|
})
|
|
11818
11993
|
);
|
|
@@ -11842,7 +12017,10 @@ function assertVaultScopeForSweep(ctx) {
|
|
|
11842
12017
|
}
|
|
11843
12018
|
async function getDecayCandidatesRawOp(ctx) {
|
|
11844
12019
|
assertVaultScopeForSweep(ctx);
|
|
11845
|
-
const results = await ctx.vaultMemoryCollection.query(
|
|
12020
|
+
const results = await ctx.vaultMemoryCollection.query(
|
|
12021
|
+
...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true }),
|
|
12022
|
+
Q5.where("kind", null)
|
|
12023
|
+
).unsafeFetchRaw();
|
|
11846
12024
|
return results.map((raw) => ({
|
|
11847
12025
|
uniqueId: raw.id,
|
|
11848
12026
|
factType: raw.fact_type ?? null,
|
|
@@ -11857,20 +12035,20 @@ async function getDecayCandidatesRawOp(ctx) {
|
|
|
11857
12035
|
}
|
|
11858
12036
|
async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
11859
12037
|
try {
|
|
11860
|
-
const
|
|
11861
|
-
if (
|
|
12038
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
12039
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11862
12040
|
let stale = false;
|
|
11863
12041
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
11864
12042
|
await ctx.database.write(async () => {
|
|
11865
|
-
if (
|
|
12043
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
11866
12044
|
stale = true;
|
|
11867
12045
|
return;
|
|
11868
12046
|
}
|
|
11869
|
-
if (opts?.expectedUpdatedAt !== void 0 &&
|
|
12047
|
+
if (opts?.expectedUpdatedAt !== void 0 && record2.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record2.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
|
|
11870
12048
|
stale = true;
|
|
11871
12049
|
return;
|
|
11872
12050
|
}
|
|
11873
|
-
await
|
|
12051
|
+
await record2.update((r) => {
|
|
11874
12052
|
r._setRaw("archived_at", archivedAtValue);
|
|
11875
12053
|
});
|
|
11876
12054
|
});
|
|
@@ -11881,15 +12059,15 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
11881
12059
|
}
|
|
11882
12060
|
async function restoreVaultMemoryOp(ctx, id) {
|
|
11883
12061
|
try {
|
|
11884
|
-
const
|
|
11885
|
-
if (
|
|
12062
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
12063
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11886
12064
|
let stale = false;
|
|
11887
12065
|
await ctx.database.write(async () => {
|
|
11888
|
-
if (
|
|
12066
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11889
12067
|
stale = true;
|
|
11890
12068
|
return;
|
|
11891
12069
|
}
|
|
11892
|
-
await
|
|
12070
|
+
await record2.update((r) => {
|
|
11893
12071
|
r._setRaw("archived_at", null);
|
|
11894
12072
|
});
|
|
11895
12073
|
});
|
|
@@ -11900,17 +12078,17 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
11900
12078
|
}
|
|
11901
12079
|
async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
11902
12080
|
try {
|
|
11903
|
-
const
|
|
11904
|
-
if (
|
|
12081
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
12082
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11905
12083
|
const now = opts.now ?? Date.now();
|
|
11906
12084
|
let stale = false;
|
|
11907
12085
|
await ctx.database.write(async () => {
|
|
11908
|
-
const archivedAt =
|
|
11909
|
-
if (
|
|
12086
|
+
const archivedAt = record2.archivedAt;
|
|
12087
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
11910
12088
|
stale = true;
|
|
11911
12089
|
return;
|
|
11912
12090
|
}
|
|
11913
|
-
await
|
|
12091
|
+
await record2.update((r) => {
|
|
11914
12092
|
r._setRaw("is_deleted", true);
|
|
11915
12093
|
});
|
|
11916
12094
|
});
|
|
@@ -11928,14 +12106,14 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
11928
12106
|
}
|
|
11929
12107
|
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
11930
12108
|
try {
|
|
11931
|
-
const
|
|
11932
|
-
if (
|
|
11933
|
-
const readUpdatedAt =
|
|
11934
|
-
const readStoredContent =
|
|
12109
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
12110
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
12111
|
+
const readUpdatedAt = record2.updatedAt.getTime();
|
|
12112
|
+
const readStoredContent = record2._getRaw("content");
|
|
11935
12113
|
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
11936
12114
|
if (expected?.content !== void 0) {
|
|
11937
12115
|
const current = await vaultMemoryToStored(
|
|
11938
|
-
|
|
12116
|
+
record2,
|
|
11939
12117
|
ctx.walletAddress,
|
|
11940
12118
|
ctx.signMessage,
|
|
11941
12119
|
ctx.embeddedWalletSigner
|
|
@@ -11944,11 +12122,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
11944
12122
|
}
|
|
11945
12123
|
let written = false;
|
|
11946
12124
|
await ctx.database.write(async () => {
|
|
11947
|
-
if (
|
|
11948
|
-
const originalUpdatedAt =
|
|
11949
|
-
if (originalUpdatedAt !== readUpdatedAt ||
|
|
12125
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
12126
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12127
|
+
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
11950
12128
|
return;
|
|
11951
|
-
await
|
|
12129
|
+
await record2.update((r) => {
|
|
11952
12130
|
r._setRaw("embedding", embedding);
|
|
11953
12131
|
r._setRaw("embedding_model", embeddingModel);
|
|
11954
12132
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -11963,8 +12141,8 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
11963
12141
|
function normalizeForDedupe(content) {
|
|
11964
12142
|
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
11965
12143
|
}
|
|
11966
|
-
async function findQuarantinedDuplicateOp(ctx, content,
|
|
11967
|
-
const wanted = [...new Set(
|
|
12144
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds2, where) {
|
|
12145
|
+
const wanted = [...new Set(sourceIds2)].sort().join("\0");
|
|
11968
12146
|
const target = normalizeForDedupe(content);
|
|
11969
12147
|
const rows = await ctx.vaultMemoryCollection.query(
|
|
11970
12148
|
Q5.where("trust_tier", "quarantined"),
|
|
@@ -11983,13 +12161,13 @@ async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
|
11983
12161
|
if (!Array.isArray(ids)) continue;
|
|
11984
12162
|
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
11985
12163
|
if (key !== wanted) continue;
|
|
11986
|
-
const
|
|
12164
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
11987
12165
|
raw,
|
|
11988
12166
|
ctx.walletAddress,
|
|
11989
12167
|
ctx.signMessage,
|
|
11990
12168
|
ctx.embeddedWalletSigner
|
|
11991
12169
|
);
|
|
11992
|
-
if (normalizeForDedupe(
|
|
12170
|
+
if (normalizeForDedupe(stored2.content) === target) return stored2.uniqueId;
|
|
11993
12171
|
}
|
|
11994
12172
|
return null;
|
|
11995
12173
|
}
|
|
@@ -12098,25 +12276,26 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
12098
12276
|
inserted = writable.length;
|
|
12099
12277
|
if (writable.length === 0) return;
|
|
12100
12278
|
const prepared = writable.map(
|
|
12101
|
-
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12279
|
+
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record2) => {
|
|
12280
|
+
record2._raw.id = row.memoryId;
|
|
12281
|
+
record2._setRaw("content", content);
|
|
12282
|
+
record2._setRaw("scope", "shared");
|
|
12283
|
+
record2._setRaw("level", "matching");
|
|
12284
|
+
record2._setRaw("folder_id", null);
|
|
12285
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
12286
|
+
record2._setRaw("is_deleted", false);
|
|
12287
|
+
record2._setRaw("proof_count", 1);
|
|
12288
|
+
record2._setRaw("source", SOURCE_PHOTO);
|
|
12289
|
+
record2._setRaw(
|
|
12111
12290
|
"media",
|
|
12112
12291
|
row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
|
|
12113
12292
|
);
|
|
12114
|
-
|
|
12115
|
-
|
|
12293
|
+
record2._setRaw("visibility", "public");
|
|
12294
|
+
record2._setRaw("published_at", now);
|
|
12116
12295
|
if (row.eventTime) {
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12296
|
+
record2._setRaw("event_time_start", row.eventTime.start ?? null);
|
|
12297
|
+
record2._setRaw("event_time_end", row.eventTime.end ?? null);
|
|
12298
|
+
record2._setRaw("event_time_kind", row.eventTime.kind ?? null);
|
|
12120
12299
|
}
|
|
12121
12300
|
})
|
|
12122
12301
|
);
|
|
@@ -12480,11 +12659,11 @@ function folderToStored(folder) {
|
|
|
12480
12659
|
}
|
|
12481
12660
|
async function createVaultFolderOp(ctx, opts) {
|
|
12482
12661
|
const created = await ctx.database.write(async () => {
|
|
12483
|
-
return ctx.vaultFolderCollection.create((
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12662
|
+
return ctx.vaultFolderCollection.create((record2) => {
|
|
12663
|
+
record2._setRaw("name", opts.name);
|
|
12664
|
+
record2._setRaw("scope", opts.scope ?? "private");
|
|
12665
|
+
record2._setRaw("is_system", opts.isSystem ?? false);
|
|
12666
|
+
record2._setRaw("is_deleted", false);
|
|
12488
12667
|
});
|
|
12489
12668
|
});
|
|
12490
12669
|
return folderToStored(created);
|
|
@@ -12495,14 +12674,14 @@ async function getAllVaultFoldersOp(ctx) {
|
|
|
12495
12674
|
}
|
|
12496
12675
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
12497
12676
|
try {
|
|
12498
|
-
const
|
|
12499
|
-
if (
|
|
12500
|
-
const scopeChanged = opts.scope !== void 0 && opts.scope !==
|
|
12677
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
12678
|
+
if (record2.isDeleted) return null;
|
|
12679
|
+
const scopeChanged = opts.scope !== void 0 && opts.scope !== record2.scope;
|
|
12501
12680
|
const updated = await ctx.database.write(async () => {
|
|
12502
12681
|
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q6.where("folder_id", id), Q6.where("is_deleted", false)).fetch() : [];
|
|
12503
12682
|
const updates = [];
|
|
12504
12683
|
updates.push(
|
|
12505
|
-
|
|
12684
|
+
record2.prepareUpdate((r) => {
|
|
12506
12685
|
if (opts.name !== void 0) r._setRaw("name", opts.name);
|
|
12507
12686
|
if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
|
|
12508
12687
|
})
|
|
@@ -12510,6 +12689,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
12510
12689
|
for (const memory of memories) {
|
|
12511
12690
|
updates.push(
|
|
12512
12691
|
memory.prepareUpdate((r) => {
|
|
12692
|
+
r._setRaw("level", levelForScopeChange(r, opts.scope));
|
|
12513
12693
|
r._setRaw("scope", opts.scope);
|
|
12514
12694
|
})
|
|
12515
12695
|
);
|
|
@@ -12524,17 +12704,18 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
12524
12704
|
}
|
|
12525
12705
|
async function deleteVaultFolderOp(ctx, id) {
|
|
12526
12706
|
try {
|
|
12527
|
-
const
|
|
12528
|
-
if (
|
|
12707
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
12708
|
+
if (record2.isDeleted) return false;
|
|
12529
12709
|
await ctx.database.write(async () => {
|
|
12530
12710
|
const memories = await ctx.vaultMemoryCollection.query(Q6.where("folder_id", id), Q6.where("is_deleted", false)).fetch();
|
|
12531
12711
|
const preparedMemories = memories.map(
|
|
12532
12712
|
(memory) => memory.prepareUpdate((r) => {
|
|
12533
12713
|
r._setRaw("folder_id", null);
|
|
12714
|
+
r._setRaw("level", levelForScopeChange(r, "private"));
|
|
12534
12715
|
r._setRaw("scope", "private");
|
|
12535
12716
|
})
|
|
12536
12717
|
);
|
|
12537
|
-
const preparedFolder =
|
|
12718
|
+
const preparedFolder = record2.prepareUpdate((r) => {
|
|
12538
12719
|
r._setRaw("is_deleted", true);
|
|
12539
12720
|
});
|
|
12540
12721
|
await ctx.database.batch(...preparedMemories, preparedFolder);
|
|
@@ -12567,6 +12748,7 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
12567
12748
|
const prepared = memories.map(
|
|
12568
12749
|
(memory) => memory.prepareUpdate((r) => {
|
|
12569
12750
|
r._setRaw("folder_id", folderId);
|
|
12751
|
+
r._setRaw("level", levelForScopeChange(r, targetScope));
|
|
12570
12752
|
r._setRaw("scope", targetScope);
|
|
12571
12753
|
})
|
|
12572
12754
|
);
|
|
@@ -12580,11 +12762,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
12580
12762
|
}
|
|
12581
12763
|
async function updateVaultFolderContextOp(ctx, id, context) {
|
|
12582
12764
|
try {
|
|
12583
|
-
const
|
|
12584
|
-
if (
|
|
12765
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
12766
|
+
if (record2.isDeleted) return null;
|
|
12585
12767
|
const updated = await ctx.database.write(async () => {
|
|
12586
12768
|
await ctx.database.batch(
|
|
12587
|
-
|
|
12769
|
+
record2.prepareUpdate((r) => {
|
|
12588
12770
|
r._setRaw("context", context);
|
|
12589
12771
|
})
|
|
12590
12772
|
);
|
|
@@ -14641,7 +14823,7 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
14641
14823
|
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
14642
14824
|
let subEmbeddings;
|
|
14643
14825
|
try {
|
|
14644
|
-
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
14826
|
+
subEmbeddings = prepared.facetEmbeddings ?? await generateEmbeddings(facetQueries, embeddingOptions);
|
|
14645
14827
|
} catch (err) {
|
|
14646
14828
|
getLogger().warn(
|
|
14647
14829
|
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
@@ -14826,6 +15008,35 @@ var DEFAULT_SCOPE = "private";
|
|
|
14826
15008
|
var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
|
|
14827
15009
|
var DEFAULT_CONSOLIDATE_TOP_K = 20;
|
|
14828
15010
|
async function retain(content, ctx, options = {}) {
|
|
15011
|
+
return retainWithPersistence(
|
|
15012
|
+
content,
|
|
15013
|
+
{
|
|
15014
|
+
embeddingOptions: ctx.embeddingOptions,
|
|
15015
|
+
vaultCache: ctx.vaultCache,
|
|
15016
|
+
persistence: {
|
|
15017
|
+
prepare: (query, searchOptions) => prepareVaultCandidates(
|
|
15018
|
+
query,
|
|
15019
|
+
ctx.vaultCtx,
|
|
15020
|
+
ctx.embeddingOptions,
|
|
15021
|
+
ctx.vaultCache,
|
|
15022
|
+
searchOptions
|
|
15023
|
+
),
|
|
15024
|
+
get: (id) => getVaultMemoryOp(ctx.vaultCtx, id),
|
|
15025
|
+
tombstones: (_embedding, _model, scope, folderId) => getAllVaultMemoriesOp(ctx.vaultCtx, {
|
|
15026
|
+
includeDeleted: true,
|
|
15027
|
+
scopes: [scope],
|
|
15028
|
+
...folderId !== void 0 && { folderId }
|
|
15029
|
+
}),
|
|
15030
|
+
create: (input) => createVaultMemoryOp(ctx.vaultCtx, input),
|
|
15031
|
+
update: (id, patch) => updateVaultMemoryOp(ctx.vaultCtx, id, patch),
|
|
15032
|
+
supersede: (id, successor) => supersedeVaultMemoryOp(ctx.vaultCtx, id, successor),
|
|
15033
|
+
createSuperseding: (input, target) => createSupersedingMemoryOp(ctx.vaultCtx, input, target)
|
|
15034
|
+
}
|
|
15035
|
+
},
|
|
15036
|
+
options
|
|
15037
|
+
);
|
|
15038
|
+
}
|
|
15039
|
+
async function retainWithPersistence(content, ctx, options = {}) {
|
|
14829
15040
|
const trimmed = content.trim();
|
|
14830
15041
|
if (trimmed.length === 0) {
|
|
14831
15042
|
throw new Error("retain: content cannot be empty");
|
|
@@ -14838,19 +15049,14 @@ async function retain(content, ctx, options = {}) {
|
|
|
14838
15049
|
let supersedeContent;
|
|
14839
15050
|
let prepared;
|
|
14840
15051
|
if (enableAutoMerge) {
|
|
14841
|
-
prepared = await
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
{
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
scopes: [resolvedScope],
|
|
14850
|
-
includeArchived: true,
|
|
14851
|
-
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
14852
|
-
}
|
|
14853
|
-
);
|
|
15052
|
+
prepared = await ctx.persistence.prepare(trimmed, {
|
|
15053
|
+
limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
|
|
15054
|
+
useFusion: false,
|
|
15055
|
+
scopes: [resolvedScope],
|
|
15056
|
+
includeArchived: true,
|
|
15057
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
15058
|
+
});
|
|
15059
|
+
prepared = withoutKindedRows(prepared);
|
|
14854
15060
|
if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
|
|
14855
15061
|
throw new Error(
|
|
14856
15062
|
"retain: embeddings unavailable \u2014 refusing to auto-merge against an inert cosine lane, which would create a duplicate instead of merging into the existing memory. Retry when embeddings recover, or pass enableAutoMerge: false to force a create."
|
|
@@ -14881,7 +15087,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
14881
15087
|
);
|
|
14882
15088
|
if (matches.length > 0) {
|
|
14883
15089
|
const targetId = matches[0].uniqueId;
|
|
14884
|
-
const existing = await
|
|
15090
|
+
const existing = await ctx.persistence.get(targetId);
|
|
14885
15091
|
if (existing && !existing.supersededBy) {
|
|
14886
15092
|
const mergedSourceIds = unionStrings(
|
|
14887
15093
|
existing.sourceChunkIds ?? [],
|
|
@@ -14890,8 +15096,9 @@ async function retain(content, ctx, options = {}) {
|
|
|
14890
15096
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
14891
15097
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
14892
15098
|
const resurrect = resurrectFields(existing);
|
|
14893
|
-
const updated = await
|
|
15099
|
+
const updated = await ctx.persistence.update(targetId, {
|
|
14894
15100
|
content: existing.content,
|
|
15101
|
+
freeFormOnly: true,
|
|
14895
15102
|
proofCountIncrement: 1,
|
|
14896
15103
|
observationSourceIds: options.sourceChunkIds,
|
|
14897
15104
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -14917,7 +15124,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
14917
15124
|
}
|
|
14918
15125
|
const contentToWrite = supersedeContent ?? trimmed;
|
|
14919
15126
|
const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
|
|
14920
|
-
const
|
|
15127
|
+
const generatedEmbedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
15128
|
+
const embedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
14921
15129
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
14922
15130
|
if (options.respectTombstones) {
|
|
14923
15131
|
const tombstone = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -14957,8 +15165,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
14957
15165
|
};
|
|
14958
15166
|
if (supersedeTargetIds.length > 0) {
|
|
14959
15167
|
const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
|
|
14960
|
-
const { created: created2, retired } = await
|
|
14961
|
-
ctx.vaultCtx,
|
|
15168
|
+
const { created: created2, retired } = await ctx.persistence.createSuperseding(
|
|
14962
15169
|
createOpts,
|
|
14963
15170
|
primaryTargetId
|
|
14964
15171
|
);
|
|
@@ -14974,11 +15181,11 @@ async function retain(content, ctx, options = {}) {
|
|
|
14974
15181
|
for (const staleId of restTargetIds) {
|
|
14975
15182
|
let ok = false;
|
|
14976
15183
|
try {
|
|
14977
|
-
ok = await
|
|
15184
|
+
ok = await ctx.persistence.supersede(staleId, created2.uniqueId) === true;
|
|
14978
15185
|
} catch {
|
|
14979
15186
|
}
|
|
14980
15187
|
if (ok) continue;
|
|
14981
|
-
const stillLive = await
|
|
15188
|
+
const stillLive = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(staleId) : ctx.persistence.get(staleId)).catch(() => null);
|
|
14982
15189
|
if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
|
|
14983
15190
|
}
|
|
14984
15191
|
if (liveLeftovers.length > 0) {
|
|
@@ -15005,7 +15212,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
15005
15212
|
`supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
|
|
15006
15213
|
);
|
|
15007
15214
|
}
|
|
15008
|
-
const created = await
|
|
15215
|
+
const created = await ctx.persistence.create(createOpts);
|
|
15009
15216
|
cacheRowVector(
|
|
15010
15217
|
ctx.vaultCache,
|
|
15011
15218
|
created.uniqueId,
|
|
@@ -15020,15 +15227,22 @@ async function retain(content, ctx, options = {}) {
|
|
|
15020
15227
|
...consolidationDecidedCreate && { consolidation: "create" }
|
|
15021
15228
|
};
|
|
15022
15229
|
}
|
|
15230
|
+
function withoutKindedRows(prepared) {
|
|
15231
|
+
const kinded = new Set(
|
|
15232
|
+
prepared.memories.filter((m) => m.kind !== null && m.kind !== void 0).map((m) => m.uniqueId)
|
|
15233
|
+
);
|
|
15234
|
+
if (kinded.size === 0) return prepared;
|
|
15235
|
+
return {
|
|
15236
|
+
...prepared,
|
|
15237
|
+
memories: prepared.memories.filter((m) => !kinded.has(m.uniqueId)),
|
|
15238
|
+
embeddedItems: prepared.embeddedItems.filter((item) => !kinded.has(item.id))
|
|
15239
|
+
};
|
|
15240
|
+
}
|
|
15023
15241
|
function unionStrings(a, b) {
|
|
15024
15242
|
return [.../* @__PURE__ */ new Set([...a, ...b])];
|
|
15025
15243
|
}
|
|
15026
15244
|
async function findTombstoneMatch(embedding, embeddingModel, scope, ctx, opts) {
|
|
15027
|
-
const rows = await
|
|
15028
|
-
includeDeleted: true,
|
|
15029
|
-
scopes: [scope],
|
|
15030
|
-
...opts.folderId !== void 0 && { folderId: opts.folderId }
|
|
15031
|
-
});
|
|
15245
|
+
const rows = await ctx.persistence.tombstones(embedding, embeddingModel, scope, opts.folderId);
|
|
15032
15246
|
let bestId = null;
|
|
15033
15247
|
let bestSim = opts.threshold;
|
|
15034
15248
|
for (const row of rows) {
|
|
@@ -15095,7 +15309,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15095
15309
|
if (requestedIds.length === 0) return null;
|
|
15096
15310
|
const valid = [];
|
|
15097
15311
|
for (const id of requestedIds) {
|
|
15098
|
-
const existing = await
|
|
15312
|
+
const existing = await ctx.persistence.get(id);
|
|
15099
15313
|
if (existing && !existing.supersededBy) valid.push(id);
|
|
15100
15314
|
}
|
|
15101
15315
|
if (valid.length === 0) {
|
|
@@ -15107,7 +15321,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15107
15321
|
return { supersede: valid, content: decision.content };
|
|
15108
15322
|
}
|
|
15109
15323
|
if (decision.action === "noop" && decision.targetId) {
|
|
15110
|
-
const existing = await
|
|
15324
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
15111
15325
|
if (!existing || existing.supersededBy) {
|
|
15112
15326
|
return abandonToRace(
|
|
15113
15327
|
options,
|
|
@@ -15121,8 +15335,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15121
15335
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
15122
15336
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
15123
15337
|
const resurrect = resurrectFields(existing);
|
|
15124
|
-
const updated = await
|
|
15338
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
15125
15339
|
content: existing.content,
|
|
15340
|
+
freeFormOnly: true,
|
|
15126
15341
|
proofCountIncrement: 1,
|
|
15127
15342
|
observationSourceIds: options.sourceChunkIds,
|
|
15128
15343
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -15149,7 +15364,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15149
15364
|
};
|
|
15150
15365
|
}
|
|
15151
15366
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
15152
|
-
const existing = await
|
|
15367
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
15153
15368
|
if (!existing || existing.supersededBy) {
|
|
15154
15369
|
return abandonToRace(
|
|
15155
15370
|
options,
|
|
@@ -15160,13 +15375,15 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15160
15375
|
existing.sourceChunkIds ?? [],
|
|
15161
15376
|
options.sourceChunkIds ?? []
|
|
15162
15377
|
);
|
|
15163
|
-
const
|
|
15378
|
+
const generatedEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
|
|
15379
|
+
const newEmbedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
15164
15380
|
const consolidatedModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
15165
15381
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
15166
15382
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
15167
15383
|
const resurrect = resurrectFields(existing);
|
|
15168
|
-
const updated = await
|
|
15384
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
15169
15385
|
content: decision.content,
|
|
15386
|
+
freeFormOnly: true,
|
|
15170
15387
|
proofCountIncrement: 1,
|
|
15171
15388
|
observationSourceIds: options.sourceChunkIds,
|
|
15172
15389
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -15209,8 +15426,8 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15209
15426
|
return null;
|
|
15210
15427
|
}
|
|
15211
15428
|
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
15212
|
-
const stillExists = await
|
|
15213
|
-
if (stillExists) {
|
|
15429
|
+
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
15430
|
+
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
|
|
15214
15431
|
throw new Error(`retain: merge into memory ${targetId} failed to persist`);
|
|
15215
15432
|
}
|
|
15216
15433
|
}
|
|
@@ -15724,9 +15941,9 @@ function createAutoExtractor(options) {
|
|
|
15724
15941
|
const persistCursor = (conversationId, messages, advancedToId, contiguous) => {
|
|
15725
15942
|
if (!cursorStore || conversationId === void 0 || !contiguous) return;
|
|
15726
15943
|
try {
|
|
15727
|
-
const
|
|
15728
|
-
if (
|
|
15729
|
-
const storedIdx = messages.findIndex((m) => m.id ===
|
|
15944
|
+
const stored2 = cursorStore.get(conversationId);
|
|
15945
|
+
if (stored2 && stored2 !== advancedToId) {
|
|
15946
|
+
const storedIdx = messages.findIndex((m) => m.id === stored2);
|
|
15730
15947
|
const newIdx = messages.findIndex((m) => m.id === advancedToId);
|
|
15731
15948
|
if (storedIdx !== -1 && newIdx !== -1 && storedIdx >= newIdx) return;
|
|
15732
15949
|
}
|
|
@@ -16695,7 +16912,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
16695
16912
|
if (graphLaneFailed) degraded.push("graph-lane-failed");
|
|
16696
16913
|
if (temporalLaneFailed) degraded.push("temporal-lane-failed");
|
|
16697
16914
|
if (chunksScopeRestricted) degraded.push("chunks-scope-restricted");
|
|
16698
|
-
const laneRan = types.includes("fact") && !!ctx.vaultCtx && !!ctx.vaultCache || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
|
|
16915
|
+
const laneRan = types.includes("fact") && (!!ctx.factSource || !!ctx.vaultCtx && !!ctx.vaultCache) || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
|
|
16699
16916
|
const scores = admitted.map((m) => m.score);
|
|
16700
16917
|
const minScoreApplied = factResults.length > 0 ? factFloor : chunkResults.length > 0 ? chunkFloor : factFloor >= 0 ? factFloor : chunkFloor;
|
|
16701
16918
|
const diagnostics = {
|
|
@@ -16737,7 +16954,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
16737
16954
|
return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
|
|
16738
16955
|
}
|
|
16739
16956
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
16740
|
-
const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
|
|
16957
|
+
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
16741
16958
|
const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
|
|
16742
16959
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
16743
16960
|
const prepStart = nowMs2();
|
|
@@ -16767,7 +16984,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
16767
16984
|
safeLane(
|
|
16768
16985
|
"graph",
|
|
16769
16986
|
() => graphLaneFailed = true,
|
|
16770
|
-
() => buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
16987
|
+
() => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
16771
16988
|
...options.maxHops !== void 0 && { maxHops: options.maxHops },
|
|
16772
16989
|
...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
|
|
16773
16990
|
...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
|
|
@@ -16778,13 +16995,13 @@ async function recall(query, ctx, options = {}) {
|
|
|
16778
16995
|
wantsTemporal ? safeLane(
|
|
16779
16996
|
"temporal",
|
|
16780
16997
|
() => temporalLaneFailed = true,
|
|
16781
|
-
() => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
16998
|
+
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
16782
16999
|
) : Promise.resolve([])
|
|
16783
17000
|
]);
|
|
16784
17001
|
prepMs = nowMs2() - prepStart;
|
|
16785
17002
|
graphLaneCount = entityRanking.length;
|
|
16786
17003
|
temporalLaneCount = temporalRanking.length;
|
|
16787
|
-
if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
|
|
17004
|
+
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
16788
17005
|
const factStart = nowMs2();
|
|
16789
17006
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
16790
17007
|
factFloor = vaultMinScore;
|
|
@@ -16800,50 +17017,50 @@ async function recall(query, ctx, options = {}) {
|
|
|
16800
17017
|
rankedOnCosine: factRankedOnCosine,
|
|
16801
17018
|
decryptLast: factDecryptLast,
|
|
16802
17019
|
rowsDecrypted: factRowsDecrypted
|
|
16803
|
-
} = await searchVaultMemoriesWithSize(
|
|
16804
|
-
|
|
17020
|
+
} = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
|
|
17021
|
+
searchQuery,
|
|
16805
17022
|
ctx.vaultCtx,
|
|
16806
17023
|
ctx.embeddingOptions,
|
|
16807
17024
|
ctx.vaultCache,
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16846
|
-
);
|
|
17025
|
+
searchOptions
|
|
17026
|
+
)))(query, {
|
|
17027
|
+
limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
|
|
17028
|
+
minSimilarity: vaultMinScore,
|
|
17029
|
+
useFusion: true,
|
|
17030
|
+
rerank: flags.rerank,
|
|
17031
|
+
...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
|
|
17032
|
+
...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
|
|
17033
|
+
...options.rerankLoadTimeoutMs !== void 0 && {
|
|
17034
|
+
rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
|
|
17035
|
+
},
|
|
17036
|
+
...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
|
|
17037
|
+
...options.recency && { recency: options.recency },
|
|
17038
|
+
...options.mmr !== void 0 && { mmr: options.mmr },
|
|
17039
|
+
...options.supersessionBoost !== void 0 && {
|
|
17040
|
+
supersessionBoost: options.supersessionBoost
|
|
17041
|
+
},
|
|
17042
|
+
...options.supersessionWindow !== void 0 && {
|
|
17043
|
+
supersessionWindow: options.supersessionWindow
|
|
17044
|
+
},
|
|
17045
|
+
...options.proofCountAlpha !== void 0 && {
|
|
17046
|
+
proofCountAlpha: options.proofCountAlpha
|
|
17047
|
+
},
|
|
17048
|
+
...options.bm25AdmissionDivisor !== void 0 && {
|
|
17049
|
+
bm25AdmissionDivisor: options.bm25AdmissionDivisor
|
|
17050
|
+
},
|
|
17051
|
+
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
17052
|
+
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
17053
|
+
...subQueries && { subQueries },
|
|
17054
|
+
...options.scopes && { scopes: options.scopes },
|
|
17055
|
+
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
17056
|
+
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
17057
|
+
...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
|
|
17058
|
+
...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
|
|
17059
|
+
...entityRanking.length > 0 && { entityRanking },
|
|
17060
|
+
...temporalRanking.length > 0 && { temporalRanking },
|
|
17061
|
+
...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
|
|
17062
|
+
queryEmbedTotalTimeoutMs
|
|
17063
|
+
});
|
|
16847
17064
|
factResults.push(
|
|
16848
17065
|
...dedupeBy(
|
|
16849
17066
|
results,
|
|
@@ -17648,26 +17865,26 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
|
17648
17865
|
};
|
|
17649
17866
|
const inputs = [];
|
|
17650
17867
|
for (const id of new Set(memoryIds)) {
|
|
17651
|
-
let
|
|
17868
|
+
let record2;
|
|
17652
17869
|
try {
|
|
17653
|
-
|
|
17870
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
17654
17871
|
} catch (err) {
|
|
17655
17872
|
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
17656
17873
|
skip(id, "not-found");
|
|
17657
17874
|
continue;
|
|
17658
17875
|
}
|
|
17659
|
-
if (
|
|
17876
|
+
if (record2.isDeleted || ctx.userId !== void 0 && record2.userId !== ctx.userId || record2.topicsUserManaged) {
|
|
17660
17877
|
skip(id, "excluded");
|
|
17661
17878
|
continue;
|
|
17662
17879
|
}
|
|
17663
17880
|
try {
|
|
17664
|
-
const
|
|
17665
|
-
|
|
17881
|
+
const stored2 = await vaultMemoryToStored(
|
|
17882
|
+
record2,
|
|
17666
17883
|
ctx.walletAddress,
|
|
17667
17884
|
ctx.signMessage,
|
|
17668
17885
|
ctx.embeddedWalletSigner
|
|
17669
17886
|
);
|
|
17670
|
-
inputs.push({ id, content:
|
|
17887
|
+
inputs.push({ id, content: stored2.content });
|
|
17671
17888
|
} catch (err) {
|
|
17672
17889
|
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
17673
17890
|
skip(id, "unreadable");
|
|
@@ -17852,6 +18069,780 @@ function createLocalMemoryStore(options) {
|
|
|
17852
18069
|
};
|
|
17853
18070
|
}
|
|
17854
18071
|
|
|
18072
|
+
// src/lib/memory/store/remotePersistence.ts
|
|
18073
|
+
var RemoteMemoryError = class extends Error {
|
|
18074
|
+
constructor(message, status, code) {
|
|
18075
|
+
super(message);
|
|
18076
|
+
this.status = status;
|
|
18077
|
+
this.code = code;
|
|
18078
|
+
this.name = "RemoteMemoryError";
|
|
18079
|
+
}
|
|
18080
|
+
};
|
|
18081
|
+
var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
|
|
18082
|
+
var memoryFields = {
|
|
18083
|
+
memory_id: true,
|
|
18084
|
+
content: true,
|
|
18085
|
+
scope: true,
|
|
18086
|
+
created_at: true,
|
|
18087
|
+
updated_at: true,
|
|
18088
|
+
is_deleted: true,
|
|
18089
|
+
embedding: true,
|
|
18090
|
+
embedding_model: true,
|
|
18091
|
+
kind: true,
|
|
18092
|
+
kind_value: true,
|
|
18093
|
+
level: true,
|
|
18094
|
+
folder_id: true,
|
|
18095
|
+
source_chunk_ids: true,
|
|
18096
|
+
proof_count: true,
|
|
18097
|
+
source: true,
|
|
18098
|
+
event_time_start: true,
|
|
18099
|
+
event_time_end: true,
|
|
18100
|
+
event_time_kind: true,
|
|
18101
|
+
topics_user_managed: true,
|
|
18102
|
+
topics: true,
|
|
18103
|
+
topics_updated_at: true,
|
|
18104
|
+
media: true,
|
|
18105
|
+
topics_extracted_at: true,
|
|
18106
|
+
topics_extracted_version: true,
|
|
18107
|
+
superseded_by: true,
|
|
18108
|
+
superseded_at: true,
|
|
18109
|
+
last_observed_at: true,
|
|
18110
|
+
fact_type: true,
|
|
18111
|
+
archived_at: true,
|
|
18112
|
+
trust_tier: true,
|
|
18113
|
+
visibility: true,
|
|
18114
|
+
twin_opt_in: true,
|
|
18115
|
+
published_at: true,
|
|
18116
|
+
geohash: true
|
|
18117
|
+
};
|
|
18118
|
+
var candidateListLimits = [
|
|
18119
|
+
["scopes", 20],
|
|
18120
|
+
["fact_types", 20],
|
|
18121
|
+
["memory_ids", 1e3],
|
|
18122
|
+
["force_ids", 100]
|
|
18123
|
+
];
|
|
18124
|
+
function record(value) {
|
|
18125
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18126
|
+
}
|
|
18127
|
+
function memoryRecord(value) {
|
|
18128
|
+
if (!record(value) || !record(value.memory) || typeof value.memory.memory_id !== "string" || typeof value.memory.content !== "string" || typeof value.memory.scope !== "string" || typeof value.memory.created_at !== "number" || typeof value.memory.updated_at !== "number" || typeof value.memory.is_deleted !== "boolean" || !Number.isSafeInteger(value.version) || value.version < 1 || typeof value.server_updated_at !== "string" || value.score !== void 0 && (typeof value.score !== "number" || !Number.isFinite(value.score))) {
|
|
18129
|
+
throw new Error("Invalid nearby private-memory response");
|
|
18130
|
+
}
|
|
18131
|
+
return value;
|
|
18132
|
+
}
|
|
18133
|
+
async function createRemoteMemoryPersistence(options) {
|
|
18134
|
+
const base = new URL(options.baseUrl);
|
|
18135
|
+
if (!/^https?:$/.test(base.protocol) || base.username || base.password || base.search || base.hash) {
|
|
18136
|
+
throw new Error(
|
|
18137
|
+
"baseUrl must be an HTTP(S) origin or base path without credentials, query or fragment"
|
|
18138
|
+
);
|
|
18139
|
+
}
|
|
18140
|
+
if (!options.keyId || options.keyId.length > 256)
|
|
18141
|
+
throw new Error("A canonical keyId is required");
|
|
18142
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
18143
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
18144
|
+
throw new Error("timeoutMs must be a positive number");
|
|
18145
|
+
const root = base.href.replace(/\/$/, "") + "/api/private-memories";
|
|
18146
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
18147
|
+
const request = async (path, init = {}, signal) => {
|
|
18148
|
+
const controller = new AbortController();
|
|
18149
|
+
let timedOut = false;
|
|
18150
|
+
const timer = setTimeout(() => {
|
|
18151
|
+
timedOut = true;
|
|
18152
|
+
controller.abort();
|
|
18153
|
+
}, timeoutMs);
|
|
18154
|
+
const forwardAbort = () => controller.abort(signal?.reason);
|
|
18155
|
+
if (signal?.aborted) forwardAbort();
|
|
18156
|
+
else signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
18157
|
+
let rejectAborted;
|
|
18158
|
+
const aborted = new Promise((_, reject) => {
|
|
18159
|
+
rejectAborted = () => reject(
|
|
18160
|
+
controller.signal.reason instanceof Error ? controller.signal.reason : new Error("Nearby request aborted")
|
|
18161
|
+
);
|
|
18162
|
+
if (controller.signal.aborted) rejectAborted();
|
|
18163
|
+
else controller.signal.addEventListener("abort", rejectAborted, { once: true });
|
|
18164
|
+
});
|
|
18165
|
+
aborted.catch(() => void 0);
|
|
18166
|
+
try {
|
|
18167
|
+
const token = await Promise.race([options.getToken(), aborted]);
|
|
18168
|
+
if (controller.signal.aborted) await aborted;
|
|
18169
|
+
if (!token) throw new RemoteMemoryError("Authentication required", 401);
|
|
18170
|
+
const response = await fetcher(root + path, {
|
|
18171
|
+
...init,
|
|
18172
|
+
headers: {
|
|
18173
|
+
Authorization: `Bearer ${token}`,
|
|
18174
|
+
...init.body ? { "Content-Type": "application/json" } : {}
|
|
18175
|
+
},
|
|
18176
|
+
redirect: "error",
|
|
18177
|
+
signal: controller.signal
|
|
18178
|
+
});
|
|
18179
|
+
if (!response.ok) {
|
|
18180
|
+
const body = await response.json().catch(() => null);
|
|
18181
|
+
throw new RemoteMemoryError(
|
|
18182
|
+
record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
18183
|
+
response.status,
|
|
18184
|
+
record(body) && typeof body.code === "string" ? body.code : void 0
|
|
18185
|
+
);
|
|
18186
|
+
}
|
|
18187
|
+
return await response.json();
|
|
18188
|
+
} catch (error) {
|
|
18189
|
+
if (timedOut) throw new RemoteMemoryError("Nearby request timed out", 408, "timeout");
|
|
18190
|
+
throw error;
|
|
18191
|
+
} finally {
|
|
18192
|
+
clearTimeout(timer);
|
|
18193
|
+
signal?.removeEventListener("abort", forwardAbort);
|
|
18194
|
+
if (rejectAborted) controller.signal.removeEventListener("abort", rejectAborted);
|
|
18195
|
+
}
|
|
18196
|
+
};
|
|
18197
|
+
const account = await request("/account", {}, options.signal);
|
|
18198
|
+
if (!record(account) || account.state !== "active") {
|
|
18199
|
+
throw new RemoteMemoryError(
|
|
18200
|
+
"Complete and verify migration before using remote memories",
|
|
18201
|
+
409,
|
|
18202
|
+
"memory_not_active"
|
|
18203
|
+
);
|
|
18204
|
+
}
|
|
18205
|
+
if (account.key_id !== options.keyId) {
|
|
18206
|
+
throw new RemoteMemoryError(
|
|
18207
|
+
"The canonical memory key does not match this account",
|
|
18208
|
+
409,
|
|
18209
|
+
"key_mismatch"
|
|
18210
|
+
);
|
|
18211
|
+
}
|
|
18212
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
18213
|
+
const decode = async (value) => {
|
|
18214
|
+
const item = memoryRecord(value);
|
|
18215
|
+
const decrypt = async (ciphertext) => {
|
|
18216
|
+
if (!ciphertextPattern.test(ciphertext))
|
|
18217
|
+
throw new Error("Nearby returned unencrypted memory content");
|
|
18218
|
+
const plaintext = await options.decrypt(ciphertext);
|
|
18219
|
+
if (plaintext === ciphertext) throw new Error("Memory decryption failed");
|
|
18220
|
+
return plaintext;
|
|
18221
|
+
};
|
|
18222
|
+
const decoded = {
|
|
18223
|
+
...item,
|
|
18224
|
+
memory: {
|
|
18225
|
+
...item.memory,
|
|
18226
|
+
content: await decrypt(item.memory.content),
|
|
18227
|
+
...item.memory.kind_value !== void 0 && {
|
|
18228
|
+
kind_value: await decrypt(item.memory.kind_value)
|
|
18229
|
+
}
|
|
18230
|
+
}
|
|
18231
|
+
};
|
|
18232
|
+
return remember(decoded, item);
|
|
18233
|
+
};
|
|
18234
|
+
const remember = (decoded, item) => {
|
|
18235
|
+
snapshots.set(decoded, {
|
|
18236
|
+
id: item.memory.memory_id,
|
|
18237
|
+
version: item.version,
|
|
18238
|
+
content: decoded.memory.content,
|
|
18239
|
+
kindValue: decoded.memory.kind_value,
|
|
18240
|
+
encryptedContent: item.memory.content,
|
|
18241
|
+
encryptedKindValue: item.memory.kind_value
|
|
18242
|
+
});
|
|
18243
|
+
return decoded;
|
|
18244
|
+
};
|
|
18245
|
+
const decodeAll = async (values) => {
|
|
18246
|
+
const records = values.map(memoryRecord);
|
|
18247
|
+
const settled = await Promise.allSettled(records.map(decode));
|
|
18248
|
+
const items = [];
|
|
18249
|
+
const failed = [];
|
|
18250
|
+
settled.forEach((result, i) => {
|
|
18251
|
+
if (result.status === "fulfilled") items.push(result.value);
|
|
18252
|
+
else
|
|
18253
|
+
failed.push({
|
|
18254
|
+
memory_id: records[i].memory.memory_id,
|
|
18255
|
+
version: records[i].version,
|
|
18256
|
+
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
18257
|
+
});
|
|
18258
|
+
});
|
|
18259
|
+
return { items, failed };
|
|
18260
|
+
};
|
|
18261
|
+
const decodeCommitted = async (value, write) => {
|
|
18262
|
+
const item = memoryRecord(value);
|
|
18263
|
+
if (item.memory.memory_id !== write.body.memory.memory_id || item.memory.content !== write.body.memory.content || item.memory.kind_value !== write.body.memory.kind_value)
|
|
18264
|
+
return decode(item);
|
|
18265
|
+
return remember(
|
|
18266
|
+
{
|
|
18267
|
+
...item,
|
|
18268
|
+
memory: {
|
|
18269
|
+
...item.memory,
|
|
18270
|
+
content: write.content,
|
|
18271
|
+
...write.kindValue !== void 0 && { kind_value: write.kindValue }
|
|
18272
|
+
}
|
|
18273
|
+
},
|
|
18274
|
+
item
|
|
18275
|
+
);
|
|
18276
|
+
};
|
|
18277
|
+
const encryptField2 = async (plaintext) => {
|
|
18278
|
+
const ciphertext = await options.encrypt(plaintext);
|
|
18279
|
+
if (ciphertext === plaintext || !ciphertextPattern.test(ciphertext))
|
|
18280
|
+
throw new Error("Field encryption must return SDK ciphertext; refusing to upload plaintext");
|
|
18281
|
+
return ciphertext;
|
|
18282
|
+
};
|
|
18283
|
+
const memoryPath = (id) => {
|
|
18284
|
+
if (!id || id.length > 128) throw new Error("memory_id must be 1\u2013128 characters");
|
|
18285
|
+
return "/memories/" + encodeURIComponent(id);
|
|
18286
|
+
};
|
|
18287
|
+
const prepareWrite = async (memory, expectedVersion, signal) => {
|
|
18288
|
+
const unknown = Object.keys(memory).filter(
|
|
18289
|
+
(key) => !Object.prototype.hasOwnProperty.call(memoryFields, key)
|
|
18290
|
+
);
|
|
18291
|
+
if (unknown.length) {
|
|
18292
|
+
throw new RemoteMemoryError(
|
|
18293
|
+
`Unknown private-memory fields (${unknown.join(", ")}); refusing to forward them`,
|
|
18294
|
+
400,
|
|
18295
|
+
"unknown_field"
|
|
18296
|
+
);
|
|
18297
|
+
}
|
|
18298
|
+
memory = { ...memory, ...memory.embedding && { embedding: [...memory.embedding] } };
|
|
18299
|
+
const path = memoryPath(memory.memory_id);
|
|
18300
|
+
const snapshot = typeof expectedVersion === "number" ? void 0 : snapshots.get(expectedVersion);
|
|
18301
|
+
if (typeof expectedVersion !== "number" && (!snapshot || snapshot.id !== memory.memory_id || snapshot.version !== expectedVersion.version))
|
|
18302
|
+
throw new Error(
|
|
18303
|
+
"Expected snapshot must be an unmodified version from this persistence instance"
|
|
18304
|
+
);
|
|
18305
|
+
expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
|
|
18306
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
18307
|
+
throw new Error("expectedVersion must be a nonnegative integer");
|
|
18308
|
+
const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
|
|
18309
|
+
let existing;
|
|
18310
|
+
if (expectedVersion !== 0 && !snapshot) {
|
|
18311
|
+
try {
|
|
18312
|
+
existing = memoryRecord(await request(path, {}, signal));
|
|
18313
|
+
} catch (error) {
|
|
18314
|
+
if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
|
|
18315
|
+
throw error;
|
|
18316
|
+
}
|
|
18317
|
+
}
|
|
18318
|
+
if (existing && existing.version !== expectedVersion) throw conflict();
|
|
18319
|
+
const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
|
|
18320
|
+
const content = (snapshot?.content ?? decoded?.memory.content) === memory.content ? snapshot?.encryptedContent ?? existing.memory.content : await encryptField2(memory.content);
|
|
18321
|
+
const kindValue = memory.kind_value === void 0 ? void 0 : (snapshot?.kindValue ?? decoded?.memory.kind_value) === memory.kind_value ? snapshot?.encryptedKindValue ?? existing.memory.kind_value : await encryptField2(memory.kind_value);
|
|
18322
|
+
return {
|
|
18323
|
+
body: {
|
|
18324
|
+
expected_version: expectedVersion,
|
|
18325
|
+
memory: { ...memory, content, ...kindValue !== void 0 && { kind_value: kindValue } }
|
|
18326
|
+
},
|
|
18327
|
+
content: memory.content,
|
|
18328
|
+
kindValue: memory.kind_value
|
|
18329
|
+
};
|
|
18330
|
+
};
|
|
18331
|
+
const fetchCandidates = async (embedding, candidateOptions, withCounts) => {
|
|
18332
|
+
const limit = candidateOptions.limit ?? 100;
|
|
18333
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
18334
|
+
throw new Error("Candidate limit must be 1\u2013100");
|
|
18335
|
+
for (const [key, max] of candidateListLimits) {
|
|
18336
|
+
const values = candidateOptions[key];
|
|
18337
|
+
if (values && values.length > max)
|
|
18338
|
+
throw new Error(`Candidate ${key} accepts at most ${max} entries (got ${values.length})`);
|
|
18339
|
+
}
|
|
18340
|
+
const result = await request(
|
|
18341
|
+
"/candidates",
|
|
18342
|
+
{
|
|
18343
|
+
method: "POST",
|
|
18344
|
+
body: JSON.stringify({
|
|
18345
|
+
embedding,
|
|
18346
|
+
limit,
|
|
18347
|
+
force_ids: candidateOptions.force_ids ?? [],
|
|
18348
|
+
...withCounts && { with_counts: true },
|
|
18349
|
+
...Object.fromEntries(
|
|
18350
|
+
[
|
|
18351
|
+
"scopes",
|
|
18352
|
+
"memory_ids",
|
|
18353
|
+
"embedding_model",
|
|
18354
|
+
"strict_model",
|
|
18355
|
+
"include_deleted",
|
|
18356
|
+
"deleted_only"
|
|
18357
|
+
].filter(
|
|
18358
|
+
(key) => candidateOptions[key] !== void 0
|
|
18359
|
+
).map((key) => [key, candidateOptions[key]])
|
|
18360
|
+
),
|
|
18361
|
+
...candidateOptions.fact_types !== void 0 && {
|
|
18362
|
+
fact_types: candidateOptions.fact_types
|
|
18363
|
+
},
|
|
18364
|
+
...candidateOptions.include_archived !== void 0 && {
|
|
18365
|
+
include_archived: candidateOptions.include_archived
|
|
18366
|
+
},
|
|
18367
|
+
...candidateOptions.include_quarantined !== void 0 && {
|
|
18368
|
+
include_quarantined: candidateOptions.include_quarantined
|
|
18369
|
+
},
|
|
18370
|
+
...candidateOptions.include_superseded !== void 0 && {
|
|
18371
|
+
include_superseded: candidateOptions.include_superseded
|
|
18372
|
+
}
|
|
18373
|
+
})
|
|
18374
|
+
},
|
|
18375
|
+
candidateOptions.signal
|
|
18376
|
+
);
|
|
18377
|
+
if (!record(result) || !Array.isArray(result.items))
|
|
18378
|
+
throw new Error("Invalid nearby candidate response");
|
|
18379
|
+
return result;
|
|
18380
|
+
};
|
|
18381
|
+
const candidateSet = async (embedding, candidateOptions = {}) => {
|
|
18382
|
+
const result = await fetchCandidates(embedding, candidateOptions, true);
|
|
18383
|
+
if (!Number.isSafeInteger(result.total_count) || result.total_count < 0 || !Number.isSafeInteger(result.unavailable_count) || result.unavailable_count < 0)
|
|
18384
|
+
throw new Error("Invalid nearby candidate response");
|
|
18385
|
+
return {
|
|
18386
|
+
...await decodeAll(result.items),
|
|
18387
|
+
total_count: result.total_count,
|
|
18388
|
+
unavailable_count: result.unavailable_count
|
|
18389
|
+
};
|
|
18390
|
+
};
|
|
18391
|
+
return {
|
|
18392
|
+
get: async (id, signal) => {
|
|
18393
|
+
try {
|
|
18394
|
+
return await decode(await request(memoryPath(id), {}, signal));
|
|
18395
|
+
} catch (error) {
|
|
18396
|
+
if (error instanceof RemoteMemoryError && error.status === 404) return null;
|
|
18397
|
+
throw error;
|
|
18398
|
+
}
|
|
18399
|
+
},
|
|
18400
|
+
list: async (listOptions = {}) => {
|
|
18401
|
+
const { signal, ...query } = listOptions;
|
|
18402
|
+
if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) {
|
|
18403
|
+
throw new Error("Page limit must be 1\u2013200");
|
|
18404
|
+
}
|
|
18405
|
+
const params = new URLSearchParams();
|
|
18406
|
+
for (const key of [
|
|
18407
|
+
"cursor",
|
|
18408
|
+
"limit",
|
|
18409
|
+
"include_deleted",
|
|
18410
|
+
"include_archived",
|
|
18411
|
+
"include_quarantined",
|
|
18412
|
+
"include_superseded",
|
|
18413
|
+
"include_embeddings"
|
|
18414
|
+
]) {
|
|
18415
|
+
if (query[key] !== void 0) params.set(key, String(query[key]));
|
|
18416
|
+
}
|
|
18417
|
+
const page = await request("/memories?" + params.toString(), {}, signal);
|
|
18418
|
+
if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
|
|
18419
|
+
throw new Error("Invalid nearby private-memory page");
|
|
18420
|
+
}
|
|
18421
|
+
return {
|
|
18422
|
+
...await decodeAll(page.items),
|
|
18423
|
+
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
|
|
18424
|
+
};
|
|
18425
|
+
},
|
|
18426
|
+
put: async (memory, expectedVersion, signal) => {
|
|
18427
|
+
const write = await prepareWrite(memory, expectedVersion, signal);
|
|
18428
|
+
return decodeCommitted(
|
|
18429
|
+
await request(
|
|
18430
|
+
memoryPath(write.body.memory.memory_id),
|
|
18431
|
+
{
|
|
18432
|
+
method: "PUT",
|
|
18433
|
+
body: JSON.stringify({ key_id: options.keyId, ...write.body })
|
|
18434
|
+
},
|
|
18435
|
+
signal
|
|
18436
|
+
),
|
|
18437
|
+
write
|
|
18438
|
+
);
|
|
18439
|
+
},
|
|
18440
|
+
putMany: async (writes, signal) => {
|
|
18441
|
+
if (writes.length < 1 || writes.length > 50 || new Set(writes.map((w) => w.memory.memory_id)).size !== writes.length)
|
|
18442
|
+
throw new Error("Batch must contain 1\u201350 distinct memory ids");
|
|
18443
|
+
const prepared = await Promise.all(
|
|
18444
|
+
writes.map((w) => prepareWrite(w.memory, w.expectedVersion, signal))
|
|
18445
|
+
);
|
|
18446
|
+
const result = await request(
|
|
18447
|
+
"/memories/batch",
|
|
18448
|
+
{
|
|
18449
|
+
method: "POST",
|
|
18450
|
+
body: JSON.stringify({ key_id: options.keyId, writes: prepared.map((w) => w.body) })
|
|
18451
|
+
},
|
|
18452
|
+
signal
|
|
18453
|
+
);
|
|
18454
|
+
if (!record(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
|
|
18455
|
+
throw new Error("Invalid nearby batch response");
|
|
18456
|
+
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
18457
|
+
},
|
|
18458
|
+
candidateSet,
|
|
18459
|
+
candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
|
|
18460
|
+
};
|
|
18461
|
+
}
|
|
18462
|
+
|
|
18463
|
+
// src/lib/memory/store/remotePipeline.ts
|
|
18464
|
+
import { v7 as uuidv74 } from "uuid";
|
|
18465
|
+
function storedVector(vector) {
|
|
18466
|
+
if (!Array.isArray(vector) || vector.length !== 1536 && vector.length !== 4096 || vector.some((v) => !Number.isFinite(v)))
|
|
18467
|
+
throw new Error("Remote memories require a finite 1536/4096-dimensional vector");
|
|
18468
|
+
const out = vector.slice(0, 1536);
|
|
18469
|
+
const norm = Math.sqrt(out.reduce((sum, v) => sum + v * v, 0));
|
|
18470
|
+
if (!norm) throw new Error("Remote query/content vector has no direction after MRL truncation");
|
|
18471
|
+
return out.map((v) => v / norm);
|
|
18472
|
+
}
|
|
18473
|
+
function sourceIds(value) {
|
|
18474
|
+
if (!value) return [];
|
|
18475
|
+
try {
|
|
18476
|
+
const parsed = JSON.parse(value);
|
|
18477
|
+
return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
|
|
18478
|
+
} catch {
|
|
18479
|
+
return [];
|
|
18480
|
+
}
|
|
18481
|
+
}
|
|
18482
|
+
function isMemoryLevel(value) {
|
|
18483
|
+
return MEMORY_LEVELS.includes(value);
|
|
18484
|
+
}
|
|
18485
|
+
function stored(row) {
|
|
18486
|
+
return {
|
|
18487
|
+
uniqueId: row.memory_id,
|
|
18488
|
+
content: row.content,
|
|
18489
|
+
scope: row.scope,
|
|
18490
|
+
folderId: row.folder_id ?? null,
|
|
18491
|
+
userId: null,
|
|
18492
|
+
kind: row.kind ?? null,
|
|
18493
|
+
kindValue: row.kind_value ?? null,
|
|
18494
|
+
...isMemoryLevel(row.level) && { level: row.level },
|
|
18495
|
+
embedding: row.embedding ? JSON.stringify(row.embedding) : null,
|
|
18496
|
+
embeddingModel: row.embedding_model ?? null,
|
|
18497
|
+
sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
|
|
18498
|
+
proofCount: row.proof_count ?? null,
|
|
18499
|
+
source: row.source ?? null,
|
|
18500
|
+
media: parseMedia(row.media),
|
|
18501
|
+
eventTimeStart: row.event_time_start ?? null,
|
|
18502
|
+
eventTimeEnd: row.event_time_end ?? null,
|
|
18503
|
+
eventTimeKind: row.event_time_kind ?? null,
|
|
18504
|
+
topicsUserManaged: row.topics_user_managed ?? false,
|
|
18505
|
+
topics: parseTopics(row.topics),
|
|
18506
|
+
topicsUpdatedAt: row.topics_updated_at ?? null,
|
|
18507
|
+
topicsExtractedAt: row.topics_extracted_at ?? null,
|
|
18508
|
+
topicsExtractedVersion: row.topics_extracted_version ?? null,
|
|
18509
|
+
supersededBy: row.superseded_by ?? null,
|
|
18510
|
+
supersededAt: row.superseded_at ?? null,
|
|
18511
|
+
lastObservedAt: row.last_observed_at ?? null,
|
|
18512
|
+
factType: row.fact_type ?? null,
|
|
18513
|
+
archivedAt: row.archived_at ?? null,
|
|
18514
|
+
trustTier: row.trust_tier ?? null,
|
|
18515
|
+
visibility: row.visibility === "public" ? "public" : "private",
|
|
18516
|
+
twinOptIn: row.twin_opt_in ?? false,
|
|
18517
|
+
publishedAt: row.published_at ?? null,
|
|
18518
|
+
geohash: row.geohash ?? null,
|
|
18519
|
+
createdAt: new Date(row.created_at),
|
|
18520
|
+
updatedAt: new Date(row.updated_at),
|
|
18521
|
+
isDeleted: row.is_deleted
|
|
18522
|
+
};
|
|
18523
|
+
}
|
|
18524
|
+
function createRemoteMemoryPipeline(options) {
|
|
18525
|
+
const { persistence, embeddingOptions } = options;
|
|
18526
|
+
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
18527
|
+
const operation = (mode) => {
|
|
18528
|
+
const rejectUndecryptable = (failed) => {
|
|
18529
|
+
if (!failed.length) return;
|
|
18530
|
+
if (mode === "retain")
|
|
18531
|
+
throw new Error(
|
|
18532
|
+
`Remote memories could not decrypt ${failed.length} candidate row(s); refusing to retain until they are repaired`
|
|
18533
|
+
);
|
|
18534
|
+
getLogger().warn(
|
|
18535
|
+
`[memory/remote] Skipping ${failed.length} undecryptable candidate row(s)`,
|
|
18536
|
+
failed.map((failure) => failure.memory_id)
|
|
18537
|
+
);
|
|
18538
|
+
};
|
|
18539
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
18540
|
+
const remember = (items) => {
|
|
18541
|
+
items.forEach((item) => snapshots.set(item.memory.memory_id, item));
|
|
18542
|
+
return items.map((item) => stored(item.memory));
|
|
18543
|
+
};
|
|
18544
|
+
const get = async (id) => {
|
|
18545
|
+
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
18546
|
+
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
18547
|
+
snapshots.set(id, snapshot);
|
|
18548
|
+
return stored(snapshot.memory);
|
|
18549
|
+
};
|
|
18550
|
+
const prepare = async (query, search = {}) => {
|
|
18551
|
+
if (search.folderId !== void 0)
|
|
18552
|
+
throw new Error("Remote memories do not support folder filters");
|
|
18553
|
+
const facets = normalizeSubQueries(search.subQueries);
|
|
18554
|
+
const facetQueries = facets.length >= 2 ? facets : [];
|
|
18555
|
+
const start = Date.now();
|
|
18556
|
+
const budgetMs = search.queryEmbedTotalTimeoutMs ?? 8e3;
|
|
18557
|
+
const embed = (texts) => generateEmbeddings(texts, {
|
|
18558
|
+
...embeddingOptions,
|
|
18559
|
+
totalTimeoutMs: budgetMs
|
|
18560
|
+
});
|
|
18561
|
+
const embedFacets = async () => {
|
|
18562
|
+
if (!facetQueries.length) return [];
|
|
18563
|
+
try {
|
|
18564
|
+
const vectors2 = await embed(facetQueries);
|
|
18565
|
+
if (vectors2.length !== facetQueries.length)
|
|
18566
|
+
throw new Error("Incomplete facet embeddings");
|
|
18567
|
+
return vectors2.map(storedVector);
|
|
18568
|
+
} catch (error) {
|
|
18569
|
+
getLogger().warn(
|
|
18570
|
+
"[memory/remote] Facet embeddings unavailable; using primary query",
|
|
18571
|
+
error
|
|
18572
|
+
);
|
|
18573
|
+
return [];
|
|
18574
|
+
}
|
|
18575
|
+
};
|
|
18576
|
+
const [primary, facetEmbeddings] = await Promise.all([
|
|
18577
|
+
search.queryEmbedding ?? embed([query]).then((vectors2) => vectors2[0]),
|
|
18578
|
+
embedFacets()
|
|
18579
|
+
]);
|
|
18580
|
+
const queryEmbedding = storedVector(primary);
|
|
18581
|
+
const queryEmbedMs = Date.now() - start;
|
|
18582
|
+
const graph = search.entityRanking ?? [];
|
|
18583
|
+
const temporal = search.temporalRanking ?? [];
|
|
18584
|
+
const forced = /* @__PURE__ */ new Set();
|
|
18585
|
+
for (let i = 0; i < Math.max(graph.length, temporal.length) && forced.size < 100; i++) {
|
|
18586
|
+
if (graph[i] !== void 0) forced.add(graph[i]);
|
|
18587
|
+
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
18588
|
+
}
|
|
18589
|
+
const forceIds = [...forced];
|
|
18590
|
+
const windowOptions = (i, signal) => ({
|
|
18591
|
+
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
18592
|
+
force_ids: i === 0 ? forceIds : [],
|
|
18593
|
+
...search.scopes && { scopes: search.scopes },
|
|
18594
|
+
...search.factTypes && { fact_types: search.factTypes },
|
|
18595
|
+
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
18596
|
+
include_archived: search.includeArchived,
|
|
18597
|
+
embedding_model: model,
|
|
18598
|
+
...signal && { signal }
|
|
18599
|
+
});
|
|
18600
|
+
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
18601
|
+
let windows;
|
|
18602
|
+
if (mode === "retain") {
|
|
18603
|
+
windows = await Promise.all(
|
|
18604
|
+
vectors.map((embedding, i) => persistence.candidateSet(embedding, windowOptions(i)))
|
|
18605
|
+
);
|
|
18606
|
+
} else {
|
|
18607
|
+
const deadline = new AbortController();
|
|
18608
|
+
const timer = setTimeout(
|
|
18609
|
+
() => deadline.abort(
|
|
18610
|
+
new RemoteMemoryError("Remote recall exceeded its query budget", 408, "timeout")
|
|
18611
|
+
),
|
|
18612
|
+
Math.max(0, start + budgetMs - Date.now())
|
|
18613
|
+
);
|
|
18614
|
+
try {
|
|
18615
|
+
windows = await Promise.all(
|
|
18616
|
+
vectors.map(
|
|
18617
|
+
(embedding, i) => persistence.candidates(embedding, windowOptions(i, deadline.signal))
|
|
18618
|
+
)
|
|
18619
|
+
);
|
|
18620
|
+
} finally {
|
|
18621
|
+
clearTimeout(timer);
|
|
18622
|
+
}
|
|
18623
|
+
}
|
|
18624
|
+
rejectUndecryptable([
|
|
18625
|
+
...new Map(
|
|
18626
|
+
windows.flatMap((window2) => window2.failed).map((failure) => [failure.memory_id, failure])
|
|
18627
|
+
).values()
|
|
18628
|
+
]);
|
|
18629
|
+
const items = [
|
|
18630
|
+
...new Map(
|
|
18631
|
+
windows.flatMap((window2) => window2.items).map((item) => [item.memory.memory_id, item])
|
|
18632
|
+
).values()
|
|
18633
|
+
];
|
|
18634
|
+
const memories = remember(items);
|
|
18635
|
+
return {
|
|
18636
|
+
memories,
|
|
18637
|
+
embeddedItems: memories.map((memory) => ({
|
|
18638
|
+
id: memory.uniqueId,
|
|
18639
|
+
content: memory.content,
|
|
18640
|
+
embedding: JSON.parse(memory.embedding ?? "[]"),
|
|
18641
|
+
createdAt: memory.createdAt,
|
|
18642
|
+
updatedAt: memory.updatedAt,
|
|
18643
|
+
proofCount: memory.proofCount,
|
|
18644
|
+
lastObservedAt: memory.lastObservedAt,
|
|
18645
|
+
eventTimeStart: memory.eventTimeStart,
|
|
18646
|
+
eventTimeEnd: memory.eventTimeEnd,
|
|
18647
|
+
eventTimeKind: memory.eventTimeKind === "point" || memory.eventTimeKind === "range" || memory.eventTimeKind === "ongoing" ? memory.eventTimeKind : null,
|
|
18648
|
+
factType: memory.factType,
|
|
18649
|
+
sourceChunkIds: memory.sourceChunkIds
|
|
18650
|
+
})),
|
|
18651
|
+
queryEmbedding,
|
|
18652
|
+
facetEmbeddings,
|
|
18653
|
+
vaultSize: Math.max(windows[0].total_count ?? 0, items.length),
|
|
18654
|
+
embeddingFailure: windows.some((window2) => (window2.unavailable_count ?? 0) > 0),
|
|
18655
|
+
embeddingsUnavailable: (windows[0].total_count ?? items.length) > 0 && !memories.some((memory) => memory.embedding),
|
|
18656
|
+
decryptLast: true,
|
|
18657
|
+
rowsDecrypted: items.length,
|
|
18658
|
+
queryEmbedMs,
|
|
18659
|
+
rowsEmbedded: 0
|
|
18660
|
+
};
|
|
18661
|
+
};
|
|
18662
|
+
const createRow = (input) => {
|
|
18663
|
+
if (input.folderId !== void 0 && input.folderId !== null)
|
|
18664
|
+
throw new Error("Remote memories do not support folders");
|
|
18665
|
+
const now = Date.now();
|
|
18666
|
+
return {
|
|
18667
|
+
memory_id: uuidv74(),
|
|
18668
|
+
content: input.content,
|
|
18669
|
+
scope: input.scope ?? "private",
|
|
18670
|
+
created_at: now,
|
|
18671
|
+
updated_at: now,
|
|
18672
|
+
is_deleted: false,
|
|
18673
|
+
...input.embedding !== void 0 && {
|
|
18674
|
+
embedding: storedVector(JSON.parse(input.embedding)),
|
|
18675
|
+
embedding_model: input.embeddingModel
|
|
18676
|
+
},
|
|
18677
|
+
source_chunk_ids: JSON.stringify(input.sourceChunkIds ?? []),
|
|
18678
|
+
proof_count: input.proofCount ?? 1,
|
|
18679
|
+
source: input.source ?? "manual",
|
|
18680
|
+
...input.eventTime && {
|
|
18681
|
+
event_time_start: input.eventTime.start ?? void 0,
|
|
18682
|
+
event_time_end: input.eventTime.end ?? void 0,
|
|
18683
|
+
event_time_kind: input.eventTime.kind ?? void 0
|
|
18684
|
+
},
|
|
18685
|
+
fact_type: input.factType,
|
|
18686
|
+
trust_tier: normalizeTrustTier(input.trustTier) ?? void 0,
|
|
18687
|
+
geohash: input.geohash,
|
|
18688
|
+
visibility: "private",
|
|
18689
|
+
twin_opt_in: false
|
|
18690
|
+
};
|
|
18691
|
+
};
|
|
18692
|
+
const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
|
|
18693
|
+
const port = {
|
|
18694
|
+
prepare,
|
|
18695
|
+
get,
|
|
18696
|
+
getFresh: async (id) => {
|
|
18697
|
+
const current = await persistence.get(id);
|
|
18698
|
+
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
18699
|
+
},
|
|
18700
|
+
tombstones: async (embedding, embeddingModel, scope, folderId) => {
|
|
18701
|
+
if (folderId !== void 0) throw new Error("Remote memories do not support folders");
|
|
18702
|
+
const window2 = await persistence.candidateSet(storedVector(embedding), {
|
|
18703
|
+
limit: 1,
|
|
18704
|
+
scopes: [scope],
|
|
18705
|
+
embedding_model: embeddingModel,
|
|
18706
|
+
strict_model: true,
|
|
18707
|
+
include_deleted: true,
|
|
18708
|
+
deleted_only: true
|
|
18709
|
+
});
|
|
18710
|
+
rejectUndecryptable(window2.failed);
|
|
18711
|
+
return remember(window2.items);
|
|
18712
|
+
},
|
|
18713
|
+
create: (input) => write(createRow(input), 0),
|
|
18714
|
+
update: async (id, patch) => {
|
|
18715
|
+
const existing = await get(id);
|
|
18716
|
+
if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
18717
|
+
return null;
|
|
18718
|
+
const snapshot = snapshots.get(id);
|
|
18719
|
+
const memory = {
|
|
18720
|
+
...snapshot.memory,
|
|
18721
|
+
content: patch.content,
|
|
18722
|
+
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
|
|
18723
|
+
};
|
|
18724
|
+
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
18725
|
+
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
18726
|
+
delete memory.embedding;
|
|
18727
|
+
delete memory.embedding_model;
|
|
18728
|
+
}
|
|
18729
|
+
if (patch.embedding !== void 0) {
|
|
18730
|
+
memory.embedding = patch.embedding === null ? [] : storedVector(JSON.parse(patch.embedding));
|
|
18731
|
+
memory.embedding_model = patch.embeddingModel ?? void 0;
|
|
18732
|
+
}
|
|
18733
|
+
const observed = sourceIds(memory.source_chunk_ids);
|
|
18734
|
+
const replay = !!patch.observationSourceIds?.length && patch.observationSourceIds.every((id2) => observed.includes(id2));
|
|
18735
|
+
if (patch.sourceChunkIds !== void 0)
|
|
18736
|
+
memory.source_chunk_ids = JSON.stringify(
|
|
18737
|
+
patch.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observed, ...patch.sourceChunkIds])] : patch.sourceChunkIds
|
|
18738
|
+
);
|
|
18739
|
+
if (!replay) {
|
|
18740
|
+
if (patch.proofCountIncrement !== void 0)
|
|
18741
|
+
memory.proof_count = (memory.proof_count ?? 1) + patch.proofCountIncrement;
|
|
18742
|
+
else if (patch.proofCount !== void 0) memory.proof_count = patch.proofCount;
|
|
18743
|
+
if (patch.lastObservedAt !== void 0) memory.last_observed_at = patch.lastObservedAt;
|
|
18744
|
+
}
|
|
18745
|
+
if (patch.source !== void 0) memory.source = patch.source;
|
|
18746
|
+
if (patch.factType !== void 0) memory.fact_type = patch.factType;
|
|
18747
|
+
if (patch.trustTier !== void 0)
|
|
18748
|
+
memory.trust_tier = normalizeTrustTier(patch.trustTier) ?? void 0;
|
|
18749
|
+
if (patch.topicsUserManaged !== void 0)
|
|
18750
|
+
memory.topics_user_managed = patch.topicsUserManaged;
|
|
18751
|
+
if (patch.eventTime !== void 0) {
|
|
18752
|
+
memory.event_time_start = patch.eventTime.start ?? void 0;
|
|
18753
|
+
memory.event_time_end = patch.eventTime.end ?? void 0;
|
|
18754
|
+
memory.event_time_kind = patch.eventTime.kind ?? void 0;
|
|
18755
|
+
}
|
|
18756
|
+
if (patch.restore) memory.archived_at = void 0;
|
|
18757
|
+
return write(memory, snapshot);
|
|
18758
|
+
},
|
|
18759
|
+
supersede: async (id, successor) => {
|
|
18760
|
+
const [target, newer] = await Promise.all([get(id), get(successor)]);
|
|
18761
|
+
if (!target || !newer || id === successor) return false;
|
|
18762
|
+
const old = snapshots.get(id);
|
|
18763
|
+
const next = snapshots.get(successor);
|
|
18764
|
+
remember(
|
|
18765
|
+
await persistence.putMany([
|
|
18766
|
+
{
|
|
18767
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
18768
|
+
expectedVersion: old
|
|
18769
|
+
},
|
|
18770
|
+
{ memory: next.memory, expectedVersion: next }
|
|
18771
|
+
])
|
|
18772
|
+
);
|
|
18773
|
+
return true;
|
|
18774
|
+
},
|
|
18775
|
+
createSuperseding: async (input, targetId) => {
|
|
18776
|
+
const target = await get(targetId);
|
|
18777
|
+
if (!target) return { created: null, retired: false };
|
|
18778
|
+
const snapshot = snapshots.get(targetId);
|
|
18779
|
+
const successor = createRow(input);
|
|
18780
|
+
const rows = remember(
|
|
18781
|
+
await persistence.putMany([
|
|
18782
|
+
{ memory: successor, expectedVersion: 0 },
|
|
18783
|
+
{
|
|
18784
|
+
memory: {
|
|
18785
|
+
...snapshot.memory,
|
|
18786
|
+
superseded_by: successor.memory_id,
|
|
18787
|
+
superseded_at: Date.now()
|
|
18788
|
+
},
|
|
18789
|
+
expectedVersion: snapshot
|
|
18790
|
+
}
|
|
18791
|
+
])
|
|
18792
|
+
);
|
|
18793
|
+
return { created: rows[0], retired: true };
|
|
18794
|
+
}
|
|
18795
|
+
};
|
|
18796
|
+
return { prepare, port };
|
|
18797
|
+
};
|
|
18798
|
+
return {
|
|
18799
|
+
recall: async (query, recallOptions = {}) => {
|
|
18800
|
+
const { prepare } = operation("recall");
|
|
18801
|
+
return recall(
|
|
18802
|
+
query,
|
|
18803
|
+
{
|
|
18804
|
+
embeddingOptions,
|
|
18805
|
+
factSource: {
|
|
18806
|
+
graphRanking: options.graphRanking,
|
|
18807
|
+
temporalRanking: options.temporalRanking,
|
|
18808
|
+
search: async (text12, searchOptions) => {
|
|
18809
|
+
const prepared = await prepare(text12, searchOptions);
|
|
18810
|
+
const ranked = await rankPreparedVaultCandidates(
|
|
18811
|
+
text12,
|
|
18812
|
+
prepared,
|
|
18813
|
+
embeddingOptions,
|
|
18814
|
+
searchOptions
|
|
18815
|
+
);
|
|
18816
|
+
return {
|
|
18817
|
+
...ranked,
|
|
18818
|
+
rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
|
|
18819
|
+
decryptLast: true,
|
|
18820
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
18821
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
18822
|
+
rowsEmbedded: 0
|
|
18823
|
+
};
|
|
18824
|
+
}
|
|
18825
|
+
}
|
|
18826
|
+
},
|
|
18827
|
+
{ ...recallOptions, types: ["fact"] }
|
|
18828
|
+
);
|
|
18829
|
+
},
|
|
18830
|
+
retain: async (content, retainOptions) => {
|
|
18831
|
+
const { port } = operation("retain");
|
|
18832
|
+
return retainWithPersistence(
|
|
18833
|
+
content,
|
|
18834
|
+
{
|
|
18835
|
+
persistence: port,
|
|
18836
|
+
embeddingOptions,
|
|
18837
|
+
vaultCache: /* @__PURE__ */ new Map(),
|
|
18838
|
+
normalizeEmbedding: storedVector
|
|
18839
|
+
},
|
|
18840
|
+
retainOptions
|
|
18841
|
+
);
|
|
18842
|
+
}
|
|
18843
|
+
};
|
|
18844
|
+
}
|
|
18845
|
+
|
|
17855
18846
|
// src/lib/memory/synthesizeProfile.ts
|
|
17856
18847
|
var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
|
|
17857
18848
|
var DEFAULT_FACET_RECALL_LIMIT = 20;
|
|
@@ -21262,7 +22253,7 @@ function useChat(options) {
|
|
|
21262
22253
|
|
|
21263
22254
|
// src/expo/useChatStorage.ts
|
|
21264
22255
|
import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
|
|
21265
|
-
import { v7 as
|
|
22256
|
+
import { v7 as uuidv76 } from "uuid";
|
|
21266
22257
|
|
|
21267
22258
|
// src/lib/chat/assembleMessages.ts
|
|
21268
22259
|
function assembleMessagesWithHistory(historyMessages, callerMessages, summarySystemMessage) {
|
|
@@ -21919,9 +22910,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
|
|
|
21919
22910
|
}
|
|
21920
22911
|
|
|
21921
22912
|
// src/lib/db/media/types.ts
|
|
21922
|
-
import { v7 as
|
|
22913
|
+
import { v7 as uuidv75 } from "uuid";
|
|
21923
22914
|
function generateMediaId() {
|
|
21924
|
-
return `media_${
|
|
22915
|
+
return `media_${uuidv75()}`;
|
|
21925
22916
|
}
|
|
21926
22917
|
|
|
21927
22918
|
// src/lib/db/media/operations.ts
|
|
@@ -22128,10 +23119,10 @@ function extractImageModelFromToolEvents(toolCallEvents) {
|
|
|
22128
23119
|
}
|
|
22129
23120
|
return void 0;
|
|
22130
23121
|
}
|
|
22131
|
-
function storedToLlmapiMessage(
|
|
22132
|
-
const content = [{ type: "text", text:
|
|
22133
|
-
if (
|
|
22134
|
-
for (const file of
|
|
23122
|
+
function storedToLlmapiMessage(stored2) {
|
|
23123
|
+
const content = [{ type: "text", text: stored2.content }];
|
|
23124
|
+
if (stored2.role !== "assistant" && stored2.files?.length) {
|
|
23125
|
+
for (const file of stored2.files) {
|
|
22135
23126
|
if (isSendableImageURL(file.url)) {
|
|
22136
23127
|
content.push({
|
|
22137
23128
|
type: "image_url",
|
|
@@ -22141,11 +23132,11 @@ function storedToLlmapiMessage(stored) {
|
|
|
22141
23132
|
}
|
|
22142
23133
|
}
|
|
22143
23134
|
const messages = [];
|
|
22144
|
-
if (
|
|
23135
|
+
if (stored2.role === "assistant" && stored2.toolCallEvents?.length) {
|
|
22145
23136
|
messages.push({
|
|
22146
|
-
role:
|
|
23137
|
+
role: stored2.role,
|
|
22147
23138
|
content: void 0,
|
|
22148
|
-
tool_calls:
|
|
23139
|
+
tool_calls: stored2.toolCallEvents.map((event) => ({
|
|
22149
23140
|
id: event.id,
|
|
22150
23141
|
type: "function",
|
|
22151
23142
|
function: {
|
|
@@ -22154,7 +23145,7 @@ function storedToLlmapiMessage(stored) {
|
|
|
22154
23145
|
}
|
|
22155
23146
|
}))
|
|
22156
23147
|
});
|
|
22157
|
-
for (const event of
|
|
23148
|
+
for (const event of stored2.toolCallEvents) {
|
|
22158
23149
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
22159
23150
|
messages.push({
|
|
22160
23151
|
role: "tool",
|
|
@@ -22163,14 +23154,14 @@ function storedToLlmapiMessage(stored) {
|
|
|
22163
23154
|
});
|
|
22164
23155
|
}
|
|
22165
23156
|
}
|
|
22166
|
-
const postToolText =
|
|
23157
|
+
const postToolText = stored2.content.replace(/!\[[^\]]*\]\(https?:\/\/[a-z0-9]+\.r2\.cloudflarestorage\.com\/[^)]+\)/g, "").replace(/https?:\/\/[a-z0-9]+\.r2\.cloudflarestorage\.com\/[^\s)]+/g, "").replace(/!\[[^\]]*\]\(https?:\/\/[^)\s]+\/api\/v1\/media\/[^/)\s]+\/[^)]+\)/g, "").replace(/https?:\/\/[^\s)]+\/api\/v1\/media\/[^/\s)]+\/[^\s)]+/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
22167
23158
|
messages.push({
|
|
22168
|
-
role:
|
|
23159
|
+
role: stored2.role,
|
|
22169
23160
|
content: [{ type: "text", text: postToolText }]
|
|
22170
23161
|
});
|
|
22171
23162
|
} else {
|
|
22172
23163
|
messages.push({
|
|
22173
|
-
role:
|
|
23164
|
+
role: stored2.role,
|
|
22174
23165
|
content
|
|
22175
23166
|
});
|
|
22176
23167
|
}
|
|
@@ -22877,7 +23868,7 @@ function useChatStorage(options) {
|
|
|
22877
23868
|
};
|
|
22878
23869
|
};
|
|
22879
23870
|
pendingResumeRef.current = null;
|
|
22880
|
-
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${
|
|
23871
|
+
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv76()}` : void 0);
|
|
22881
23872
|
const embedToolText = (text12, mask, masked, token) => {
|
|
22882
23873
|
const opts = {
|
|
22883
23874
|
getToken: token,
|
|
@@ -23395,7 +24386,7 @@ function useChatStorage(options) {
|
|
|
23395
24386
|
const detachedResult = result;
|
|
23396
24387
|
if (detachedResult.detached) {
|
|
23397
24388
|
recordToolSetTurn(database, convId, matchedToolSets);
|
|
23398
|
-
const rowId = effectiveAssistantUniqueId ?? `msg_${
|
|
24389
|
+
const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv76()}`;
|
|
23399
24390
|
pendingResumeRef.current = {
|
|
23400
24391
|
handle: detachedResult.resume ?? null,
|
|
23401
24392
|
convId,
|
|
@@ -23904,6 +24895,9 @@ export {
|
|
|
23904
24895
|
LoggerProvider,
|
|
23905
24896
|
MAX_HOPS,
|
|
23906
24897
|
MEDIUM_TTL_MS,
|
|
24898
|
+
MEMORY_KINDS,
|
|
24899
|
+
MEMORY_LEVELS,
|
|
24900
|
+
MemoryLevelError,
|
|
23907
24901
|
NEVER_TTL_MS,
|
|
23908
24902
|
NODE_BUDGET,
|
|
23909
24903
|
NOTION_OAUTH_CONFIG,
|
|
@@ -23914,6 +24908,7 @@ export {
|
|
|
23914
24908
|
QueueManager,
|
|
23915
24909
|
RECALL_MAX_LIMIT,
|
|
23916
24910
|
RECALL_TOOL_NAME,
|
|
24911
|
+
RemoteMemoryError,
|
|
23917
24912
|
RerankerUnavailableError,
|
|
23918
24913
|
SDK_SCHEMA_VERSION,
|
|
23919
24914
|
SHORT_TTL_MS,
|
|
@@ -23977,6 +24972,8 @@ export {
|
|
|
23977
24972
|
createNotionTools,
|
|
23978
24973
|
createPlatformCursorStore,
|
|
23979
24974
|
createRecallTool,
|
|
24975
|
+
createRemoteMemoryPersistence,
|
|
24976
|
+
createRemoteMemoryPipeline,
|
|
23980
24977
|
createStockPricePreProcessor,
|
|
23981
24978
|
createStreamingDeAnonymizer,
|
|
23982
24979
|
createVaultEmbeddingCache,
|