@anuma/sdk 6.33.2 → 6.34.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 +1099 -293
- package/dist/expo/index.d.mts +218 -4
- package/dist/expo/index.d.ts +218 -4
- package/dist/expo/index.mjs +1095 -293
- package/dist/index.cjs +18 -6
- package/dist/index.mjs +18 -6
- package/dist/react/index.cjs +1180 -374
- package/dist/react/index.d.mts +251 -4
- package/dist/react/index.d.ts +251 -4
- package/dist/react/index.mjs +1176 -374
- package/dist/server/index.cjs +118 -86
- package/dist/server/index.d.mts +77 -3
- package/dist/server/index.d.ts +77 -3
- package/dist/server/index.mjs +118 -86
- 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
|
}
|
|
@@ -10486,25 +10498,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
10486
10498
|
const kindBackfills = existing.filter((e) => {
|
|
10487
10499
|
const incoming = kindByName.get(e.canonicalName);
|
|
10488
10500
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
10489
|
-
}).map((
|
|
10501
|
+
}).map((record2) => ({ record: record2, kind: kindByName.get(record2.canonicalName) }));
|
|
10490
10502
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
10491
10503
|
const created = missing.map(
|
|
10492
|
-
(name) => ctx.entityCollection.prepareCreate((
|
|
10493
|
-
|
|
10504
|
+
(name) => ctx.entityCollection.prepareCreate((record2) => {
|
|
10505
|
+
record2._setRaw("canonical_name", name);
|
|
10494
10506
|
const kind = kindByName.get(name);
|
|
10495
|
-
if (kind !== void 0)
|
|
10507
|
+
if (kind !== void 0) record2._setRaw("kind", kind);
|
|
10496
10508
|
})
|
|
10497
10509
|
);
|
|
10498
10510
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
10499
|
-
for (const
|
|
10500
|
-
for (const { record, kind } of kindBackfills) {
|
|
10501
|
-
out.set(
|
|
10511
|
+
for (const record2 of created) out.set(record2.canonicalName, entityToStored(record2));
|
|
10512
|
+
for (const { record: record2, kind } of kindBackfills) {
|
|
10513
|
+
out.set(record2.canonicalName, { ...entityToStored(record2), kind });
|
|
10502
10514
|
}
|
|
10503
10515
|
return { entities: out, operations: created, kindBackfills };
|
|
10504
10516
|
}
|
|
10505
10517
|
function prepareKindBackfills(backfills) {
|
|
10506
10518
|
return backfills.map(
|
|
10507
|
-
({ record, kind }) =>
|
|
10519
|
+
({ record: record2, kind }) => record2.prepareUpdate((r) => {
|
|
10508
10520
|
r._setRaw("kind", kind);
|
|
10509
10521
|
})
|
|
10510
10522
|
);
|
|
@@ -10535,10 +10547,10 @@ function displayNamesOf(entities) {
|
|
|
10535
10547
|
}
|
|
10536
10548
|
return out;
|
|
10537
10549
|
}
|
|
10538
|
-
function topicsEqual(
|
|
10539
|
-
if (
|
|
10550
|
+
function topicsEqual(stored2, computed) {
|
|
10551
|
+
if (stored2 === null || stored2.length !== computed.length) return false;
|
|
10540
10552
|
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
10541
|
-
const storedKeys =
|
|
10553
|
+
const storedKeys = stored2.map(key).sort();
|
|
10542
10554
|
const computedKeys = computed.map(key).sort();
|
|
10543
10555
|
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
10544
10556
|
}
|
|
@@ -10604,10 +10616,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
10604
10616
|
return;
|
|
10605
10617
|
}
|
|
10606
10618
|
const linkOps = toCreate.map(
|
|
10607
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
if (userId !== void 0)
|
|
10619
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
10620
|
+
record2._setRaw("memory_id", memoryId);
|
|
10621
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
10622
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
10611
10623
|
})
|
|
10612
10624
|
);
|
|
10613
10625
|
await ctx.database.batch(
|
|
@@ -10675,10 +10687,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
10675
10687
|
...entityOps,
|
|
10676
10688
|
...prepareKindBackfills(kindBackfills),
|
|
10677
10689
|
...toCreate.map(
|
|
10678
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
if (userId !== void 0)
|
|
10690
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
10691
|
+
record2._setRaw("memory_id", memoryId);
|
|
10692
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
10693
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
10682
10694
|
})
|
|
10683
10695
|
),
|
|
10684
10696
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
@@ -10831,8 +10843,8 @@ function visibilityConditions(requested) {
|
|
|
10831
10843
|
if (excluded.length === 0) return [];
|
|
10832
10844
|
return [Q5.or(Q5.where("visibility", null), Q5.where("visibility", Q5.notIn(excluded)))];
|
|
10833
10845
|
}
|
|
10834
|
-
function isOwnedByCtxUser(ctx,
|
|
10835
|
-
return ctx.userId === void 0 ||
|
|
10846
|
+
function isOwnedByCtxUser(ctx, record2) {
|
|
10847
|
+
return ctx.userId === void 0 || record2.userId === ctx.userId;
|
|
10836
10848
|
}
|
|
10837
10849
|
function baseVaultConditions(ctx, options) {
|
|
10838
10850
|
return [
|
|
@@ -10912,39 +10924,39 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
10912
10924
|
}
|
|
10913
10925
|
return raw;
|
|
10914
10926
|
}
|
|
10915
|
-
function populateNewVaultMemory(
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10927
|
+
function populateNewVaultMemory(record2, ctx, opts, encryptedContent) {
|
|
10928
|
+
record2._setRaw("content", encryptedContent);
|
|
10929
|
+
record2._setRaw("scope", opts.scope ?? "private");
|
|
10930
|
+
record2._setRaw("folder_id", opts.folderId ?? null);
|
|
10931
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
10932
|
+
record2._setRaw("is_deleted", false);
|
|
10921
10933
|
if (opts.embedding !== void 0) {
|
|
10922
|
-
|
|
10923
|
-
|
|
10934
|
+
record2._setRaw("embedding", opts.embedding);
|
|
10935
|
+
record2._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
10924
10936
|
}
|
|
10925
10937
|
if (opts.sourceChunkIds !== void 0) {
|
|
10926
|
-
|
|
10938
|
+
record2._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
10927
10939
|
}
|
|
10928
|
-
|
|
10929
|
-
|
|
10940
|
+
record2._setRaw("proof_count", opts.proofCount ?? 1);
|
|
10941
|
+
record2._setRaw("source", opts.source ?? "manual");
|
|
10930
10942
|
if (opts.eventTime) {
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10943
|
+
record2._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
10944
|
+
record2._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
10945
|
+
record2._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
10934
10946
|
}
|
|
10935
10947
|
if (opts.factType !== void 0) {
|
|
10936
|
-
|
|
10948
|
+
record2._setRaw("fact_type", opts.factType);
|
|
10937
10949
|
}
|
|
10938
10950
|
if (opts.trustTier !== void 0) {
|
|
10939
|
-
|
|
10951
|
+
record2._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
10940
10952
|
}
|
|
10941
|
-
|
|
10942
|
-
|
|
10953
|
+
record2._setRaw("visibility", opts.visibility ?? "private");
|
|
10954
|
+
record2._setRaw(
|
|
10943
10955
|
"published_at",
|
|
10944
10956
|
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
10945
10957
|
);
|
|
10946
10958
|
if (opts.geohash !== void 0) {
|
|
10947
|
-
|
|
10959
|
+
record2._setRaw("geohash", opts.geohash);
|
|
10948
10960
|
}
|
|
10949
10961
|
}
|
|
10950
10962
|
async function createVaultMemoryOp(ctx, opts) {
|
|
@@ -10958,7 +10970,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
10958
10970
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
10959
10971
|
throw new Error("Memory source is no longer eligible");
|
|
10960
10972
|
return ctx.vaultMemoryCollection.create(
|
|
10961
|
-
(
|
|
10973
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
|
|
10962
10974
|
);
|
|
10963
10975
|
});
|
|
10964
10976
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
@@ -10983,7 +10995,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
10983
10995
|
}
|
|
10984
10996
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
10985
10997
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
10986
|
-
(
|
|
10998
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
|
|
10987
10999
|
);
|
|
10988
11000
|
await target.update((r) => {
|
|
10989
11001
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -11065,7 +11077,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11065
11077
|
throw new Error("Memory source is no longer eligible");
|
|
11066
11078
|
const prepared = optionsArray.map(
|
|
11067
11079
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11068
|
-
(
|
|
11080
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i])
|
|
11069
11081
|
)
|
|
11070
11082
|
);
|
|
11071
11083
|
await ctx.database.batch(...prepared);
|
|
@@ -11073,16 +11085,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11073
11085
|
});
|
|
11074
11086
|
return Promise.all(
|
|
11075
11087
|
created.map(
|
|
11076
|
-
(
|
|
11088
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
11077
11089
|
)
|
|
11078
11090
|
);
|
|
11079
11091
|
}
|
|
11080
11092
|
async function getVaultMemoryOp(ctx, id) {
|
|
11081
11093
|
try {
|
|
11082
|
-
const
|
|
11083
|
-
if (
|
|
11094
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11095
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
11084
11096
|
return vaultMemoryToStored(
|
|
11085
|
-
|
|
11097
|
+
record2,
|
|
11086
11098
|
ctx.walletAddress,
|
|
11087
11099
|
ctx.signMessage,
|
|
11088
11100
|
ctx.embeddedWalletSigner
|
|
@@ -11140,11 +11152,11 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
11140
11152
|
};
|
|
11141
11153
|
}
|
|
11142
11154
|
async function vaultMemoryRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner) {
|
|
11143
|
-
const
|
|
11155
|
+
const stored2 = vaultMemoryRawToStoredRaw(raw);
|
|
11144
11156
|
if (walletAddress) {
|
|
11145
|
-
return decryptVaultMemoryFields(
|
|
11157
|
+
return decryptVaultMemoryFields(stored2, walletAddress, signMessage, embeddedWalletSigner);
|
|
11146
11158
|
}
|
|
11147
|
-
return
|
|
11159
|
+
return stored2;
|
|
11148
11160
|
}
|
|
11149
11161
|
async function getAllVaultMemoriesOp(ctx, options) {
|
|
11150
11162
|
const conditions = [
|
|
@@ -11296,13 +11308,13 @@ async function getVaultMemoriesByIdsOp(ctx, ids, options) {
|
|
|
11296
11308
|
async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
11297
11309
|
const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, options)).unsafeFetchRaw();
|
|
11298
11310
|
return mapInBatches(results, async (raw) => {
|
|
11299
|
-
const
|
|
11311
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
11300
11312
|
raw,
|
|
11301
11313
|
ctx.walletAddress,
|
|
11302
11314
|
ctx.signMessage,
|
|
11303
11315
|
ctx.embeddedWalletSigner
|
|
11304
11316
|
);
|
|
11305
|
-
return
|
|
11317
|
+
return stored2.content;
|
|
11306
11318
|
});
|
|
11307
11319
|
}
|
|
11308
11320
|
async function countActiveVaultMemoriesOp(ctx) {
|
|
@@ -11324,12 +11336,12 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11324
11336
|
ctx.embeddedWalletSigner
|
|
11325
11337
|
) : opts.content;
|
|
11326
11338
|
let stale = false;
|
|
11327
|
-
const
|
|
11328
|
-
const originalUpdatedAt =
|
|
11339
|
+
const record2 = probe;
|
|
11340
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11329
11341
|
await ctx.database.write(async () => {
|
|
11330
11342
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11331
11343
|
throw new Error("Memory source is no longer eligible");
|
|
11332
|
-
if (
|
|
11344
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
11333
11345
|
stale = true;
|
|
11334
11346
|
return;
|
|
11335
11347
|
}
|
|
@@ -11337,14 +11349,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11337
11349
|
let replayedObservation = false;
|
|
11338
11350
|
if (opts.observationSourceIds?.length) {
|
|
11339
11351
|
try {
|
|
11340
|
-
const parsed = JSON.parse(
|
|
11352
|
+
const parsed = JSON.parse(record2.sourceChunkIds ?? "[]");
|
|
11341
11353
|
if (Array.isArray(parsed))
|
|
11342
11354
|
observedSources = parsed.filter((id2) => typeof id2 === "string");
|
|
11343
11355
|
} catch {
|
|
11344
11356
|
}
|
|
11345
11357
|
replayedObservation = opts.observationSourceIds.every((id2) => observedSources.includes(id2));
|
|
11346
11358
|
}
|
|
11347
|
-
await
|
|
11359
|
+
await record2.update((r) => {
|
|
11348
11360
|
r._setRaw("content", encryptedContent);
|
|
11349
11361
|
if (opts.scope !== void 0) {
|
|
11350
11362
|
r._setRaw("scope", opts.scope);
|
|
@@ -11401,7 +11413,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11401
11413
|
});
|
|
11402
11414
|
if (stale) return null;
|
|
11403
11415
|
return vaultMemoryToStored(
|
|
11404
|
-
|
|
11416
|
+
record2,
|
|
11405
11417
|
ctx.walletAddress,
|
|
11406
11418
|
ctx.signMessage,
|
|
11407
11419
|
ctx.embeddedWalletSigner
|
|
@@ -11415,21 +11427,21 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
11415
11427
|
if (!entityCtx) {
|
|
11416
11428
|
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
11417
11429
|
}
|
|
11418
|
-
let
|
|
11430
|
+
let record2;
|
|
11419
11431
|
try {
|
|
11420
|
-
|
|
11432
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
11421
11433
|
} catch {
|
|
11422
11434
|
return null;
|
|
11423
11435
|
}
|
|
11424
|
-
if (
|
|
11436
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
11425
11437
|
let stale = false;
|
|
11426
|
-
const originalUpdatedAt =
|
|
11438
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11427
11439
|
await ctx.database.write(async (writer) => {
|
|
11428
|
-
if (
|
|
11440
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11429
11441
|
stale = true;
|
|
11430
11442
|
return;
|
|
11431
11443
|
}
|
|
11432
|
-
await
|
|
11444
|
+
await record2.update((r) => {
|
|
11433
11445
|
r._setRaw("topics_user_managed", true);
|
|
11434
11446
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
11435
11447
|
});
|
|
@@ -11453,25 +11465,25 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
11453
11465
|
);
|
|
11454
11466
|
});
|
|
11455
11467
|
if (stale) return null;
|
|
11456
|
-
return vaultMemoryToStored(
|
|
11468
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11457
11469
|
}
|
|
11458
11470
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
11459
|
-
let
|
|
11471
|
+
let record2;
|
|
11460
11472
|
try {
|
|
11461
|
-
|
|
11473
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
11462
11474
|
} catch {
|
|
11463
11475
|
return false;
|
|
11464
11476
|
}
|
|
11465
|
-
if (
|
|
11466
|
-
const originalUpdatedAt =
|
|
11477
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11478
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11467
11479
|
let cleared = false;
|
|
11468
11480
|
await ctx.database.write(async () => {
|
|
11469
|
-
if (options?.unlessTopicsRecorded && parseTopics(
|
|
11481
|
+
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
11470
11482
|
cleared = true;
|
|
11471
|
-
await
|
|
11483
|
+
await record2.update((r) => {
|
|
11472
11484
|
r._setRaw("topics_user_managed", false);
|
|
11473
11485
|
r._setRaw("topics_extracted_version", null);
|
|
11474
|
-
if (
|
|
11486
|
+
if (record2.topicsExtractedAt === null) {
|
|
11475
11487
|
r._setRaw("topics_extracted_at", originalUpdatedAt);
|
|
11476
11488
|
}
|
|
11477
11489
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -11480,22 +11492,22 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
11480
11492
|
return cleared;
|
|
11481
11493
|
}
|
|
11482
11494
|
async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
11483
|
-
let
|
|
11495
|
+
let record2;
|
|
11484
11496
|
try {
|
|
11485
|
-
|
|
11497
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11486
11498
|
} catch {
|
|
11487
11499
|
return null;
|
|
11488
11500
|
}
|
|
11489
|
-
if (
|
|
11501
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
11490
11502
|
let stale = false;
|
|
11491
11503
|
await ctx.database.write(async () => {
|
|
11492
|
-
if (
|
|
11504
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11493
11505
|
stale = true;
|
|
11494
11506
|
return;
|
|
11495
11507
|
}
|
|
11496
|
-
const currentUpdatedAt =
|
|
11497
|
-
const currentPublishedAt =
|
|
11498
|
-
await
|
|
11508
|
+
const currentUpdatedAt = record2.updatedAt.getTime();
|
|
11509
|
+
const currentPublishedAt = record2.publishedAt ?? null;
|
|
11510
|
+
await record2.update((r) => {
|
|
11499
11511
|
r._setRaw("visibility", opts.visibility);
|
|
11500
11512
|
if (opts.visibility === "private") {
|
|
11501
11513
|
r._setRaw("published_at", null);
|
|
@@ -11509,19 +11521,19 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
11509
11521
|
});
|
|
11510
11522
|
});
|
|
11511
11523
|
if (stale) return null;
|
|
11512
|
-
return vaultMemoryToStored(
|
|
11524
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11513
11525
|
}
|
|
11514
11526
|
async function deleteVaultMemoryOp(ctx, id) {
|
|
11515
11527
|
try {
|
|
11516
|
-
const
|
|
11517
|
-
if (
|
|
11528
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11529
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11518
11530
|
let stale = false;
|
|
11519
11531
|
await ctx.database.write(async () => {
|
|
11520
|
-
if (
|
|
11532
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11521
11533
|
stale = true;
|
|
11522
11534
|
return;
|
|
11523
11535
|
}
|
|
11524
|
-
await
|
|
11536
|
+
await record2.update((r) => {
|
|
11525
11537
|
r._setRaw("is_deleted", true);
|
|
11526
11538
|
});
|
|
11527
11539
|
});
|
|
@@ -11540,8 +11552,8 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
11540
11552
|
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
11541
11553
|
if (id === supersededById) return false;
|
|
11542
11554
|
try {
|
|
11543
|
-
const
|
|
11544
|
-
if (
|
|
11555
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11556
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11545
11557
|
let successor;
|
|
11546
11558
|
try {
|
|
11547
11559
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -11555,7 +11567,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
11555
11567
|
await ctx.database.write(async () => {
|
|
11556
11568
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11557
11569
|
throw new Error("Memory source is no longer eligible");
|
|
11558
|
-
if (
|
|
11570
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
11559
11571
|
stale = true;
|
|
11560
11572
|
return;
|
|
11561
11573
|
}
|
|
@@ -11563,7 +11575,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
11563
11575
|
stale = true;
|
|
11564
11576
|
return;
|
|
11565
11577
|
}
|
|
11566
|
-
await
|
|
11578
|
+
await record2.update((r) => {
|
|
11567
11579
|
r._setRaw("superseded_by", supersededById);
|
|
11568
11580
|
r._setRaw("superseded_at", Date.now());
|
|
11569
11581
|
});
|
|
@@ -11582,7 +11594,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
11582
11594
|
const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
|
|
11583
11595
|
return mapInBatches(
|
|
11584
11596
|
results,
|
|
11585
|
-
(
|
|
11597
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
11586
11598
|
);
|
|
11587
11599
|
}
|
|
11588
11600
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
@@ -11724,17 +11736,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
11724
11736
|
}
|
|
11725
11737
|
}
|
|
11726
11738
|
const eligible = records.filter(
|
|
11727
|
-
(
|
|
11739
|
+
(record2) => !record2.isDeleted && isOwnedByCtxUser(ctx, record2) && !record2.topicsUserManaged
|
|
11728
11740
|
);
|
|
11729
|
-
const prepared = eligible.map((
|
|
11730
|
-
const originalUpdatedAt =
|
|
11731
|
-
return
|
|
11741
|
+
const prepared = eligible.map((record2) => {
|
|
11742
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11743
|
+
return record2.prepareUpdate((r) => {
|
|
11732
11744
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
11733
11745
|
r._setRaw("topics_extracted_version", version);
|
|
11734
11746
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
11735
11747
|
});
|
|
11736
11748
|
});
|
|
11737
|
-
for (const
|
|
11749
|
+
for (const record2 of eligible) stamped.push(record2.id);
|
|
11738
11750
|
if (prepared.length > 0) await ctx.database.batch(...prepared);
|
|
11739
11751
|
});
|
|
11740
11752
|
}
|
|
@@ -11749,14 +11761,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
11749
11761
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
11750
11762
|
try {
|
|
11751
11763
|
await ctx.database.write(async (writer) => {
|
|
11752
|
-
let
|
|
11764
|
+
let record2;
|
|
11753
11765
|
try {
|
|
11754
|
-
|
|
11766
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11755
11767
|
} catch {
|
|
11756
11768
|
return;
|
|
11757
11769
|
}
|
|
11758
|
-
if (
|
|
11759
|
-
const topics = parseTopics(
|
|
11770
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
11771
|
+
const topics = parseTopics(record2.topics);
|
|
11760
11772
|
if (topics === null) return;
|
|
11761
11773
|
await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics));
|
|
11762
11774
|
relinked.push(id);
|
|
@@ -11781,20 +11793,20 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
11781
11793
|
await ctx.database.write(async () => {
|
|
11782
11794
|
const writes = [];
|
|
11783
11795
|
for (const id of chunkIds) {
|
|
11784
|
-
let
|
|
11796
|
+
let record2;
|
|
11785
11797
|
try {
|
|
11786
|
-
|
|
11798
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11787
11799
|
} catch {
|
|
11788
11800
|
continue;
|
|
11789
11801
|
}
|
|
11790
|
-
if (
|
|
11791
|
-
if (parseTopics(
|
|
11802
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) continue;
|
|
11803
|
+
if (parseTopics(record2.topics) !== null) continue;
|
|
11792
11804
|
const links = await entityCtx.memoryEntityCollection.query(Q5.where("memory_id", id)).unsafeFetchRaw();
|
|
11793
11805
|
const entityIds = links.map((l) => String(l.entity_id));
|
|
11794
11806
|
if (entityIds.length === 0) continue;
|
|
11795
11807
|
const entities = await entityCtx.entityCollection.query(Q5.where("id", Q5.oneOf(entityIds))).fetch();
|
|
11796
11808
|
if (entities.length === 0) continue;
|
|
11797
|
-
const source =
|
|
11809
|
+
const source = record2.topicsUserManaged ? "user" : "auto";
|
|
11798
11810
|
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
11799
11811
|
if (write) writes.push(write);
|
|
11800
11812
|
}
|
|
@@ -11812,7 +11824,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
11812
11824
|
if (records.length === 0) return 0;
|
|
11813
11825
|
await ctx.database.write(async () => {
|
|
11814
11826
|
const prepared = records.map(
|
|
11815
|
-
(
|
|
11827
|
+
(record2) => record2.prepareUpdate((r) => {
|
|
11816
11828
|
r._setRaw("is_deleted", true);
|
|
11817
11829
|
})
|
|
11818
11830
|
);
|
|
@@ -11857,20 +11869,20 @@ async function getDecayCandidatesRawOp(ctx) {
|
|
|
11857
11869
|
}
|
|
11858
11870
|
async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
11859
11871
|
try {
|
|
11860
|
-
const
|
|
11861
|
-
if (
|
|
11872
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11873
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11862
11874
|
let stale = false;
|
|
11863
11875
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
11864
11876
|
await ctx.database.write(async () => {
|
|
11865
|
-
if (
|
|
11877
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
11866
11878
|
stale = true;
|
|
11867
11879
|
return;
|
|
11868
11880
|
}
|
|
11869
|
-
if (opts?.expectedUpdatedAt !== void 0 &&
|
|
11881
|
+
if (opts?.expectedUpdatedAt !== void 0 && record2.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record2.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
|
|
11870
11882
|
stale = true;
|
|
11871
11883
|
return;
|
|
11872
11884
|
}
|
|
11873
|
-
await
|
|
11885
|
+
await record2.update((r) => {
|
|
11874
11886
|
r._setRaw("archived_at", archivedAtValue);
|
|
11875
11887
|
});
|
|
11876
11888
|
});
|
|
@@ -11881,15 +11893,15 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
11881
11893
|
}
|
|
11882
11894
|
async function restoreVaultMemoryOp(ctx, id) {
|
|
11883
11895
|
try {
|
|
11884
|
-
const
|
|
11885
|
-
if (
|
|
11896
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11897
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11886
11898
|
let stale = false;
|
|
11887
11899
|
await ctx.database.write(async () => {
|
|
11888
|
-
if (
|
|
11900
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
11889
11901
|
stale = true;
|
|
11890
11902
|
return;
|
|
11891
11903
|
}
|
|
11892
|
-
await
|
|
11904
|
+
await record2.update((r) => {
|
|
11893
11905
|
r._setRaw("archived_at", null);
|
|
11894
11906
|
});
|
|
11895
11907
|
});
|
|
@@ -11900,17 +11912,17 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
11900
11912
|
}
|
|
11901
11913
|
async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
11902
11914
|
try {
|
|
11903
|
-
const
|
|
11904
|
-
if (
|
|
11915
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11916
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11905
11917
|
const now = opts.now ?? Date.now();
|
|
11906
11918
|
let stale = false;
|
|
11907
11919
|
await ctx.database.write(async () => {
|
|
11908
|
-
const archivedAt =
|
|
11909
|
-
if (
|
|
11920
|
+
const archivedAt = record2.archivedAt;
|
|
11921
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
11910
11922
|
stale = true;
|
|
11911
11923
|
return;
|
|
11912
11924
|
}
|
|
11913
|
-
await
|
|
11925
|
+
await record2.update((r) => {
|
|
11914
11926
|
r._setRaw("is_deleted", true);
|
|
11915
11927
|
});
|
|
11916
11928
|
});
|
|
@@ -11928,14 +11940,14 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
11928
11940
|
}
|
|
11929
11941
|
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
11930
11942
|
try {
|
|
11931
|
-
const
|
|
11932
|
-
if (
|
|
11933
|
-
const readUpdatedAt =
|
|
11934
|
-
const readStoredContent =
|
|
11943
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11944
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11945
|
+
const readUpdatedAt = record2.updatedAt.getTime();
|
|
11946
|
+
const readStoredContent = record2._getRaw("content");
|
|
11935
11947
|
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
11936
11948
|
if (expected?.content !== void 0) {
|
|
11937
11949
|
const current = await vaultMemoryToStored(
|
|
11938
|
-
|
|
11950
|
+
record2,
|
|
11939
11951
|
ctx.walletAddress,
|
|
11940
11952
|
ctx.signMessage,
|
|
11941
11953
|
ctx.embeddedWalletSigner
|
|
@@ -11944,11 +11956,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
11944
11956
|
}
|
|
11945
11957
|
let written = false;
|
|
11946
11958
|
await ctx.database.write(async () => {
|
|
11947
|
-
if (
|
|
11948
|
-
const originalUpdatedAt =
|
|
11949
|
-
if (originalUpdatedAt !== readUpdatedAt ||
|
|
11959
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
11960
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
11961
|
+
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
11950
11962
|
return;
|
|
11951
|
-
await
|
|
11963
|
+
await record2.update((r) => {
|
|
11952
11964
|
r._setRaw("embedding", embedding);
|
|
11953
11965
|
r._setRaw("embedding_model", embeddingModel);
|
|
11954
11966
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -11963,8 +11975,8 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
11963
11975
|
function normalizeForDedupe(content) {
|
|
11964
11976
|
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
11965
11977
|
}
|
|
11966
|
-
async function findQuarantinedDuplicateOp(ctx, content,
|
|
11967
|
-
const wanted = [...new Set(
|
|
11978
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds2, where) {
|
|
11979
|
+
const wanted = [...new Set(sourceIds2)].sort().join("\0");
|
|
11968
11980
|
const target = normalizeForDedupe(content);
|
|
11969
11981
|
const rows = await ctx.vaultMemoryCollection.query(
|
|
11970
11982
|
Q5.where("trust_tier", "quarantined"),
|
|
@@ -11983,13 +11995,13 @@ async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
|
11983
11995
|
if (!Array.isArray(ids)) continue;
|
|
11984
11996
|
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
11985
11997
|
if (key !== wanted) continue;
|
|
11986
|
-
const
|
|
11998
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
11987
11999
|
raw,
|
|
11988
12000
|
ctx.walletAddress,
|
|
11989
12001
|
ctx.signMessage,
|
|
11990
12002
|
ctx.embeddedWalletSigner
|
|
11991
12003
|
);
|
|
11992
|
-
if (normalizeForDedupe(
|
|
12004
|
+
if (normalizeForDedupe(stored2.content) === target) return stored2.uniqueId;
|
|
11993
12005
|
}
|
|
11994
12006
|
return null;
|
|
11995
12007
|
}
|
|
@@ -12098,25 +12110,25 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
12098
12110
|
inserted = writable.length;
|
|
12099
12111
|
if (writable.length === 0) return;
|
|
12100
12112
|
const prepared = writable.map(
|
|
12101
|
-
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12113
|
+
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record2) => {
|
|
12114
|
+
record2._raw.id = row.memoryId;
|
|
12115
|
+
record2._setRaw("content", content);
|
|
12116
|
+
record2._setRaw("scope", "shared");
|
|
12117
|
+
record2._setRaw("folder_id", null);
|
|
12118
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
12119
|
+
record2._setRaw("is_deleted", false);
|
|
12120
|
+
record2._setRaw("proof_count", 1);
|
|
12121
|
+
record2._setRaw("source", SOURCE_PHOTO);
|
|
12122
|
+
record2._setRaw(
|
|
12111
12123
|
"media",
|
|
12112
12124
|
row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
|
|
12113
12125
|
);
|
|
12114
|
-
|
|
12115
|
-
|
|
12126
|
+
record2._setRaw("visibility", "public");
|
|
12127
|
+
record2._setRaw("published_at", now);
|
|
12116
12128
|
if (row.eventTime) {
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12129
|
+
record2._setRaw("event_time_start", row.eventTime.start ?? null);
|
|
12130
|
+
record2._setRaw("event_time_end", row.eventTime.end ?? null);
|
|
12131
|
+
record2._setRaw("event_time_kind", row.eventTime.kind ?? null);
|
|
12120
12132
|
}
|
|
12121
12133
|
})
|
|
12122
12134
|
);
|
|
@@ -12480,11 +12492,11 @@ function folderToStored(folder) {
|
|
|
12480
12492
|
}
|
|
12481
12493
|
async function createVaultFolderOp(ctx, opts) {
|
|
12482
12494
|
const created = await ctx.database.write(async () => {
|
|
12483
|
-
return ctx.vaultFolderCollection.create((
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12495
|
+
return ctx.vaultFolderCollection.create((record2) => {
|
|
12496
|
+
record2._setRaw("name", opts.name);
|
|
12497
|
+
record2._setRaw("scope", opts.scope ?? "private");
|
|
12498
|
+
record2._setRaw("is_system", opts.isSystem ?? false);
|
|
12499
|
+
record2._setRaw("is_deleted", false);
|
|
12488
12500
|
});
|
|
12489
12501
|
});
|
|
12490
12502
|
return folderToStored(created);
|
|
@@ -12495,14 +12507,14 @@ async function getAllVaultFoldersOp(ctx) {
|
|
|
12495
12507
|
}
|
|
12496
12508
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
12497
12509
|
try {
|
|
12498
|
-
const
|
|
12499
|
-
if (
|
|
12500
|
-
const scopeChanged = opts.scope !== void 0 && opts.scope !==
|
|
12510
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
12511
|
+
if (record2.isDeleted) return null;
|
|
12512
|
+
const scopeChanged = opts.scope !== void 0 && opts.scope !== record2.scope;
|
|
12501
12513
|
const updated = await ctx.database.write(async () => {
|
|
12502
12514
|
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q6.where("folder_id", id), Q6.where("is_deleted", false)).fetch() : [];
|
|
12503
12515
|
const updates = [];
|
|
12504
12516
|
updates.push(
|
|
12505
|
-
|
|
12517
|
+
record2.prepareUpdate((r) => {
|
|
12506
12518
|
if (opts.name !== void 0) r._setRaw("name", opts.name);
|
|
12507
12519
|
if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
|
|
12508
12520
|
})
|
|
@@ -12524,8 +12536,8 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
12524
12536
|
}
|
|
12525
12537
|
async function deleteVaultFolderOp(ctx, id) {
|
|
12526
12538
|
try {
|
|
12527
|
-
const
|
|
12528
|
-
if (
|
|
12539
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
12540
|
+
if (record2.isDeleted) return false;
|
|
12529
12541
|
await ctx.database.write(async () => {
|
|
12530
12542
|
const memories = await ctx.vaultMemoryCollection.query(Q6.where("folder_id", id), Q6.where("is_deleted", false)).fetch();
|
|
12531
12543
|
const preparedMemories = memories.map(
|
|
@@ -12534,7 +12546,7 @@ async function deleteVaultFolderOp(ctx, id) {
|
|
|
12534
12546
|
r._setRaw("scope", "private");
|
|
12535
12547
|
})
|
|
12536
12548
|
);
|
|
12537
|
-
const preparedFolder =
|
|
12549
|
+
const preparedFolder = record2.prepareUpdate((r) => {
|
|
12538
12550
|
r._setRaw("is_deleted", true);
|
|
12539
12551
|
});
|
|
12540
12552
|
await ctx.database.batch(...preparedMemories, preparedFolder);
|
|
@@ -12580,11 +12592,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
12580
12592
|
}
|
|
12581
12593
|
async function updateVaultFolderContextOp(ctx, id, context) {
|
|
12582
12594
|
try {
|
|
12583
|
-
const
|
|
12584
|
-
if (
|
|
12595
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
12596
|
+
if (record2.isDeleted) return null;
|
|
12585
12597
|
const updated = await ctx.database.write(async () => {
|
|
12586
12598
|
await ctx.database.batch(
|
|
12587
|
-
|
|
12599
|
+
record2.prepareUpdate((r) => {
|
|
12588
12600
|
r._setRaw("context", context);
|
|
12589
12601
|
})
|
|
12590
12602
|
);
|
|
@@ -14641,7 +14653,7 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
14641
14653
|
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
14642
14654
|
let subEmbeddings;
|
|
14643
14655
|
try {
|
|
14644
|
-
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
14656
|
+
subEmbeddings = prepared.facetEmbeddings ?? await generateEmbeddings(facetQueries, embeddingOptions);
|
|
14645
14657
|
} catch (err) {
|
|
14646
14658
|
getLogger().warn(
|
|
14647
14659
|
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
@@ -14826,6 +14838,35 @@ var DEFAULT_SCOPE = "private";
|
|
|
14826
14838
|
var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
|
|
14827
14839
|
var DEFAULT_CONSOLIDATE_TOP_K = 20;
|
|
14828
14840
|
async function retain(content, ctx, options = {}) {
|
|
14841
|
+
return retainWithPersistence(
|
|
14842
|
+
content,
|
|
14843
|
+
{
|
|
14844
|
+
embeddingOptions: ctx.embeddingOptions,
|
|
14845
|
+
vaultCache: ctx.vaultCache,
|
|
14846
|
+
persistence: {
|
|
14847
|
+
prepare: (query, searchOptions) => prepareVaultCandidates(
|
|
14848
|
+
query,
|
|
14849
|
+
ctx.vaultCtx,
|
|
14850
|
+
ctx.embeddingOptions,
|
|
14851
|
+
ctx.vaultCache,
|
|
14852
|
+
searchOptions
|
|
14853
|
+
),
|
|
14854
|
+
get: (id) => getVaultMemoryOp(ctx.vaultCtx, id),
|
|
14855
|
+
tombstones: (_embedding, _model, scope, folderId) => getAllVaultMemoriesOp(ctx.vaultCtx, {
|
|
14856
|
+
includeDeleted: true,
|
|
14857
|
+
scopes: [scope],
|
|
14858
|
+
...folderId !== void 0 && { folderId }
|
|
14859
|
+
}),
|
|
14860
|
+
create: (input) => createVaultMemoryOp(ctx.vaultCtx, input),
|
|
14861
|
+
update: (id, patch) => updateVaultMemoryOp(ctx.vaultCtx, id, patch),
|
|
14862
|
+
supersede: (id, successor) => supersedeVaultMemoryOp(ctx.vaultCtx, id, successor),
|
|
14863
|
+
createSuperseding: (input, target) => createSupersedingMemoryOp(ctx.vaultCtx, input, target)
|
|
14864
|
+
}
|
|
14865
|
+
},
|
|
14866
|
+
options
|
|
14867
|
+
);
|
|
14868
|
+
}
|
|
14869
|
+
async function retainWithPersistence(content, ctx, options = {}) {
|
|
14829
14870
|
const trimmed = content.trim();
|
|
14830
14871
|
if (trimmed.length === 0) {
|
|
14831
14872
|
throw new Error("retain: content cannot be empty");
|
|
@@ -14838,19 +14879,13 @@ async function retain(content, ctx, options = {}) {
|
|
|
14838
14879
|
let supersedeContent;
|
|
14839
14880
|
let prepared;
|
|
14840
14881
|
if (enableAutoMerge) {
|
|
14841
|
-
prepared = await
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
{
|
|
14847
|
-
|
|
14848
|
-
useFusion: false,
|
|
14849
|
-
scopes: [resolvedScope],
|
|
14850
|
-
includeArchived: true,
|
|
14851
|
-
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
14852
|
-
}
|
|
14853
|
-
);
|
|
14882
|
+
prepared = await ctx.persistence.prepare(trimmed, {
|
|
14883
|
+
limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
|
|
14884
|
+
useFusion: false,
|
|
14885
|
+
scopes: [resolvedScope],
|
|
14886
|
+
includeArchived: true,
|
|
14887
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
14888
|
+
});
|
|
14854
14889
|
if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
|
|
14855
14890
|
throw new Error(
|
|
14856
14891
|
"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 +14916,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
14881
14916
|
);
|
|
14882
14917
|
if (matches.length > 0) {
|
|
14883
14918
|
const targetId = matches[0].uniqueId;
|
|
14884
|
-
const existing = await
|
|
14919
|
+
const existing = await ctx.persistence.get(targetId);
|
|
14885
14920
|
if (existing && !existing.supersededBy) {
|
|
14886
14921
|
const mergedSourceIds = unionStrings(
|
|
14887
14922
|
existing.sourceChunkIds ?? [],
|
|
@@ -14890,7 +14925,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
14890
14925
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
14891
14926
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
14892
14927
|
const resurrect = resurrectFields(existing);
|
|
14893
|
-
const updated = await
|
|
14928
|
+
const updated = await ctx.persistence.update(targetId, {
|
|
14894
14929
|
content: existing.content,
|
|
14895
14930
|
proofCountIncrement: 1,
|
|
14896
14931
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -14917,7 +14952,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
14917
14952
|
}
|
|
14918
14953
|
const contentToWrite = supersedeContent ?? trimmed;
|
|
14919
14954
|
const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
|
|
14920
|
-
const
|
|
14955
|
+
const generatedEmbedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
14956
|
+
const embedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
14921
14957
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
14922
14958
|
if (options.respectTombstones) {
|
|
14923
14959
|
const tombstone = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -14957,8 +14993,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
14957
14993
|
};
|
|
14958
14994
|
if (supersedeTargetIds.length > 0) {
|
|
14959
14995
|
const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
|
|
14960
|
-
const { created: created2, retired } = await
|
|
14961
|
-
ctx.vaultCtx,
|
|
14996
|
+
const { created: created2, retired } = await ctx.persistence.createSuperseding(
|
|
14962
14997
|
createOpts,
|
|
14963
14998
|
primaryTargetId
|
|
14964
14999
|
);
|
|
@@ -14974,11 +15009,11 @@ async function retain(content, ctx, options = {}) {
|
|
|
14974
15009
|
for (const staleId of restTargetIds) {
|
|
14975
15010
|
let ok = false;
|
|
14976
15011
|
try {
|
|
14977
|
-
ok = await
|
|
15012
|
+
ok = await ctx.persistence.supersede(staleId, created2.uniqueId) === true;
|
|
14978
15013
|
} catch {
|
|
14979
15014
|
}
|
|
14980
15015
|
if (ok) continue;
|
|
14981
|
-
const stillLive = await
|
|
15016
|
+
const stillLive = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(staleId) : ctx.persistence.get(staleId)).catch(() => null);
|
|
14982
15017
|
if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
|
|
14983
15018
|
}
|
|
14984
15019
|
if (liveLeftovers.length > 0) {
|
|
@@ -15005,7 +15040,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
15005
15040
|
`supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
|
|
15006
15041
|
);
|
|
15007
15042
|
}
|
|
15008
|
-
const created = await
|
|
15043
|
+
const created = await ctx.persistence.create(createOpts);
|
|
15009
15044
|
cacheRowVector(
|
|
15010
15045
|
ctx.vaultCache,
|
|
15011
15046
|
created.uniqueId,
|
|
@@ -15024,11 +15059,7 @@ function unionStrings(a, b) {
|
|
|
15024
15059
|
return [.../* @__PURE__ */ new Set([...a, ...b])];
|
|
15025
15060
|
}
|
|
15026
15061
|
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
|
-
});
|
|
15062
|
+
const rows = await ctx.persistence.tombstones(embedding, embeddingModel, scope, opts.folderId);
|
|
15032
15063
|
let bestId = null;
|
|
15033
15064
|
let bestSim = opts.threshold;
|
|
15034
15065
|
for (const row of rows) {
|
|
@@ -15095,7 +15126,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15095
15126
|
if (requestedIds.length === 0) return null;
|
|
15096
15127
|
const valid = [];
|
|
15097
15128
|
for (const id of requestedIds) {
|
|
15098
|
-
const existing = await
|
|
15129
|
+
const existing = await ctx.persistence.get(id);
|
|
15099
15130
|
if (existing && !existing.supersededBy) valid.push(id);
|
|
15100
15131
|
}
|
|
15101
15132
|
if (valid.length === 0) {
|
|
@@ -15107,7 +15138,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15107
15138
|
return { supersede: valid, content: decision.content };
|
|
15108
15139
|
}
|
|
15109
15140
|
if (decision.action === "noop" && decision.targetId) {
|
|
15110
|
-
const existing = await
|
|
15141
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
15111
15142
|
if (!existing || existing.supersededBy) {
|
|
15112
15143
|
return abandonToRace(
|
|
15113
15144
|
options,
|
|
@@ -15121,7 +15152,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15121
15152
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
15122
15153
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
15123
15154
|
const resurrect = resurrectFields(existing);
|
|
15124
|
-
const updated = await
|
|
15155
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
15125
15156
|
content: existing.content,
|
|
15126
15157
|
proofCountIncrement: 1,
|
|
15127
15158
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -15149,7 +15180,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15149
15180
|
};
|
|
15150
15181
|
}
|
|
15151
15182
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
15152
|
-
const existing = await
|
|
15183
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
15153
15184
|
if (!existing || existing.supersededBy) {
|
|
15154
15185
|
return abandonToRace(
|
|
15155
15186
|
options,
|
|
@@ -15160,12 +15191,13 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15160
15191
|
existing.sourceChunkIds ?? [],
|
|
15161
15192
|
options.sourceChunkIds ?? []
|
|
15162
15193
|
);
|
|
15163
|
-
const
|
|
15194
|
+
const generatedEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
|
|
15195
|
+
const newEmbedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
15164
15196
|
const consolidatedModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
15165
15197
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
15166
15198
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
15167
15199
|
const resurrect = resurrectFields(existing);
|
|
15168
|
-
const updated = await
|
|
15200
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
15169
15201
|
content: decision.content,
|
|
15170
15202
|
proofCountIncrement: 1,
|
|
15171
15203
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -15209,7 +15241,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15209
15241
|
return null;
|
|
15210
15242
|
}
|
|
15211
15243
|
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
15212
|
-
const stillExists = await
|
|
15244
|
+
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
15213
15245
|
if (stillExists) {
|
|
15214
15246
|
throw new Error(`retain: merge into memory ${targetId} failed to persist`);
|
|
15215
15247
|
}
|
|
@@ -15724,9 +15756,9 @@ function createAutoExtractor(options) {
|
|
|
15724
15756
|
const persistCursor = (conversationId, messages, advancedToId, contiguous) => {
|
|
15725
15757
|
if (!cursorStore || conversationId === void 0 || !contiguous) return;
|
|
15726
15758
|
try {
|
|
15727
|
-
const
|
|
15728
|
-
if (
|
|
15729
|
-
const storedIdx = messages.findIndex((m) => m.id ===
|
|
15759
|
+
const stored2 = cursorStore.get(conversationId);
|
|
15760
|
+
if (stored2 && stored2 !== advancedToId) {
|
|
15761
|
+
const storedIdx = messages.findIndex((m) => m.id === stored2);
|
|
15730
15762
|
const newIdx = messages.findIndex((m) => m.id === advancedToId);
|
|
15731
15763
|
if (storedIdx !== -1 && newIdx !== -1 && storedIdx >= newIdx) return;
|
|
15732
15764
|
}
|
|
@@ -16695,7 +16727,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
16695
16727
|
if (graphLaneFailed) degraded.push("graph-lane-failed");
|
|
16696
16728
|
if (temporalLaneFailed) degraded.push("temporal-lane-failed");
|
|
16697
16729
|
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;
|
|
16730
|
+
const laneRan = types.includes("fact") && (!!ctx.factSource || !!ctx.vaultCtx && !!ctx.vaultCache) || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
|
|
16699
16731
|
const scores = admitted.map((m) => m.score);
|
|
16700
16732
|
const minScoreApplied = factResults.length > 0 ? factFloor : chunkResults.length > 0 ? chunkFloor : factFloor >= 0 ? factFloor : chunkFloor;
|
|
16701
16733
|
const diagnostics = {
|
|
@@ -16737,7 +16769,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
16737
16769
|
return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
|
|
16738
16770
|
}
|
|
16739
16771
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
16740
|
-
const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
|
|
16772
|
+
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
16741
16773
|
const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
|
|
16742
16774
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
16743
16775
|
const prepStart = nowMs2();
|
|
@@ -16767,7 +16799,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
16767
16799
|
safeLane(
|
|
16768
16800
|
"graph",
|
|
16769
16801
|
() => graphLaneFailed = true,
|
|
16770
|
-
() => buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
16802
|
+
() => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
16771
16803
|
...options.maxHops !== void 0 && { maxHops: options.maxHops },
|
|
16772
16804
|
...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
|
|
16773
16805
|
...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
|
|
@@ -16778,13 +16810,13 @@ async function recall(query, ctx, options = {}) {
|
|
|
16778
16810
|
wantsTemporal ? safeLane(
|
|
16779
16811
|
"temporal",
|
|
16780
16812
|
() => temporalLaneFailed = true,
|
|
16781
|
-
() => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
16813
|
+
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
16782
16814
|
) : Promise.resolve([])
|
|
16783
16815
|
]);
|
|
16784
16816
|
prepMs = nowMs2() - prepStart;
|
|
16785
16817
|
graphLaneCount = entityRanking.length;
|
|
16786
16818
|
temporalLaneCount = temporalRanking.length;
|
|
16787
|
-
if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
|
|
16819
|
+
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
16788
16820
|
const factStart = nowMs2();
|
|
16789
16821
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
16790
16822
|
factFloor = vaultMinScore;
|
|
@@ -16800,50 +16832,50 @@ async function recall(query, ctx, options = {}) {
|
|
|
16800
16832
|
rankedOnCosine: factRankedOnCosine,
|
|
16801
16833
|
decryptLast: factDecryptLast,
|
|
16802
16834
|
rowsDecrypted: factRowsDecrypted
|
|
16803
|
-
} = await searchVaultMemoriesWithSize(
|
|
16804
|
-
|
|
16835
|
+
} = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
|
|
16836
|
+
searchQuery,
|
|
16805
16837
|
ctx.vaultCtx,
|
|
16806
16838
|
ctx.embeddingOptions,
|
|
16807
16839
|
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
|
-
);
|
|
16840
|
+
searchOptions
|
|
16841
|
+
)))(query, {
|
|
16842
|
+
limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
|
|
16843
|
+
minSimilarity: vaultMinScore,
|
|
16844
|
+
useFusion: true,
|
|
16845
|
+
rerank: flags.rerank,
|
|
16846
|
+
...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
|
|
16847
|
+
...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
|
|
16848
|
+
...options.rerankLoadTimeoutMs !== void 0 && {
|
|
16849
|
+
rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
|
|
16850
|
+
},
|
|
16851
|
+
...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
|
|
16852
|
+
...options.recency && { recency: options.recency },
|
|
16853
|
+
...options.mmr !== void 0 && { mmr: options.mmr },
|
|
16854
|
+
...options.supersessionBoost !== void 0 && {
|
|
16855
|
+
supersessionBoost: options.supersessionBoost
|
|
16856
|
+
},
|
|
16857
|
+
...options.supersessionWindow !== void 0 && {
|
|
16858
|
+
supersessionWindow: options.supersessionWindow
|
|
16859
|
+
},
|
|
16860
|
+
...options.proofCountAlpha !== void 0 && {
|
|
16861
|
+
proofCountAlpha: options.proofCountAlpha
|
|
16862
|
+
},
|
|
16863
|
+
...options.bm25AdmissionDivisor !== void 0 && {
|
|
16864
|
+
bm25AdmissionDivisor: options.bm25AdmissionDivisor
|
|
16865
|
+
},
|
|
16866
|
+
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
16867
|
+
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
16868
|
+
...subQueries && { subQueries },
|
|
16869
|
+
...options.scopes && { scopes: options.scopes },
|
|
16870
|
+
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
16871
|
+
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
16872
|
+
...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
|
|
16873
|
+
...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
|
|
16874
|
+
...entityRanking.length > 0 && { entityRanking },
|
|
16875
|
+
...temporalRanking.length > 0 && { temporalRanking },
|
|
16876
|
+
...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
|
|
16877
|
+
queryEmbedTotalTimeoutMs
|
|
16878
|
+
});
|
|
16847
16879
|
factResults.push(
|
|
16848
16880
|
...dedupeBy(
|
|
16849
16881
|
results,
|
|
@@ -17648,26 +17680,26 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
|
17648
17680
|
};
|
|
17649
17681
|
const inputs = [];
|
|
17650
17682
|
for (const id of new Set(memoryIds)) {
|
|
17651
|
-
let
|
|
17683
|
+
let record2;
|
|
17652
17684
|
try {
|
|
17653
|
-
|
|
17685
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
17654
17686
|
} catch (err) {
|
|
17655
17687
|
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
17656
17688
|
skip(id, "not-found");
|
|
17657
17689
|
continue;
|
|
17658
17690
|
}
|
|
17659
|
-
if (
|
|
17691
|
+
if (record2.isDeleted || ctx.userId !== void 0 && record2.userId !== ctx.userId || record2.topicsUserManaged) {
|
|
17660
17692
|
skip(id, "excluded");
|
|
17661
17693
|
continue;
|
|
17662
17694
|
}
|
|
17663
17695
|
try {
|
|
17664
|
-
const
|
|
17665
|
-
|
|
17696
|
+
const stored2 = await vaultMemoryToStored(
|
|
17697
|
+
record2,
|
|
17666
17698
|
ctx.walletAddress,
|
|
17667
17699
|
ctx.signMessage,
|
|
17668
17700
|
ctx.embeddedWalletSigner
|
|
17669
17701
|
);
|
|
17670
|
-
inputs.push({ id, content:
|
|
17702
|
+
inputs.push({ id, content: stored2.content });
|
|
17671
17703
|
} catch (err) {
|
|
17672
17704
|
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
17673
17705
|
skip(id, "unreadable");
|
|
@@ -17852,6 +17884,773 @@ function createLocalMemoryStore(options) {
|
|
|
17852
17884
|
};
|
|
17853
17885
|
}
|
|
17854
17886
|
|
|
17887
|
+
// src/lib/memory/store/remotePersistence.ts
|
|
17888
|
+
var RemoteMemoryError = class extends Error {
|
|
17889
|
+
constructor(message, status, code) {
|
|
17890
|
+
super(message);
|
|
17891
|
+
this.status = status;
|
|
17892
|
+
this.code = code;
|
|
17893
|
+
this.name = "RemoteMemoryError";
|
|
17894
|
+
}
|
|
17895
|
+
};
|
|
17896
|
+
var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
|
|
17897
|
+
var memoryFields = {
|
|
17898
|
+
memory_id: true,
|
|
17899
|
+
content: true,
|
|
17900
|
+
scope: true,
|
|
17901
|
+
created_at: true,
|
|
17902
|
+
updated_at: true,
|
|
17903
|
+
is_deleted: true,
|
|
17904
|
+
embedding: true,
|
|
17905
|
+
embedding_model: true,
|
|
17906
|
+
kind: true,
|
|
17907
|
+
kind_value: true,
|
|
17908
|
+
level: true,
|
|
17909
|
+
folder_id: true,
|
|
17910
|
+
source_chunk_ids: true,
|
|
17911
|
+
proof_count: true,
|
|
17912
|
+
source: true,
|
|
17913
|
+
event_time_start: true,
|
|
17914
|
+
event_time_end: true,
|
|
17915
|
+
event_time_kind: true,
|
|
17916
|
+
topics_user_managed: true,
|
|
17917
|
+
topics: true,
|
|
17918
|
+
topics_updated_at: true,
|
|
17919
|
+
media: true,
|
|
17920
|
+
topics_extracted_at: true,
|
|
17921
|
+
topics_extracted_version: true,
|
|
17922
|
+
superseded_by: true,
|
|
17923
|
+
superseded_at: true,
|
|
17924
|
+
last_observed_at: true,
|
|
17925
|
+
fact_type: true,
|
|
17926
|
+
archived_at: true,
|
|
17927
|
+
trust_tier: true,
|
|
17928
|
+
visibility: true,
|
|
17929
|
+
twin_opt_in: true,
|
|
17930
|
+
published_at: true,
|
|
17931
|
+
geohash: true
|
|
17932
|
+
};
|
|
17933
|
+
var candidateListLimits = [
|
|
17934
|
+
["scopes", 20],
|
|
17935
|
+
["fact_types", 20],
|
|
17936
|
+
["memory_ids", 1e3],
|
|
17937
|
+
["force_ids", 100]
|
|
17938
|
+
];
|
|
17939
|
+
function record(value) {
|
|
17940
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17941
|
+
}
|
|
17942
|
+
function memoryRecord(value) {
|
|
17943
|
+
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))) {
|
|
17944
|
+
throw new Error("Invalid nearby private-memory response");
|
|
17945
|
+
}
|
|
17946
|
+
return value;
|
|
17947
|
+
}
|
|
17948
|
+
async function createRemoteMemoryPersistence(options) {
|
|
17949
|
+
const base = new URL(options.baseUrl);
|
|
17950
|
+
if (!/^https?:$/.test(base.protocol) || base.username || base.password || base.search || base.hash) {
|
|
17951
|
+
throw new Error(
|
|
17952
|
+
"baseUrl must be an HTTP(S) origin or base path without credentials, query or fragment"
|
|
17953
|
+
);
|
|
17954
|
+
}
|
|
17955
|
+
if (!options.keyId || options.keyId.length > 256)
|
|
17956
|
+
throw new Error("A canonical keyId is required");
|
|
17957
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
17958
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
17959
|
+
throw new Error("timeoutMs must be a positive number");
|
|
17960
|
+
const root = base.href.replace(/\/$/, "") + "/api/private-memories";
|
|
17961
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
17962
|
+
const request = async (path, init = {}, signal) => {
|
|
17963
|
+
const controller = new AbortController();
|
|
17964
|
+
let timedOut = false;
|
|
17965
|
+
const timer = setTimeout(() => {
|
|
17966
|
+
timedOut = true;
|
|
17967
|
+
controller.abort();
|
|
17968
|
+
}, timeoutMs);
|
|
17969
|
+
const forwardAbort = () => controller.abort(signal?.reason);
|
|
17970
|
+
if (signal?.aborted) forwardAbort();
|
|
17971
|
+
else signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
17972
|
+
let rejectAborted;
|
|
17973
|
+
const aborted = new Promise((_, reject) => {
|
|
17974
|
+
rejectAborted = () => reject(
|
|
17975
|
+
controller.signal.reason instanceof Error ? controller.signal.reason : new Error("Nearby request aborted")
|
|
17976
|
+
);
|
|
17977
|
+
if (controller.signal.aborted) rejectAborted();
|
|
17978
|
+
else controller.signal.addEventListener("abort", rejectAborted, { once: true });
|
|
17979
|
+
});
|
|
17980
|
+
aborted.catch(() => void 0);
|
|
17981
|
+
try {
|
|
17982
|
+
const token = await Promise.race([options.getToken(), aborted]);
|
|
17983
|
+
if (controller.signal.aborted) await aborted;
|
|
17984
|
+
if (!token) throw new RemoteMemoryError("Authentication required", 401);
|
|
17985
|
+
const response = await fetcher(root + path, {
|
|
17986
|
+
...init,
|
|
17987
|
+
headers: {
|
|
17988
|
+
Authorization: `Bearer ${token}`,
|
|
17989
|
+
...init.body ? { "Content-Type": "application/json" } : {}
|
|
17990
|
+
},
|
|
17991
|
+
redirect: "error",
|
|
17992
|
+
signal: controller.signal
|
|
17993
|
+
});
|
|
17994
|
+
if (!response.ok) {
|
|
17995
|
+
const body = await response.json().catch(() => null);
|
|
17996
|
+
throw new RemoteMemoryError(
|
|
17997
|
+
record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
17998
|
+
response.status,
|
|
17999
|
+
record(body) && typeof body.code === "string" ? body.code : void 0
|
|
18000
|
+
);
|
|
18001
|
+
}
|
|
18002
|
+
return await response.json();
|
|
18003
|
+
} catch (error) {
|
|
18004
|
+
if (timedOut) throw new RemoteMemoryError("Nearby request timed out", 408, "timeout");
|
|
18005
|
+
throw error;
|
|
18006
|
+
} finally {
|
|
18007
|
+
clearTimeout(timer);
|
|
18008
|
+
signal?.removeEventListener("abort", forwardAbort);
|
|
18009
|
+
if (rejectAborted) controller.signal.removeEventListener("abort", rejectAborted);
|
|
18010
|
+
}
|
|
18011
|
+
};
|
|
18012
|
+
const account = await request("/account", {}, options.signal);
|
|
18013
|
+
if (!record(account) || account.state !== "active") {
|
|
18014
|
+
throw new RemoteMemoryError(
|
|
18015
|
+
"Complete and verify migration before using remote memories",
|
|
18016
|
+
409,
|
|
18017
|
+
"memory_not_active"
|
|
18018
|
+
);
|
|
18019
|
+
}
|
|
18020
|
+
if (account.key_id !== options.keyId) {
|
|
18021
|
+
throw new RemoteMemoryError(
|
|
18022
|
+
"The canonical memory key does not match this account",
|
|
18023
|
+
409,
|
|
18024
|
+
"key_mismatch"
|
|
18025
|
+
);
|
|
18026
|
+
}
|
|
18027
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
18028
|
+
const decode = async (value) => {
|
|
18029
|
+
const item = memoryRecord(value);
|
|
18030
|
+
const decrypt = async (ciphertext) => {
|
|
18031
|
+
if (!ciphertextPattern.test(ciphertext))
|
|
18032
|
+
throw new Error("Nearby returned unencrypted memory content");
|
|
18033
|
+
const plaintext = await options.decrypt(ciphertext);
|
|
18034
|
+
if (plaintext === ciphertext) throw new Error("Memory decryption failed");
|
|
18035
|
+
return plaintext;
|
|
18036
|
+
};
|
|
18037
|
+
const decoded = {
|
|
18038
|
+
...item,
|
|
18039
|
+
memory: {
|
|
18040
|
+
...item.memory,
|
|
18041
|
+
content: await decrypt(item.memory.content),
|
|
18042
|
+
...item.memory.kind_value !== void 0 && {
|
|
18043
|
+
kind_value: await decrypt(item.memory.kind_value)
|
|
18044
|
+
}
|
|
18045
|
+
}
|
|
18046
|
+
};
|
|
18047
|
+
return remember(decoded, item);
|
|
18048
|
+
};
|
|
18049
|
+
const remember = (decoded, item) => {
|
|
18050
|
+
snapshots.set(decoded, {
|
|
18051
|
+
id: item.memory.memory_id,
|
|
18052
|
+
version: item.version,
|
|
18053
|
+
content: decoded.memory.content,
|
|
18054
|
+
kindValue: decoded.memory.kind_value,
|
|
18055
|
+
encryptedContent: item.memory.content,
|
|
18056
|
+
encryptedKindValue: item.memory.kind_value
|
|
18057
|
+
});
|
|
18058
|
+
return decoded;
|
|
18059
|
+
};
|
|
18060
|
+
const decodeAll = async (values) => {
|
|
18061
|
+
const records = values.map(memoryRecord);
|
|
18062
|
+
const settled = await Promise.allSettled(records.map(decode));
|
|
18063
|
+
const items = [];
|
|
18064
|
+
const failed = [];
|
|
18065
|
+
settled.forEach((result, i) => {
|
|
18066
|
+
if (result.status === "fulfilled") items.push(result.value);
|
|
18067
|
+
else
|
|
18068
|
+
failed.push({
|
|
18069
|
+
memory_id: records[i].memory.memory_id,
|
|
18070
|
+
version: records[i].version,
|
|
18071
|
+
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
18072
|
+
});
|
|
18073
|
+
});
|
|
18074
|
+
return { items, failed };
|
|
18075
|
+
};
|
|
18076
|
+
const decodeCommitted = async (value, write) => {
|
|
18077
|
+
const item = memoryRecord(value);
|
|
18078
|
+
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)
|
|
18079
|
+
return decode(item);
|
|
18080
|
+
return remember(
|
|
18081
|
+
{
|
|
18082
|
+
...item,
|
|
18083
|
+
memory: {
|
|
18084
|
+
...item.memory,
|
|
18085
|
+
content: write.content,
|
|
18086
|
+
...write.kindValue !== void 0 && { kind_value: write.kindValue }
|
|
18087
|
+
}
|
|
18088
|
+
},
|
|
18089
|
+
item
|
|
18090
|
+
);
|
|
18091
|
+
};
|
|
18092
|
+
const encryptField2 = async (plaintext) => {
|
|
18093
|
+
const ciphertext = await options.encrypt(plaintext);
|
|
18094
|
+
if (ciphertext === plaintext || !ciphertextPattern.test(ciphertext))
|
|
18095
|
+
throw new Error("Field encryption must return SDK ciphertext; refusing to upload plaintext");
|
|
18096
|
+
return ciphertext;
|
|
18097
|
+
};
|
|
18098
|
+
const memoryPath = (id) => {
|
|
18099
|
+
if (!id || id.length > 128) throw new Error("memory_id must be 1\u2013128 characters");
|
|
18100
|
+
return "/memories/" + encodeURIComponent(id);
|
|
18101
|
+
};
|
|
18102
|
+
const prepareWrite = async (memory, expectedVersion, signal) => {
|
|
18103
|
+
const unknown = Object.keys(memory).filter(
|
|
18104
|
+
(key) => !Object.prototype.hasOwnProperty.call(memoryFields, key)
|
|
18105
|
+
);
|
|
18106
|
+
if (unknown.length) {
|
|
18107
|
+
throw new RemoteMemoryError(
|
|
18108
|
+
`Unknown private-memory fields (${unknown.join(", ")}); refusing to forward them`,
|
|
18109
|
+
400,
|
|
18110
|
+
"unknown_field"
|
|
18111
|
+
);
|
|
18112
|
+
}
|
|
18113
|
+
memory = { ...memory, ...memory.embedding && { embedding: [...memory.embedding] } };
|
|
18114
|
+
const path = memoryPath(memory.memory_id);
|
|
18115
|
+
const snapshot = typeof expectedVersion === "number" ? void 0 : snapshots.get(expectedVersion);
|
|
18116
|
+
if (typeof expectedVersion !== "number" && (!snapshot || snapshot.id !== memory.memory_id || snapshot.version !== expectedVersion.version))
|
|
18117
|
+
throw new Error(
|
|
18118
|
+
"Expected snapshot must be an unmodified version from this persistence instance"
|
|
18119
|
+
);
|
|
18120
|
+
expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
|
|
18121
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
18122
|
+
throw new Error("expectedVersion must be a nonnegative integer");
|
|
18123
|
+
const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
|
|
18124
|
+
let existing;
|
|
18125
|
+
if (expectedVersion !== 0 && !snapshot) {
|
|
18126
|
+
try {
|
|
18127
|
+
existing = memoryRecord(await request(path, {}, signal));
|
|
18128
|
+
} catch (error) {
|
|
18129
|
+
if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
|
|
18130
|
+
throw error;
|
|
18131
|
+
}
|
|
18132
|
+
}
|
|
18133
|
+
if (existing && existing.version !== expectedVersion) throw conflict();
|
|
18134
|
+
const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
|
|
18135
|
+
const content = (snapshot?.content ?? decoded?.memory.content) === memory.content ? snapshot?.encryptedContent ?? existing.memory.content : await encryptField2(memory.content);
|
|
18136
|
+
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);
|
|
18137
|
+
return {
|
|
18138
|
+
body: {
|
|
18139
|
+
expected_version: expectedVersion,
|
|
18140
|
+
memory: { ...memory, content, ...kindValue !== void 0 && { kind_value: kindValue } }
|
|
18141
|
+
},
|
|
18142
|
+
content: memory.content,
|
|
18143
|
+
kindValue: memory.kind_value
|
|
18144
|
+
};
|
|
18145
|
+
};
|
|
18146
|
+
const fetchCandidates = async (embedding, candidateOptions, withCounts) => {
|
|
18147
|
+
const limit = candidateOptions.limit ?? 100;
|
|
18148
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
18149
|
+
throw new Error("Candidate limit must be 1\u2013100");
|
|
18150
|
+
for (const [key, max] of candidateListLimits) {
|
|
18151
|
+
const values = candidateOptions[key];
|
|
18152
|
+
if (values && values.length > max)
|
|
18153
|
+
throw new Error(`Candidate ${key} accepts at most ${max} entries (got ${values.length})`);
|
|
18154
|
+
}
|
|
18155
|
+
const result = await request(
|
|
18156
|
+
"/candidates",
|
|
18157
|
+
{
|
|
18158
|
+
method: "POST",
|
|
18159
|
+
body: JSON.stringify({
|
|
18160
|
+
embedding,
|
|
18161
|
+
limit,
|
|
18162
|
+
force_ids: candidateOptions.force_ids ?? [],
|
|
18163
|
+
...withCounts && { with_counts: true },
|
|
18164
|
+
...Object.fromEntries(
|
|
18165
|
+
[
|
|
18166
|
+
"scopes",
|
|
18167
|
+
"memory_ids",
|
|
18168
|
+
"embedding_model",
|
|
18169
|
+
"strict_model",
|
|
18170
|
+
"include_deleted",
|
|
18171
|
+
"deleted_only"
|
|
18172
|
+
].filter(
|
|
18173
|
+
(key) => candidateOptions[key] !== void 0
|
|
18174
|
+
).map((key) => [key, candidateOptions[key]])
|
|
18175
|
+
),
|
|
18176
|
+
...candidateOptions.fact_types !== void 0 && {
|
|
18177
|
+
fact_types: candidateOptions.fact_types
|
|
18178
|
+
},
|
|
18179
|
+
...candidateOptions.include_archived !== void 0 && {
|
|
18180
|
+
include_archived: candidateOptions.include_archived
|
|
18181
|
+
},
|
|
18182
|
+
...candidateOptions.include_quarantined !== void 0 && {
|
|
18183
|
+
include_quarantined: candidateOptions.include_quarantined
|
|
18184
|
+
},
|
|
18185
|
+
...candidateOptions.include_superseded !== void 0 && {
|
|
18186
|
+
include_superseded: candidateOptions.include_superseded
|
|
18187
|
+
}
|
|
18188
|
+
})
|
|
18189
|
+
},
|
|
18190
|
+
candidateOptions.signal
|
|
18191
|
+
);
|
|
18192
|
+
if (!record(result) || !Array.isArray(result.items))
|
|
18193
|
+
throw new Error("Invalid nearby candidate response");
|
|
18194
|
+
return result;
|
|
18195
|
+
};
|
|
18196
|
+
const candidateSet = async (embedding, candidateOptions = {}) => {
|
|
18197
|
+
const result = await fetchCandidates(embedding, candidateOptions, true);
|
|
18198
|
+
if (!Number.isSafeInteger(result.total_count) || result.total_count < 0 || !Number.isSafeInteger(result.unavailable_count) || result.unavailable_count < 0)
|
|
18199
|
+
throw new Error("Invalid nearby candidate response");
|
|
18200
|
+
return {
|
|
18201
|
+
...await decodeAll(result.items),
|
|
18202
|
+
total_count: result.total_count,
|
|
18203
|
+
unavailable_count: result.unavailable_count
|
|
18204
|
+
};
|
|
18205
|
+
};
|
|
18206
|
+
return {
|
|
18207
|
+
get: async (id, signal) => {
|
|
18208
|
+
try {
|
|
18209
|
+
return await decode(await request(memoryPath(id), {}, signal));
|
|
18210
|
+
} catch (error) {
|
|
18211
|
+
if (error instanceof RemoteMemoryError && error.status === 404) return null;
|
|
18212
|
+
throw error;
|
|
18213
|
+
}
|
|
18214
|
+
},
|
|
18215
|
+
list: async (listOptions = {}) => {
|
|
18216
|
+
const { signal, ...query } = listOptions;
|
|
18217
|
+
if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) {
|
|
18218
|
+
throw new Error("Page limit must be 1\u2013200");
|
|
18219
|
+
}
|
|
18220
|
+
const params = new URLSearchParams();
|
|
18221
|
+
for (const key of [
|
|
18222
|
+
"cursor",
|
|
18223
|
+
"limit",
|
|
18224
|
+
"include_deleted",
|
|
18225
|
+
"include_archived",
|
|
18226
|
+
"include_quarantined",
|
|
18227
|
+
"include_superseded",
|
|
18228
|
+
"include_embeddings"
|
|
18229
|
+
]) {
|
|
18230
|
+
if (query[key] !== void 0) params.set(key, String(query[key]));
|
|
18231
|
+
}
|
|
18232
|
+
const page = await request("/memories?" + params.toString(), {}, signal);
|
|
18233
|
+
if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
|
|
18234
|
+
throw new Error("Invalid nearby private-memory page");
|
|
18235
|
+
}
|
|
18236
|
+
return {
|
|
18237
|
+
...await decodeAll(page.items),
|
|
18238
|
+
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
|
|
18239
|
+
};
|
|
18240
|
+
},
|
|
18241
|
+
put: async (memory, expectedVersion, signal) => {
|
|
18242
|
+
const write = await prepareWrite(memory, expectedVersion, signal);
|
|
18243
|
+
return decodeCommitted(
|
|
18244
|
+
await request(
|
|
18245
|
+
memoryPath(write.body.memory.memory_id),
|
|
18246
|
+
{
|
|
18247
|
+
method: "PUT",
|
|
18248
|
+
body: JSON.stringify({ key_id: options.keyId, ...write.body })
|
|
18249
|
+
},
|
|
18250
|
+
signal
|
|
18251
|
+
),
|
|
18252
|
+
write
|
|
18253
|
+
);
|
|
18254
|
+
},
|
|
18255
|
+
putMany: async (writes, signal) => {
|
|
18256
|
+
if (writes.length < 1 || writes.length > 50 || new Set(writes.map((w) => w.memory.memory_id)).size !== writes.length)
|
|
18257
|
+
throw new Error("Batch must contain 1\u201350 distinct memory ids");
|
|
18258
|
+
const prepared = await Promise.all(
|
|
18259
|
+
writes.map((w) => prepareWrite(w.memory, w.expectedVersion, signal))
|
|
18260
|
+
);
|
|
18261
|
+
const result = await request(
|
|
18262
|
+
"/memories/batch",
|
|
18263
|
+
{
|
|
18264
|
+
method: "POST",
|
|
18265
|
+
body: JSON.stringify({ key_id: options.keyId, writes: prepared.map((w) => w.body) })
|
|
18266
|
+
},
|
|
18267
|
+
signal
|
|
18268
|
+
);
|
|
18269
|
+
if (!record(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
|
|
18270
|
+
throw new Error("Invalid nearby batch response");
|
|
18271
|
+
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
18272
|
+
},
|
|
18273
|
+
candidateSet,
|
|
18274
|
+
candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
|
|
18275
|
+
};
|
|
18276
|
+
}
|
|
18277
|
+
|
|
18278
|
+
// src/lib/memory/store/remotePipeline.ts
|
|
18279
|
+
import { v7 as uuidv74 } from "uuid";
|
|
18280
|
+
function storedVector(vector) {
|
|
18281
|
+
if (!Array.isArray(vector) || vector.length !== 1536 && vector.length !== 4096 || vector.some((v) => !Number.isFinite(v)))
|
|
18282
|
+
throw new Error("Remote memories require a finite 1536/4096-dimensional vector");
|
|
18283
|
+
const out = vector.slice(0, 1536);
|
|
18284
|
+
const norm = Math.sqrt(out.reduce((sum, v) => sum + v * v, 0));
|
|
18285
|
+
if (!norm) throw new Error("Remote query/content vector has no direction after MRL truncation");
|
|
18286
|
+
return out.map((v) => v / norm);
|
|
18287
|
+
}
|
|
18288
|
+
function sourceIds(value) {
|
|
18289
|
+
if (!value) return [];
|
|
18290
|
+
try {
|
|
18291
|
+
const parsed = JSON.parse(value);
|
|
18292
|
+
return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
|
|
18293
|
+
} catch {
|
|
18294
|
+
return [];
|
|
18295
|
+
}
|
|
18296
|
+
}
|
|
18297
|
+
function stored(row) {
|
|
18298
|
+
return {
|
|
18299
|
+
uniqueId: row.memory_id,
|
|
18300
|
+
content: row.content,
|
|
18301
|
+
scope: row.scope,
|
|
18302
|
+
folderId: row.folder_id ?? null,
|
|
18303
|
+
userId: null,
|
|
18304
|
+
embedding: row.embedding ? JSON.stringify(row.embedding) : null,
|
|
18305
|
+
embeddingModel: row.embedding_model ?? null,
|
|
18306
|
+
sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
|
|
18307
|
+
proofCount: row.proof_count ?? null,
|
|
18308
|
+
source: row.source ?? null,
|
|
18309
|
+
media: parseMedia(row.media),
|
|
18310
|
+
eventTimeStart: row.event_time_start ?? null,
|
|
18311
|
+
eventTimeEnd: row.event_time_end ?? null,
|
|
18312
|
+
eventTimeKind: row.event_time_kind ?? null,
|
|
18313
|
+
topicsUserManaged: row.topics_user_managed ?? false,
|
|
18314
|
+
topics: parseTopics(row.topics),
|
|
18315
|
+
topicsUpdatedAt: row.topics_updated_at ?? null,
|
|
18316
|
+
topicsExtractedAt: row.topics_extracted_at ?? null,
|
|
18317
|
+
topicsExtractedVersion: row.topics_extracted_version ?? null,
|
|
18318
|
+
supersededBy: row.superseded_by ?? null,
|
|
18319
|
+
supersededAt: row.superseded_at ?? null,
|
|
18320
|
+
lastObservedAt: row.last_observed_at ?? null,
|
|
18321
|
+
factType: row.fact_type ?? null,
|
|
18322
|
+
archivedAt: row.archived_at ?? null,
|
|
18323
|
+
trustTier: row.trust_tier ?? null,
|
|
18324
|
+
visibility: row.visibility === "public" ? "public" : "private",
|
|
18325
|
+
twinOptIn: row.twin_opt_in ?? false,
|
|
18326
|
+
publishedAt: row.published_at ?? null,
|
|
18327
|
+
geohash: row.geohash ?? null,
|
|
18328
|
+
createdAt: new Date(row.created_at),
|
|
18329
|
+
updatedAt: new Date(row.updated_at),
|
|
18330
|
+
isDeleted: row.is_deleted
|
|
18331
|
+
};
|
|
18332
|
+
}
|
|
18333
|
+
function createRemoteMemoryPipeline(options) {
|
|
18334
|
+
const { persistence, embeddingOptions } = options;
|
|
18335
|
+
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
18336
|
+
const operation = (mode) => {
|
|
18337
|
+
const rejectUndecryptable = (failed) => {
|
|
18338
|
+
if (!failed.length) return;
|
|
18339
|
+
if (mode === "retain")
|
|
18340
|
+
throw new Error(
|
|
18341
|
+
`Remote memories could not decrypt ${failed.length} candidate row(s); refusing to retain until they are repaired`
|
|
18342
|
+
);
|
|
18343
|
+
getLogger().warn(
|
|
18344
|
+
`[memory/remote] Skipping ${failed.length} undecryptable candidate row(s)`,
|
|
18345
|
+
failed.map((failure) => failure.memory_id)
|
|
18346
|
+
);
|
|
18347
|
+
};
|
|
18348
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
18349
|
+
const remember = (items) => {
|
|
18350
|
+
items.forEach((item) => snapshots.set(item.memory.memory_id, item));
|
|
18351
|
+
return items.map((item) => stored(item.memory));
|
|
18352
|
+
};
|
|
18353
|
+
const get = async (id) => {
|
|
18354
|
+
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
18355
|
+
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
18356
|
+
snapshots.set(id, snapshot);
|
|
18357
|
+
return stored(snapshot.memory);
|
|
18358
|
+
};
|
|
18359
|
+
const prepare = async (query, search = {}) => {
|
|
18360
|
+
if (search.folderId !== void 0)
|
|
18361
|
+
throw new Error("Remote memories do not support folder filters");
|
|
18362
|
+
const facets = normalizeSubQueries(search.subQueries);
|
|
18363
|
+
const facetQueries = facets.length >= 2 ? facets : [];
|
|
18364
|
+
const start = Date.now();
|
|
18365
|
+
const budgetMs = search.queryEmbedTotalTimeoutMs ?? 8e3;
|
|
18366
|
+
const embed = (texts) => generateEmbeddings(texts, {
|
|
18367
|
+
...embeddingOptions,
|
|
18368
|
+
totalTimeoutMs: budgetMs
|
|
18369
|
+
});
|
|
18370
|
+
const embedFacets = async () => {
|
|
18371
|
+
if (!facetQueries.length) return [];
|
|
18372
|
+
try {
|
|
18373
|
+
const vectors2 = await embed(facetQueries);
|
|
18374
|
+
if (vectors2.length !== facetQueries.length)
|
|
18375
|
+
throw new Error("Incomplete facet embeddings");
|
|
18376
|
+
return vectors2.map(storedVector);
|
|
18377
|
+
} catch (error) {
|
|
18378
|
+
getLogger().warn(
|
|
18379
|
+
"[memory/remote] Facet embeddings unavailable; using primary query",
|
|
18380
|
+
error
|
|
18381
|
+
);
|
|
18382
|
+
return [];
|
|
18383
|
+
}
|
|
18384
|
+
};
|
|
18385
|
+
const [primary, facetEmbeddings] = await Promise.all([
|
|
18386
|
+
search.queryEmbedding ?? embed([query]).then((vectors2) => vectors2[0]),
|
|
18387
|
+
embedFacets()
|
|
18388
|
+
]);
|
|
18389
|
+
const queryEmbedding = storedVector(primary);
|
|
18390
|
+
const queryEmbedMs = Date.now() - start;
|
|
18391
|
+
const graph = search.entityRanking ?? [];
|
|
18392
|
+
const temporal = search.temporalRanking ?? [];
|
|
18393
|
+
const forced = /* @__PURE__ */ new Set();
|
|
18394
|
+
for (let i = 0; i < Math.max(graph.length, temporal.length) && forced.size < 100; i++) {
|
|
18395
|
+
if (graph[i] !== void 0) forced.add(graph[i]);
|
|
18396
|
+
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
18397
|
+
}
|
|
18398
|
+
const forceIds = [...forced];
|
|
18399
|
+
const windowOptions = (i, signal) => ({
|
|
18400
|
+
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
18401
|
+
force_ids: i === 0 ? forceIds : [],
|
|
18402
|
+
...search.scopes && { scopes: search.scopes },
|
|
18403
|
+
...search.factTypes && { fact_types: search.factTypes },
|
|
18404
|
+
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
18405
|
+
include_archived: search.includeArchived,
|
|
18406
|
+
embedding_model: model,
|
|
18407
|
+
...signal && { signal }
|
|
18408
|
+
});
|
|
18409
|
+
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
18410
|
+
let windows;
|
|
18411
|
+
if (mode === "retain") {
|
|
18412
|
+
windows = await Promise.all(
|
|
18413
|
+
vectors.map((embedding, i) => persistence.candidateSet(embedding, windowOptions(i)))
|
|
18414
|
+
);
|
|
18415
|
+
} else {
|
|
18416
|
+
const deadline = new AbortController();
|
|
18417
|
+
const timer = setTimeout(
|
|
18418
|
+
() => deadline.abort(
|
|
18419
|
+
new RemoteMemoryError("Remote recall exceeded its query budget", 408, "timeout")
|
|
18420
|
+
),
|
|
18421
|
+
Math.max(0, start + budgetMs - Date.now())
|
|
18422
|
+
);
|
|
18423
|
+
try {
|
|
18424
|
+
windows = await Promise.all(
|
|
18425
|
+
vectors.map(
|
|
18426
|
+
(embedding, i) => persistence.candidates(embedding, windowOptions(i, deadline.signal))
|
|
18427
|
+
)
|
|
18428
|
+
);
|
|
18429
|
+
} finally {
|
|
18430
|
+
clearTimeout(timer);
|
|
18431
|
+
}
|
|
18432
|
+
}
|
|
18433
|
+
rejectUndecryptable([
|
|
18434
|
+
...new Map(
|
|
18435
|
+
windows.flatMap((window2) => window2.failed).map((failure) => [failure.memory_id, failure])
|
|
18436
|
+
).values()
|
|
18437
|
+
]);
|
|
18438
|
+
const items = [
|
|
18439
|
+
...new Map(
|
|
18440
|
+
windows.flatMap((window2) => window2.items).map((item) => [item.memory.memory_id, item])
|
|
18441
|
+
).values()
|
|
18442
|
+
];
|
|
18443
|
+
const memories = remember(items);
|
|
18444
|
+
return {
|
|
18445
|
+
memories,
|
|
18446
|
+
embeddedItems: memories.map((memory) => ({
|
|
18447
|
+
id: memory.uniqueId,
|
|
18448
|
+
content: memory.content,
|
|
18449
|
+
embedding: JSON.parse(memory.embedding ?? "[]"),
|
|
18450
|
+
createdAt: memory.createdAt,
|
|
18451
|
+
updatedAt: memory.updatedAt,
|
|
18452
|
+
proofCount: memory.proofCount,
|
|
18453
|
+
lastObservedAt: memory.lastObservedAt,
|
|
18454
|
+
eventTimeStart: memory.eventTimeStart,
|
|
18455
|
+
eventTimeEnd: memory.eventTimeEnd,
|
|
18456
|
+
eventTimeKind: memory.eventTimeKind === "point" || memory.eventTimeKind === "range" || memory.eventTimeKind === "ongoing" ? memory.eventTimeKind : null,
|
|
18457
|
+
factType: memory.factType,
|
|
18458
|
+
sourceChunkIds: memory.sourceChunkIds
|
|
18459
|
+
})),
|
|
18460
|
+
queryEmbedding,
|
|
18461
|
+
facetEmbeddings,
|
|
18462
|
+
vaultSize: Math.max(windows[0].total_count ?? 0, items.length),
|
|
18463
|
+
embeddingFailure: windows.some((window2) => (window2.unavailable_count ?? 0) > 0),
|
|
18464
|
+
embeddingsUnavailable: (windows[0].total_count ?? items.length) > 0 && !memories.some((memory) => memory.embedding),
|
|
18465
|
+
decryptLast: true,
|
|
18466
|
+
rowsDecrypted: items.length,
|
|
18467
|
+
queryEmbedMs,
|
|
18468
|
+
rowsEmbedded: 0
|
|
18469
|
+
};
|
|
18470
|
+
};
|
|
18471
|
+
const createRow = (input) => {
|
|
18472
|
+
if (input.folderId !== void 0 && input.folderId !== null)
|
|
18473
|
+
throw new Error("Remote memories do not support folders");
|
|
18474
|
+
const now = Date.now();
|
|
18475
|
+
return {
|
|
18476
|
+
memory_id: uuidv74(),
|
|
18477
|
+
content: input.content,
|
|
18478
|
+
scope: input.scope ?? "private",
|
|
18479
|
+
created_at: now,
|
|
18480
|
+
updated_at: now,
|
|
18481
|
+
is_deleted: false,
|
|
18482
|
+
...input.embedding !== void 0 && {
|
|
18483
|
+
embedding: storedVector(JSON.parse(input.embedding)),
|
|
18484
|
+
embedding_model: input.embeddingModel
|
|
18485
|
+
},
|
|
18486
|
+
source_chunk_ids: JSON.stringify(input.sourceChunkIds ?? []),
|
|
18487
|
+
proof_count: input.proofCount ?? 1,
|
|
18488
|
+
source: input.source ?? "manual",
|
|
18489
|
+
...input.eventTime && {
|
|
18490
|
+
event_time_start: input.eventTime.start ?? void 0,
|
|
18491
|
+
event_time_end: input.eventTime.end ?? void 0,
|
|
18492
|
+
event_time_kind: input.eventTime.kind ?? void 0
|
|
18493
|
+
},
|
|
18494
|
+
fact_type: input.factType,
|
|
18495
|
+
trust_tier: normalizeTrustTier(input.trustTier) ?? void 0,
|
|
18496
|
+
geohash: input.geohash,
|
|
18497
|
+
visibility: "private",
|
|
18498
|
+
twin_opt_in: false
|
|
18499
|
+
};
|
|
18500
|
+
};
|
|
18501
|
+
const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
|
|
18502
|
+
const port = {
|
|
18503
|
+
prepare,
|
|
18504
|
+
get,
|
|
18505
|
+
getFresh: async (id) => {
|
|
18506
|
+
const current = await persistence.get(id);
|
|
18507
|
+
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
18508
|
+
},
|
|
18509
|
+
tombstones: async (embedding, embeddingModel, scope, folderId) => {
|
|
18510
|
+
if (folderId !== void 0) throw new Error("Remote memories do not support folders");
|
|
18511
|
+
const window2 = await persistence.candidateSet(storedVector(embedding), {
|
|
18512
|
+
limit: 1,
|
|
18513
|
+
scopes: [scope],
|
|
18514
|
+
embedding_model: embeddingModel,
|
|
18515
|
+
strict_model: true,
|
|
18516
|
+
include_deleted: true,
|
|
18517
|
+
deleted_only: true
|
|
18518
|
+
});
|
|
18519
|
+
rejectUndecryptable(window2.failed);
|
|
18520
|
+
return remember(window2.items);
|
|
18521
|
+
},
|
|
18522
|
+
create: (input) => write(createRow(input), 0),
|
|
18523
|
+
update: async (id, patch) => {
|
|
18524
|
+
const existing = await get(id);
|
|
18525
|
+
if (!existing) return null;
|
|
18526
|
+
const snapshot = snapshots.get(id);
|
|
18527
|
+
const memory = {
|
|
18528
|
+
...snapshot.memory,
|
|
18529
|
+
content: patch.content,
|
|
18530
|
+
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
|
|
18531
|
+
};
|
|
18532
|
+
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
18533
|
+
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
18534
|
+
delete memory.embedding;
|
|
18535
|
+
delete memory.embedding_model;
|
|
18536
|
+
}
|
|
18537
|
+
if (patch.embedding !== void 0) {
|
|
18538
|
+
memory.embedding = patch.embedding === null ? [] : storedVector(JSON.parse(patch.embedding));
|
|
18539
|
+
memory.embedding_model = patch.embeddingModel ?? void 0;
|
|
18540
|
+
}
|
|
18541
|
+
const observed = sourceIds(memory.source_chunk_ids);
|
|
18542
|
+
const replay = !!patch.observationSourceIds?.length && patch.observationSourceIds.every((id2) => observed.includes(id2));
|
|
18543
|
+
if (patch.sourceChunkIds !== void 0)
|
|
18544
|
+
memory.source_chunk_ids = JSON.stringify(
|
|
18545
|
+
patch.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observed, ...patch.sourceChunkIds])] : patch.sourceChunkIds
|
|
18546
|
+
);
|
|
18547
|
+
if (!replay) {
|
|
18548
|
+
if (patch.proofCountIncrement !== void 0)
|
|
18549
|
+
memory.proof_count = (memory.proof_count ?? 1) + patch.proofCountIncrement;
|
|
18550
|
+
else if (patch.proofCount !== void 0) memory.proof_count = patch.proofCount;
|
|
18551
|
+
if (patch.lastObservedAt !== void 0) memory.last_observed_at = patch.lastObservedAt;
|
|
18552
|
+
}
|
|
18553
|
+
if (patch.source !== void 0) memory.source = patch.source;
|
|
18554
|
+
if (patch.factType !== void 0) memory.fact_type = patch.factType;
|
|
18555
|
+
if (patch.trustTier !== void 0)
|
|
18556
|
+
memory.trust_tier = normalizeTrustTier(patch.trustTier) ?? void 0;
|
|
18557
|
+
if (patch.topicsUserManaged !== void 0)
|
|
18558
|
+
memory.topics_user_managed = patch.topicsUserManaged;
|
|
18559
|
+
if (patch.eventTime !== void 0) {
|
|
18560
|
+
memory.event_time_start = patch.eventTime.start ?? void 0;
|
|
18561
|
+
memory.event_time_end = patch.eventTime.end ?? void 0;
|
|
18562
|
+
memory.event_time_kind = patch.eventTime.kind ?? void 0;
|
|
18563
|
+
}
|
|
18564
|
+
if (patch.restore) memory.archived_at = void 0;
|
|
18565
|
+
return write(memory, snapshot);
|
|
18566
|
+
},
|
|
18567
|
+
supersede: async (id, successor) => {
|
|
18568
|
+
const [target, newer] = await Promise.all([get(id), get(successor)]);
|
|
18569
|
+
if (!target || !newer || id === successor) return false;
|
|
18570
|
+
const old = snapshots.get(id);
|
|
18571
|
+
const next = snapshots.get(successor);
|
|
18572
|
+
remember(
|
|
18573
|
+
await persistence.putMany([
|
|
18574
|
+
{
|
|
18575
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
18576
|
+
expectedVersion: old
|
|
18577
|
+
},
|
|
18578
|
+
{ memory: next.memory, expectedVersion: next }
|
|
18579
|
+
])
|
|
18580
|
+
);
|
|
18581
|
+
return true;
|
|
18582
|
+
},
|
|
18583
|
+
createSuperseding: async (input, targetId) => {
|
|
18584
|
+
const target = await get(targetId);
|
|
18585
|
+
if (!target) return { created: null, retired: false };
|
|
18586
|
+
const snapshot = snapshots.get(targetId);
|
|
18587
|
+
const successor = createRow(input);
|
|
18588
|
+
const rows = remember(
|
|
18589
|
+
await persistence.putMany([
|
|
18590
|
+
{ memory: successor, expectedVersion: 0 },
|
|
18591
|
+
{
|
|
18592
|
+
memory: {
|
|
18593
|
+
...snapshot.memory,
|
|
18594
|
+
superseded_by: successor.memory_id,
|
|
18595
|
+
superseded_at: Date.now()
|
|
18596
|
+
},
|
|
18597
|
+
expectedVersion: snapshot
|
|
18598
|
+
}
|
|
18599
|
+
])
|
|
18600
|
+
);
|
|
18601
|
+
return { created: rows[0], retired: true };
|
|
18602
|
+
}
|
|
18603
|
+
};
|
|
18604
|
+
return { prepare, port };
|
|
18605
|
+
};
|
|
18606
|
+
return {
|
|
18607
|
+
recall: async (query, recallOptions = {}) => {
|
|
18608
|
+
const { prepare } = operation("recall");
|
|
18609
|
+
return recall(
|
|
18610
|
+
query,
|
|
18611
|
+
{
|
|
18612
|
+
embeddingOptions,
|
|
18613
|
+
factSource: {
|
|
18614
|
+
graphRanking: options.graphRanking,
|
|
18615
|
+
temporalRanking: options.temporalRanking,
|
|
18616
|
+
search: async (text12, searchOptions) => {
|
|
18617
|
+
const prepared = await prepare(text12, searchOptions);
|
|
18618
|
+
const ranked = await rankPreparedVaultCandidates(
|
|
18619
|
+
text12,
|
|
18620
|
+
prepared,
|
|
18621
|
+
embeddingOptions,
|
|
18622
|
+
searchOptions
|
|
18623
|
+
);
|
|
18624
|
+
return {
|
|
18625
|
+
...ranked,
|
|
18626
|
+
rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
|
|
18627
|
+
decryptLast: true,
|
|
18628
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
18629
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
18630
|
+
rowsEmbedded: 0
|
|
18631
|
+
};
|
|
18632
|
+
}
|
|
18633
|
+
}
|
|
18634
|
+
},
|
|
18635
|
+
{ ...recallOptions, types: ["fact"] }
|
|
18636
|
+
);
|
|
18637
|
+
},
|
|
18638
|
+
retain: async (content, retainOptions) => {
|
|
18639
|
+
const { port } = operation("retain");
|
|
18640
|
+
return retainWithPersistence(
|
|
18641
|
+
content,
|
|
18642
|
+
{
|
|
18643
|
+
persistence: port,
|
|
18644
|
+
embeddingOptions,
|
|
18645
|
+
vaultCache: /* @__PURE__ */ new Map(),
|
|
18646
|
+
normalizeEmbedding: storedVector
|
|
18647
|
+
},
|
|
18648
|
+
retainOptions
|
|
18649
|
+
);
|
|
18650
|
+
}
|
|
18651
|
+
};
|
|
18652
|
+
}
|
|
18653
|
+
|
|
17855
18654
|
// src/lib/memory/synthesizeProfile.ts
|
|
17856
18655
|
var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
|
|
17857
18656
|
var DEFAULT_FACET_RECALL_LIMIT = 20;
|
|
@@ -21262,7 +22061,7 @@ function useChat(options) {
|
|
|
21262
22061
|
|
|
21263
22062
|
// src/expo/useChatStorage.ts
|
|
21264
22063
|
import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
|
|
21265
|
-
import { v7 as
|
|
22064
|
+
import { v7 as uuidv76 } from "uuid";
|
|
21266
22065
|
|
|
21267
22066
|
// src/lib/chat/assembleMessages.ts
|
|
21268
22067
|
function assembleMessagesWithHistory(historyMessages, callerMessages, summarySystemMessage) {
|
|
@@ -21919,9 +22718,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
|
|
|
21919
22718
|
}
|
|
21920
22719
|
|
|
21921
22720
|
// src/lib/db/media/types.ts
|
|
21922
|
-
import { v7 as
|
|
22721
|
+
import { v7 as uuidv75 } from "uuid";
|
|
21923
22722
|
function generateMediaId() {
|
|
21924
|
-
return `media_${
|
|
22723
|
+
return `media_${uuidv75()}`;
|
|
21925
22724
|
}
|
|
21926
22725
|
|
|
21927
22726
|
// src/lib/db/media/operations.ts
|
|
@@ -22128,10 +22927,10 @@ function extractImageModelFromToolEvents(toolCallEvents) {
|
|
|
22128
22927
|
}
|
|
22129
22928
|
return void 0;
|
|
22130
22929
|
}
|
|
22131
|
-
function storedToLlmapiMessage(
|
|
22132
|
-
const content = [{ type: "text", text:
|
|
22133
|
-
if (
|
|
22134
|
-
for (const file of
|
|
22930
|
+
function storedToLlmapiMessage(stored2) {
|
|
22931
|
+
const content = [{ type: "text", text: stored2.content }];
|
|
22932
|
+
if (stored2.role !== "assistant" && stored2.files?.length) {
|
|
22933
|
+
for (const file of stored2.files) {
|
|
22135
22934
|
if (isSendableImageURL(file.url)) {
|
|
22136
22935
|
content.push({
|
|
22137
22936
|
type: "image_url",
|
|
@@ -22141,11 +22940,11 @@ function storedToLlmapiMessage(stored) {
|
|
|
22141
22940
|
}
|
|
22142
22941
|
}
|
|
22143
22942
|
const messages = [];
|
|
22144
|
-
if (
|
|
22943
|
+
if (stored2.role === "assistant" && stored2.toolCallEvents?.length) {
|
|
22145
22944
|
messages.push({
|
|
22146
|
-
role:
|
|
22945
|
+
role: stored2.role,
|
|
22147
22946
|
content: void 0,
|
|
22148
|
-
tool_calls:
|
|
22947
|
+
tool_calls: stored2.toolCallEvents.map((event) => ({
|
|
22149
22948
|
id: event.id,
|
|
22150
22949
|
type: "function",
|
|
22151
22950
|
function: {
|
|
@@ -22154,7 +22953,7 @@ function storedToLlmapiMessage(stored) {
|
|
|
22154
22953
|
}
|
|
22155
22954
|
}))
|
|
22156
22955
|
});
|
|
22157
|
-
for (const event of
|
|
22956
|
+
for (const event of stored2.toolCallEvents) {
|
|
22158
22957
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
22159
22958
|
messages.push({
|
|
22160
22959
|
role: "tool",
|
|
@@ -22163,14 +22962,14 @@ function storedToLlmapiMessage(stored) {
|
|
|
22163
22962
|
});
|
|
22164
22963
|
}
|
|
22165
22964
|
}
|
|
22166
|
-
const postToolText =
|
|
22965
|
+
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
22966
|
messages.push({
|
|
22168
|
-
role:
|
|
22967
|
+
role: stored2.role,
|
|
22169
22968
|
content: [{ type: "text", text: postToolText }]
|
|
22170
22969
|
});
|
|
22171
22970
|
} else {
|
|
22172
22971
|
messages.push({
|
|
22173
|
-
role:
|
|
22972
|
+
role: stored2.role,
|
|
22174
22973
|
content
|
|
22175
22974
|
});
|
|
22176
22975
|
}
|
|
@@ -22877,7 +23676,7 @@ function useChatStorage(options) {
|
|
|
22877
23676
|
};
|
|
22878
23677
|
};
|
|
22879
23678
|
pendingResumeRef.current = null;
|
|
22880
|
-
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${
|
|
23679
|
+
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv76()}` : void 0);
|
|
22881
23680
|
const embedToolText = (text12, mask, masked, token) => {
|
|
22882
23681
|
const opts = {
|
|
22883
23682
|
getToken: token,
|
|
@@ -23395,7 +24194,7 @@ function useChatStorage(options) {
|
|
|
23395
24194
|
const detachedResult = result;
|
|
23396
24195
|
if (detachedResult.detached) {
|
|
23397
24196
|
recordToolSetTurn(database, convId, matchedToolSets);
|
|
23398
|
-
const rowId = effectiveAssistantUniqueId ?? `msg_${
|
|
24197
|
+
const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv76()}`;
|
|
23399
24198
|
pendingResumeRef.current = {
|
|
23400
24199
|
handle: detachedResult.resume ?? null,
|
|
23401
24200
|
convId,
|
|
@@ -23914,6 +24713,7 @@ export {
|
|
|
23914
24713
|
QueueManager,
|
|
23915
24714
|
RECALL_MAX_LIMIT,
|
|
23916
24715
|
RECALL_TOOL_NAME,
|
|
24716
|
+
RemoteMemoryError,
|
|
23917
24717
|
RerankerUnavailableError,
|
|
23918
24718
|
SDK_SCHEMA_VERSION,
|
|
23919
24719
|
SHORT_TTL_MS,
|
|
@@ -23977,6 +24777,8 @@ export {
|
|
|
23977
24777
|
createNotionTools,
|
|
23978
24778
|
createPlatformCursorStore,
|
|
23979
24779
|
createRecallTool,
|
|
24780
|
+
createRemoteMemoryPersistence,
|
|
24781
|
+
createRemoteMemoryPipeline,
|
|
23980
24782
|
createStockPricePreProcessor,
|
|
23981
24783
|
createStreamingDeAnonymizer,
|
|
23982
24784
|
createVaultEmbeddingCache,
|