@anuma/sdk 6.34.0 → 6.36.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 +858 -52
- package/dist/expo/index.d.mts +134 -8
- package/dist/expo/index.d.ts +134 -8
- package/dist/expo/index.mjs +848 -52
- package/dist/memory/context.d.mts +21 -1
- package/dist/memory/context.d.ts +21 -1
- package/dist/react/index.cjs +848 -42
- package/dist/react/index.d.mts +134 -8
- package/dist/react/index.d.ts +134 -8
- package/dist/react/index.mjs +838 -42
- package/dist/server/index.cjs +201 -13
- package/dist/server/index.d.mts +61 -8
- package/dist/server/index.d.ts +61 -8
- package/dist/server/index.mjs +198 -13
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -2358,14 +2358,14 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
|
|
|
2358
2358
|
});
|
|
2359
2359
|
return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
2360
2360
|
}
|
|
2361
|
-
async function updateMessageChunksOp(ctx, uniqueId,
|
|
2361
|
+
async function updateMessageChunksOp(ctx, uniqueId, chunks2, embeddingModel) {
|
|
2362
2362
|
let message;
|
|
2363
2363
|
try {
|
|
2364
2364
|
message = await ctx.messagesCollection.find(uniqueId);
|
|
2365
2365
|
} catch {
|
|
2366
2366
|
return null;
|
|
2367
2367
|
}
|
|
2368
|
-
const storedChunks =
|
|
2368
|
+
const storedChunks = chunks2.map(({ text: _text, ...rest }) => rest);
|
|
2369
2369
|
await ctx.database.write(async () => {
|
|
2370
2370
|
await message.update((msg) => {
|
|
2371
2371
|
msg._setRaw("chunks", JSON.stringify(storedChunks));
|
|
@@ -2409,12 +2409,12 @@ async function stripLegacyChunkTextOp(ctx) {
|
|
|
2409
2409
|
const messages = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(changedIds))).fetch();
|
|
2410
2410
|
const updates = messages.flatMap((message) => {
|
|
2411
2411
|
const raw = message._raw;
|
|
2412
|
-
const
|
|
2413
|
-
if (!
|
|
2412
|
+
const chunks2 = chunksWithoutText(raw.chunks);
|
|
2413
|
+
if (!chunks2) return [];
|
|
2414
2414
|
const updatedAt = raw.updated_at;
|
|
2415
2415
|
return [
|
|
2416
2416
|
message.prepareUpdate((msg) => {
|
|
2417
|
-
msg._setRaw("chunks", JSON.stringify(
|
|
2417
|
+
msg._setRaw("chunks", JSON.stringify(chunks2));
|
|
2418
2418
|
msg._setRaw("updated_at", updatedAt);
|
|
2419
2419
|
})
|
|
2420
2420
|
];
|
|
@@ -2575,15 +2575,15 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2575
2575
|
}
|
|
2576
2576
|
continue;
|
|
2577
2577
|
}
|
|
2578
|
-
const
|
|
2579
|
-
if (
|
|
2580
|
-
const vectors =
|
|
2578
|
+
const chunks2 = await readRawJsonField(message, "chunks", ctx.walletAddress);
|
|
2579
|
+
if (chunks2 && chunks2.length > 0) {
|
|
2580
|
+
const vectors = chunks2.map(
|
|
2581
2581
|
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
2582
2582
|
unreadableVectors++;
|
|
2583
2583
|
})
|
|
2584
2584
|
);
|
|
2585
2585
|
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
2586
|
-
for (let ci = 0; ci <
|
|
2586
|
+
for (let ci = 0; ci < chunks2.length; ci++) {
|
|
2587
2587
|
const vec = vectors[ci];
|
|
2588
2588
|
if (vec.length === 0) continue;
|
|
2589
2589
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
@@ -2591,7 +2591,7 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2591
2591
|
candidates.push({
|
|
2592
2592
|
message,
|
|
2593
2593
|
similarity,
|
|
2594
|
-
chunkTextSource: { kind: "chunk", chunk:
|
|
2594
|
+
chunkTextSource: { kind: "chunk", chunk: chunks2[ci], siblings: chunks2 }
|
|
2595
2595
|
});
|
|
2596
2596
|
}
|
|
2597
2597
|
}
|
|
@@ -2740,7 +2740,7 @@ function chunkText(text12, options) {
|
|
|
2740
2740
|
];
|
|
2741
2741
|
}
|
|
2742
2742
|
const sentences = splitIntoSentences(text12);
|
|
2743
|
-
const
|
|
2743
|
+
const chunks2 = [];
|
|
2744
2744
|
let currentChunkSentences = [];
|
|
2745
2745
|
let currentChunkStart = 0;
|
|
2746
2746
|
let currentOffset = 0;
|
|
@@ -2754,7 +2754,7 @@ function chunkText(text12, options) {
|
|
|
2754
2754
|
if (sentence.length > chunkSize) {
|
|
2755
2755
|
if (currentChunkSentences.length > 0) {
|
|
2756
2756
|
const chunkText2 = currentChunkSentences.join(" ");
|
|
2757
|
-
|
|
2757
|
+
chunks2.push({
|
|
2758
2758
|
text: chunkText2,
|
|
2759
2759
|
startOffset: currentChunkStart,
|
|
2760
2760
|
endOffset: currentOffset
|
|
@@ -2765,7 +2765,7 @@ function chunkText(text12, options) {
|
|
|
2765
2765
|
const chunkEnd = Math.min(j + chunkSize, sentence.length);
|
|
2766
2766
|
const chunk = sentence.slice(j, chunkEnd);
|
|
2767
2767
|
if (chunk.length >= minChunkSize) {
|
|
2768
|
-
|
|
2768
|
+
chunks2.push({
|
|
2769
2769
|
text: chunk,
|
|
2770
2770
|
startOffset: sentenceStart + j,
|
|
2771
2771
|
endOffset: sentenceStart + chunkEnd
|
|
@@ -2779,7 +2779,7 @@ function chunkText(text12, options) {
|
|
|
2779
2779
|
const currentText = currentChunkSentences.join(" ");
|
|
2780
2780
|
const potentialLength = currentText.length + (currentText ? 1 : 0) + sentence.length;
|
|
2781
2781
|
if (potentialLength > chunkSize && currentChunkSentences.length > 0) {
|
|
2782
|
-
|
|
2782
|
+
chunks2.push({
|
|
2783
2783
|
text: currentText,
|
|
2784
2784
|
startOffset: currentChunkStart,
|
|
2785
2785
|
endOffset: currentOffset
|
|
@@ -2810,14 +2810,14 @@ function chunkText(text12, options) {
|
|
|
2810
2810
|
if (currentChunkSentences.length > 0) {
|
|
2811
2811
|
const chunkText2 = currentChunkSentences.join(" ");
|
|
2812
2812
|
if (chunkText2.length >= minChunkSize) {
|
|
2813
|
-
|
|
2813
|
+
chunks2.push({
|
|
2814
2814
|
text: chunkText2,
|
|
2815
2815
|
startOffset: currentChunkStart,
|
|
2816
2816
|
endOffset: text12.length
|
|
2817
2817
|
});
|
|
2818
2818
|
}
|
|
2819
2819
|
}
|
|
2820
|
-
if (
|
|
2820
|
+
if (chunks2.length === 0) {
|
|
2821
2821
|
const trimmedText = text12.trim();
|
|
2822
2822
|
if (trimmedText.length > 0) {
|
|
2823
2823
|
return [
|
|
@@ -2829,7 +2829,7 @@ function chunkText(text12, options) {
|
|
|
2829
2829
|
];
|
|
2830
2830
|
}
|
|
2831
2831
|
}
|
|
2832
|
-
return
|
|
2832
|
+
return chunks2;
|
|
2833
2833
|
}
|
|
2834
2834
|
function shouldChunkMessage(content, chunkSize = DEFAULT_CHUNK_SIZE) {
|
|
2835
2835
|
return content.length > chunkSize;
|
|
@@ -2901,9 +2901,9 @@ function createSseClient({
|
|
|
2901
2901
|
if (done) break;
|
|
2902
2902
|
buffer += value;
|
|
2903
2903
|
buffer = buffer.replace(/\r\n?/g, "\n");
|
|
2904
|
-
const
|
|
2905
|
-
buffer =
|
|
2906
|
-
for (const chunk of
|
|
2904
|
+
const chunks2 = buffer.split("\n\n");
|
|
2905
|
+
buffer = chunks2.pop() ?? "";
|
|
2906
|
+
for (const chunk of chunks2) {
|
|
2907
2907
|
const lines = chunk.split("\n");
|
|
2908
2908
|
const dataLines = [];
|
|
2909
2909
|
let eventName;
|
|
@@ -3848,18 +3848,18 @@ async function embedMany(texts, options, outer) {
|
|
|
3848
3848
|
outer
|
|
3849
3849
|
);
|
|
3850
3850
|
} else {
|
|
3851
|
-
const
|
|
3851
|
+
const chunks2 = [];
|
|
3852
3852
|
for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
|
|
3853
|
-
|
|
3853
|
+
chunks2.push(uncachedTexts.slice(i, i + chunkSize));
|
|
3854
3854
|
}
|
|
3855
|
-
const allEmbeddings = new Array(
|
|
3855
|
+
const allEmbeddings = new Array(chunks2.length);
|
|
3856
3856
|
let nextIndex = 0;
|
|
3857
3857
|
const worker = async () => {
|
|
3858
|
-
while (nextIndex <
|
|
3858
|
+
while (nextIndex < chunks2.length) {
|
|
3859
3859
|
if (outer?.aborted) throw outer.reason;
|
|
3860
3860
|
const idx = nextIndex++;
|
|
3861
3861
|
allEmbeddings[idx] = await generateEmbeddingsBatch(
|
|
3862
|
-
|
|
3862
|
+
chunks2[idx],
|
|
3863
3863
|
headers,
|
|
3864
3864
|
baseUrl,
|
|
3865
3865
|
embeddingModel,
|
|
@@ -3871,7 +3871,7 @@ async function embedMany(texts, options, outer) {
|
|
|
3871
3871
|
}
|
|
3872
3872
|
};
|
|
3873
3873
|
const workers = Array.from(
|
|
3874
|
-
{ length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY,
|
|
3874
|
+
{ length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks2.length) },
|
|
3875
3875
|
() => worker()
|
|
3876
3876
|
);
|
|
3877
3877
|
await Promise.all(workers);
|
|
@@ -8507,7 +8507,7 @@ function sseFailureMessage(status, statusText, detail = "") {
|
|
|
8507
8507
|
return `SSE failed: ${status} ${statusText}${detail}`;
|
|
8508
8508
|
}
|
|
8509
8509
|
function parseSseChunks(raw, incompleteBuffer) {
|
|
8510
|
-
const
|
|
8510
|
+
const chunks2 = [];
|
|
8511
8511
|
const text12 = incompleteBuffer + raw;
|
|
8512
8512
|
const lines = text12.split("\n");
|
|
8513
8513
|
const remaining = raw.endsWith("\n") ? "" : lines.pop() ?? "";
|
|
@@ -8516,11 +8516,11 @@ function parseSseChunks(raw, incompleteBuffer) {
|
|
|
8516
8516
|
const data = line.substring(6).trim();
|
|
8517
8517
|
if (data === "[DONE]") continue;
|
|
8518
8518
|
try {
|
|
8519
|
-
|
|
8519
|
+
chunks2.push(JSON.parse(data));
|
|
8520
8520
|
} catch {
|
|
8521
8521
|
}
|
|
8522
8522
|
}
|
|
8523
|
-
return { chunks, remaining };
|
|
8523
|
+
return { chunks: chunks2, remaining };
|
|
8524
8524
|
}
|
|
8525
8525
|
var xhrTransport = (options) => {
|
|
8526
8526
|
const queue = [];
|
|
@@ -8589,18 +8589,18 @@ var xhrTransport = (options) => {
|
|
|
8589
8589
|
const newData = xhr.responseText.substring(lastProcessedIndex);
|
|
8590
8590
|
lastProcessedIndex = xhr.responseText.length;
|
|
8591
8591
|
if (newData.length > 0) options.onActivity?.();
|
|
8592
|
-
const { chunks, remaining } = parseSseChunks(newData, incompleteBuffer);
|
|
8592
|
+
const { chunks: chunks2, remaining } = parseSseChunks(newData, incompleteBuffer);
|
|
8593
8593
|
incompleteBuffer = remaining;
|
|
8594
|
-
for (const chunk of
|
|
8594
|
+
for (const chunk of chunks2) {
|
|
8595
8595
|
push({ type: "data", value: chunk });
|
|
8596
8596
|
}
|
|
8597
8597
|
};
|
|
8598
8598
|
xhr.onload = () => {
|
|
8599
8599
|
options.signal?.removeEventListener("abort", abortHandler);
|
|
8600
8600
|
if (incompleteBuffer) {
|
|
8601
|
-
const { chunks } = parseSseChunks(incompleteBuffer + "\n", "");
|
|
8601
|
+
const { chunks: chunks2 } = parseSseChunks(incompleteBuffer + "\n", "");
|
|
8602
8602
|
incompleteBuffer = "";
|
|
8603
|
-
for (const chunk of
|
|
8603
|
+
for (const chunk of chunks2) {
|
|
8604
8604
|
push({ type: "data", value: chunk });
|
|
8605
8605
|
}
|
|
8606
8606
|
}
|
|
@@ -9246,6 +9246,15 @@ __decorateClass([
|
|
|
9246
9246
|
__decorateClass([
|
|
9247
9247
|
text6("scope")
|
|
9248
9248
|
], VaultMemory.prototype, "scope", 2);
|
|
9249
|
+
__decorateClass([
|
|
9250
|
+
field5("kind")
|
|
9251
|
+
], VaultMemory.prototype, "kind", 2);
|
|
9252
|
+
__decorateClass([
|
|
9253
|
+
field5("kind_value")
|
|
9254
|
+
], VaultMemory.prototype, "kindValue", 2);
|
|
9255
|
+
__decorateClass([
|
|
9256
|
+
field5("level")
|
|
9257
|
+
], VaultMemory.prototype, "level", 2);
|
|
9249
9258
|
__decorateClass([
|
|
9250
9259
|
field5("folder_id")
|
|
9251
9260
|
], VaultMemory.prototype, "folderId", 2);
|
|
@@ -9471,7 +9480,7 @@ __decorateClass([
|
|
|
9471
9480
|
], VaultFolder.prototype, "context", 2);
|
|
9472
9481
|
|
|
9473
9482
|
// src/lib/db/schema.ts
|
|
9474
|
-
var SDK_SCHEMA_VERSION =
|
|
9483
|
+
var SDK_SCHEMA_VERSION = 48;
|
|
9475
9484
|
var sdkSchema = appSchema2({
|
|
9476
9485
|
version: SDK_SCHEMA_VERSION,
|
|
9477
9486
|
tables: [
|
|
@@ -9566,6 +9575,9 @@ var sdkSchema = appSchema2({
|
|
|
9566
9575
|
columns: [
|
|
9567
9576
|
{ name: "content", type: "string" },
|
|
9568
9577
|
{ name: "scope", type: "string", isIndexed: true },
|
|
9578
|
+
{ name: "kind", type: "string", isOptional: true, isIndexed: true },
|
|
9579
|
+
{ name: "kind_value", type: "string", isOptional: true },
|
|
9580
|
+
{ name: "level", type: "string", isOptional: true, isIndexed: true },
|
|
9569
9581
|
{ name: "folder_id", type: "string", isOptional: true, isIndexed: true },
|
|
9570
9582
|
{ name: "created_at", type: "number", isIndexed: true },
|
|
9571
9583
|
{ name: "updated_at", type: "number", isIndexed: true },
|
|
@@ -10242,6 +10254,22 @@ var sdkMigrations = schemaMigrations2({
|
|
|
10242
10254
|
]
|
|
10243
10255
|
})
|
|
10244
10256
|
]
|
|
10257
|
+
},
|
|
10258
|
+
{
|
|
10259
|
+
toVersion: 48,
|
|
10260
|
+
steps: [
|
|
10261
|
+
addColumns2({
|
|
10262
|
+
table: "memory_vault",
|
|
10263
|
+
columns: [
|
|
10264
|
+
{ name: "kind", type: "string", isOptional: true, isIndexed: true },
|
|
10265
|
+
{ name: "kind_value", type: "string", isOptional: true },
|
|
10266
|
+
{ name: "level", type: "string", isOptional: true, isIndexed: true }
|
|
10267
|
+
]
|
|
10268
|
+
}),
|
|
10269
|
+
unsafeExecuteSql(
|
|
10270
|
+
"UPDATE memory_vault SET level = CASE WHEN scope IN ('shared', 'public') THEN 'matching' ELSE 'private' END WHERE level IS NULL;"
|
|
10271
|
+
)
|
|
10272
|
+
]
|
|
10245
10273
|
}
|
|
10246
10274
|
]
|
|
10247
10275
|
});
|
|
@@ -10807,13 +10835,54 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
|
|
|
10807
10835
|
}
|
|
10808
10836
|
}
|
|
10809
10837
|
const decryptedContent = await decryptField(memory.content, address);
|
|
10838
|
+
const decryptedKindValue = typeof memory.kindValue === "string" ? await decryptField(memory.kindValue, address) : memory.kindValue;
|
|
10810
10839
|
return {
|
|
10811
10840
|
...memory,
|
|
10812
|
-
content: decryptedContent
|
|
10841
|
+
content: decryptedContent,
|
|
10842
|
+
...decryptedKindValue !== void 0 && { kindValue: decryptedKindValue }
|
|
10813
10843
|
};
|
|
10814
10844
|
}
|
|
10815
10845
|
|
|
10816
10846
|
// src/lib/db/memoryVault/types.ts
|
|
10847
|
+
var MEMORY_KINDS = [
|
|
10848
|
+
"display_name",
|
|
10849
|
+
"birth_date",
|
|
10850
|
+
"bio",
|
|
10851
|
+
"occupation",
|
|
10852
|
+
"interest",
|
|
10853
|
+
"gender",
|
|
10854
|
+
"height_cm",
|
|
10855
|
+
"looking_for",
|
|
10856
|
+
"politics",
|
|
10857
|
+
"religion",
|
|
10858
|
+
"ethnicity",
|
|
10859
|
+
"smoking",
|
|
10860
|
+
"drinking",
|
|
10861
|
+
"exercise",
|
|
10862
|
+
"sexuality",
|
|
10863
|
+
"prompt"
|
|
10864
|
+
];
|
|
10865
|
+
var MEMORY_LEVELS = ["private", "matching", "profile"];
|
|
10866
|
+
var MemoryLevelError = class extends Error {
|
|
10867
|
+
constructor(message) {
|
|
10868
|
+
super(message);
|
|
10869
|
+
this.name = "MemoryLevelError";
|
|
10870
|
+
}
|
|
10871
|
+
};
|
|
10872
|
+
var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
|
|
10873
|
+
function levelFromScope(scope) {
|
|
10874
|
+
return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
|
|
10875
|
+
}
|
|
10876
|
+
function scopeForLevel(level) {
|
|
10877
|
+
return level === "private" ? "private" : "shared";
|
|
10878
|
+
}
|
|
10879
|
+
function resolveMemoryLevel(level, scope) {
|
|
10880
|
+
return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
|
|
10881
|
+
}
|
|
10882
|
+
function levelForScopeChange(current, nextScope) {
|
|
10883
|
+
const implied = levelFromScope(nextScope);
|
|
10884
|
+
return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
|
|
10885
|
+
}
|
|
10817
10886
|
function parseMedia(value) {
|
|
10818
10887
|
if (typeof value !== "string" || value === "") return null;
|
|
10819
10888
|
try {
|
|
@@ -10843,6 +10912,56 @@ function visibilityConditions(requested) {
|
|
|
10843
10912
|
if (excluded.length === 0) return [];
|
|
10844
10913
|
return [Q5.or(Q5.where("visibility", null), Q5.where("visibility", Q5.notIn(excluded)))];
|
|
10845
10914
|
}
|
|
10915
|
+
function isKinded(record2) {
|
|
10916
|
+
return record2.kind !== null && record2.kind !== void 0;
|
|
10917
|
+
}
|
|
10918
|
+
function assertValidKindLevel(kind, level) {
|
|
10919
|
+
const hasKind = kind !== null && kind !== void 0;
|
|
10920
|
+
if (hasKind && !MEMORY_KINDS.includes(kind)) {
|
|
10921
|
+
throw new MemoryLevelError(`Unknown memory kind: ${kind}`);
|
|
10922
|
+
}
|
|
10923
|
+
if (level !== void 0 && !MEMORY_LEVELS.includes(level)) {
|
|
10924
|
+
throw new MemoryLevelError(`Unknown memory level: ${level}`);
|
|
10925
|
+
}
|
|
10926
|
+
if (level === "profile" && !hasKind) {
|
|
10927
|
+
throw new MemoryLevelError("Only a memory with a kind can be at level 'profile'");
|
|
10928
|
+
}
|
|
10929
|
+
}
|
|
10930
|
+
function resolveCreateLevel(opts) {
|
|
10931
|
+
if (opts.level !== void 0) return { level: opts.level, scope: scopeForLevel(opts.level) };
|
|
10932
|
+
if (opts.scope !== void 0) return { level: levelFromScope(opts.scope), scope: opts.scope };
|
|
10933
|
+
return { level: "private", scope: "private" };
|
|
10934
|
+
}
|
|
10935
|
+
async function encryptKindValue(ctx, value) {
|
|
10936
|
+
if (typeof value !== "string" || !ctx.walletAddress || !ctx.signMessage) return value;
|
|
10937
|
+
return encryptVaultMemoryContent(
|
|
10938
|
+
value,
|
|
10939
|
+
ctx.walletAddress,
|
|
10940
|
+
ctx.signMessage,
|
|
10941
|
+
ctx.embeddedWalletSigner
|
|
10942
|
+
);
|
|
10943
|
+
}
|
|
10944
|
+
function levelConditions(requested) {
|
|
10945
|
+
if (!requested?.length) return [];
|
|
10946
|
+
const published = ["shared", "public"];
|
|
10947
|
+
const wantsMatching = requested.includes("matching");
|
|
10948
|
+
const wantsPrivate = requested.includes("private");
|
|
10949
|
+
const unresolved = Q5.or(Q5.where("level", null), Q5.where("level", Q5.notIn([...MEMORY_LEVELS])));
|
|
10950
|
+
const byLevel = Q5.where("level", Q5.oneOf([...requested]));
|
|
10951
|
+
if (wantsMatching && wantsPrivate) return [Q5.or(byLevel, unresolved)];
|
|
10952
|
+
if (wantsMatching) {
|
|
10953
|
+
return [Q5.or(byLevel, Q5.and(unresolved, Q5.where("scope", Q5.oneOf(published))))];
|
|
10954
|
+
}
|
|
10955
|
+
if (wantsPrivate) {
|
|
10956
|
+
return [
|
|
10957
|
+
Q5.or(
|
|
10958
|
+
byLevel,
|
|
10959
|
+
Q5.and(unresolved, Q5.or(Q5.where("scope", null), Q5.where("scope", Q5.notIn(published))))
|
|
10960
|
+
)
|
|
10961
|
+
];
|
|
10962
|
+
}
|
|
10963
|
+
return [byLevel];
|
|
10964
|
+
}
|
|
10846
10965
|
function isOwnedByCtxUser(ctx, record2) {
|
|
10847
10966
|
return ctx.userId === void 0 || record2.userId === ctx.userId;
|
|
10848
10967
|
}
|
|
@@ -10886,6 +11005,9 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
10886
11005
|
uniqueId: memory.id,
|
|
10887
11006
|
content: memory.content,
|
|
10888
11007
|
scope: memory.scope,
|
|
11008
|
+
kind: memory.kind ?? null,
|
|
11009
|
+
kindValue: memory.kindValue ?? null,
|
|
11010
|
+
level: resolveMemoryLevel(memory.level, memory.scope),
|
|
10889
11011
|
folderId: memory.folderId ?? null,
|
|
10890
11012
|
userId: memory.userId ?? null,
|
|
10891
11013
|
embedding: memory.embedding ?? null,
|
|
@@ -10924,9 +11046,13 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
10924
11046
|
}
|
|
10925
11047
|
return raw;
|
|
10926
11048
|
}
|
|
10927
|
-
function populateNewVaultMemory(record2, ctx, opts, encryptedContent) {
|
|
11049
|
+
function populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue) {
|
|
11050
|
+
const { level, scope } = resolveCreateLevel(opts);
|
|
10928
11051
|
record2._setRaw("content", encryptedContent);
|
|
10929
|
-
record2._setRaw("scope",
|
|
11052
|
+
record2._setRaw("scope", scope);
|
|
11053
|
+
record2._setRaw("level", level);
|
|
11054
|
+
record2._setRaw("kind", opts.kind ?? null);
|
|
11055
|
+
record2._setRaw("kind_value", encryptedKindValue ?? null);
|
|
10930
11056
|
record2._setRaw("folder_id", opts.folderId ?? null);
|
|
10931
11057
|
record2._setRaw("user_id", ctx.userId ?? null);
|
|
10932
11058
|
record2._setRaw("is_deleted", false);
|
|
@@ -10960,6 +11086,8 @@ function populateNewVaultMemory(record2, ctx, opts, encryptedContent) {
|
|
|
10960
11086
|
}
|
|
10961
11087
|
}
|
|
10962
11088
|
async function createVaultMemoryOp(ctx, opts) {
|
|
11089
|
+
assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
11090
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
10963
11091
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
10964
11092
|
opts.content,
|
|
10965
11093
|
ctx.walletAddress,
|
|
@@ -10970,13 +11098,15 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
10970
11098
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
10971
11099
|
throw new Error("Memory source is no longer eligible");
|
|
10972
11100
|
return ctx.vaultMemoryCollection.create(
|
|
10973
|
-
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
|
|
11101
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
10974
11102
|
);
|
|
10975
11103
|
});
|
|
10976
11104
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
10977
11105
|
}
|
|
10978
11106
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
10979
11107
|
if (!targetId) return { created: null, retired: false };
|
|
11108
|
+
assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
11109
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
10980
11110
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
10981
11111
|
opts.content,
|
|
10982
11112
|
ctx.walletAddress,
|
|
@@ -10993,9 +11123,10 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
10993
11123
|
} catch {
|
|
10994
11124
|
return;
|
|
10995
11125
|
}
|
|
10996
|
-
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target))
|
|
11126
|
+
if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
|
|
11127
|
+
return;
|
|
10997
11128
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
10998
|
-
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
|
|
11129
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
10999
11130
|
);
|
|
11000
11131
|
await target.update((r) => {
|
|
11001
11132
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -11059,6 +11190,10 @@ async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
|
|
|
11059
11190
|
}
|
|
11060
11191
|
async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
11061
11192
|
if (optionsArray.length === 0) return [];
|
|
11193
|
+
for (const opts of optionsArray) assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
11194
|
+
const encryptedKindValues = await Promise.all(
|
|
11195
|
+
optionsArray.map((opts) => encryptKindValue(ctx, opts.kindValue))
|
|
11196
|
+
);
|
|
11062
11197
|
const encryptedContents = await Promise.all(
|
|
11063
11198
|
optionsArray.map(async (opts) => {
|
|
11064
11199
|
if (ctx.walletAddress && ctx.signMessage) {
|
|
@@ -11077,7 +11212,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11077
11212
|
throw new Error("Memory source is no longer eligible");
|
|
11078
11213
|
const prepared = optionsArray.map(
|
|
11079
11214
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11080
|
-
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i])
|
|
11215
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
11081
11216
|
)
|
|
11082
11217
|
);
|
|
11083
11218
|
await ctx.database.batch(...prepared);
|
|
@@ -11120,6 +11255,9 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
11120
11255
|
uniqueId: raw.id,
|
|
11121
11256
|
content: raw.content ?? "",
|
|
11122
11257
|
scope: raw.scope ?? "",
|
|
11258
|
+
kind: raw.kind ?? null,
|
|
11259
|
+
kindValue: raw.kind_value ?? null,
|
|
11260
|
+
level: resolveMemoryLevel(raw.level, raw.scope),
|
|
11123
11261
|
folderId: raw.folder_id ?? null,
|
|
11124
11262
|
userId: raw.user_id ?? null,
|
|
11125
11263
|
embedding: raw.embedding ?? null,
|
|
@@ -11163,6 +11301,8 @@ async function getAllVaultMemoriesOp(ctx, options) {
|
|
|
11163
11301
|
...baseVaultConditions(ctx, options),
|
|
11164
11302
|
...options?.scopes?.length ? [Q5.where("scope", Q5.oneOf(options.scopes))] : [],
|
|
11165
11303
|
...visibilityConditions(options?.visibility),
|
|
11304
|
+
...levelConditions(options?.levels),
|
|
11305
|
+
...options?.kinds?.length ? [Q5.where("kind", Q5.oneOf(options.kinds))] : [],
|
|
11166
11306
|
...options?.folderId !== void 0 ? [Q5.where("folder_id", options.folderId)] : [],
|
|
11167
11307
|
...options?.factTypes?.length ? [Q5.where("fact_type", Q5.oneOf(options.factTypes))] : [],
|
|
11168
11308
|
Q5.sortBy(options?.since ? "updated_at" : "created_at", Q5.desc),
|
|
@@ -11329,6 +11469,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11329
11469
|
try {
|
|
11330
11470
|
const probe = await ctx.vaultMemoryCollection.find(id);
|
|
11331
11471
|
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
11472
|
+
if (opts.freeFormOnly && isKinded(probe)) return null;
|
|
11473
|
+
const levelAfter = (current) => {
|
|
11474
|
+
if (opts.level !== void 0) return opts.level;
|
|
11475
|
+
if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
|
|
11476
|
+
return levelForScopeChange(current, opts.scope);
|
|
11477
|
+
};
|
|
11478
|
+
assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
|
|
11479
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
11332
11480
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
11333
11481
|
opts.content,
|
|
11334
11482
|
ctx.walletAddress,
|
|
@@ -11341,10 +11489,13 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11341
11489
|
await ctx.database.write(async () => {
|
|
11342
11490
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11343
11491
|
throw new Error("Memory source is no longer eligible");
|
|
11344
|
-
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
11492
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
11345
11493
|
stale = true;
|
|
11346
11494
|
return;
|
|
11347
11495
|
}
|
|
11496
|
+
const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
|
|
11497
|
+
const nextLevel = levelAfter(record2);
|
|
11498
|
+
assertValidKindLevel(nextKind, nextLevel);
|
|
11348
11499
|
let observedSources = [];
|
|
11349
11500
|
let replayedObservation = false;
|
|
11350
11501
|
if (opts.observationSourceIds?.length) {
|
|
@@ -11358,8 +11509,18 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11358
11509
|
}
|
|
11359
11510
|
await record2.update((r) => {
|
|
11360
11511
|
r._setRaw("content", encryptedContent);
|
|
11361
|
-
if (opts.
|
|
11512
|
+
if (opts.level !== void 0) {
|
|
11513
|
+
r._setRaw("level", nextLevel);
|
|
11514
|
+
r._setRaw("scope", scopeForLevel(nextLevel));
|
|
11515
|
+
} else if (opts.scope !== void 0) {
|
|
11362
11516
|
r._setRaw("scope", opts.scope);
|
|
11517
|
+
r._setRaw("level", nextLevel);
|
|
11518
|
+
}
|
|
11519
|
+
if (opts.kind !== void 0) {
|
|
11520
|
+
r._setRaw("kind", opts.kind);
|
|
11521
|
+
}
|
|
11522
|
+
if (encryptedKindValue !== void 0) {
|
|
11523
|
+
r._setRaw("kind_value", encryptedKindValue);
|
|
11363
11524
|
}
|
|
11364
11525
|
if (opts.folderId !== void 0) {
|
|
11365
11526
|
r._setRaw("folder_id", opts.folderId);
|
|
@@ -11418,7 +11579,8 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11418
11579
|
ctx.signMessage,
|
|
11419
11580
|
ctx.embeddedWalletSigner
|
|
11420
11581
|
);
|
|
11421
|
-
} catch {
|
|
11582
|
+
} catch (err) {
|
|
11583
|
+
if (err instanceof MemoryLevelError) throw err;
|
|
11422
11584
|
return null;
|
|
11423
11585
|
}
|
|
11424
11586
|
}
|
|
@@ -11554,6 +11716,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
11554
11716
|
try {
|
|
11555
11717
|
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
11556
11718
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
11719
|
+
if (isKinded(record2)) return false;
|
|
11557
11720
|
let successor;
|
|
11558
11721
|
try {
|
|
11559
11722
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -11854,7 +12017,10 @@ function assertVaultScopeForSweep(ctx) {
|
|
|
11854
12017
|
}
|
|
11855
12018
|
async function getDecayCandidatesRawOp(ctx) {
|
|
11856
12019
|
assertVaultScopeForSweep(ctx);
|
|
11857
|
-
const results = await ctx.vaultMemoryCollection.query(
|
|
12020
|
+
const results = await ctx.vaultMemoryCollection.query(
|
|
12021
|
+
...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true }),
|
|
12022
|
+
Q5.where("kind", null)
|
|
12023
|
+
).unsafeFetchRaw();
|
|
11858
12024
|
return results.map((raw) => ({
|
|
11859
12025
|
uniqueId: raw.id,
|
|
11860
12026
|
factType: raw.fact_type ?? null,
|
|
@@ -12114,6 +12280,7 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
12114
12280
|
record2._raw.id = row.memoryId;
|
|
12115
12281
|
record2._setRaw("content", content);
|
|
12116
12282
|
record2._setRaw("scope", "shared");
|
|
12283
|
+
record2._setRaw("level", "matching");
|
|
12117
12284
|
record2._setRaw("folder_id", null);
|
|
12118
12285
|
record2._setRaw("user_id", ctx.userId ?? null);
|
|
12119
12286
|
record2._setRaw("is_deleted", false);
|
|
@@ -12522,6 +12689,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
12522
12689
|
for (const memory of memories) {
|
|
12523
12690
|
updates.push(
|
|
12524
12691
|
memory.prepareUpdate((r) => {
|
|
12692
|
+
r._setRaw("level", levelForScopeChange(r, opts.scope));
|
|
12525
12693
|
r._setRaw("scope", opts.scope);
|
|
12526
12694
|
})
|
|
12527
12695
|
);
|
|
@@ -12543,6 +12711,7 @@ async function deleteVaultFolderOp(ctx, id) {
|
|
|
12543
12711
|
const preparedMemories = memories.map(
|
|
12544
12712
|
(memory) => memory.prepareUpdate((r) => {
|
|
12545
12713
|
r._setRaw("folder_id", null);
|
|
12714
|
+
r._setRaw("level", levelForScopeChange(r, "private"));
|
|
12546
12715
|
r._setRaw("scope", "private");
|
|
12547
12716
|
})
|
|
12548
12717
|
);
|
|
@@ -12579,6 +12748,7 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
12579
12748
|
const prepared = memories.map(
|
|
12580
12749
|
(memory) => memory.prepareUpdate((r) => {
|
|
12581
12750
|
r._setRaw("folder_id", folderId);
|
|
12751
|
+
r._setRaw("level", levelForScopeChange(r, targetScope));
|
|
12582
12752
|
r._setRaw("scope", targetScope);
|
|
12583
12753
|
})
|
|
12584
12754
|
);
|
|
@@ -14886,6 +15056,7 @@ async function retainWithPersistence(content, ctx, options = {}) {
|
|
|
14886
15056
|
includeArchived: true,
|
|
14887
15057
|
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
14888
15058
|
});
|
|
15059
|
+
prepared = withoutKindedRows(prepared);
|
|
14889
15060
|
if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
|
|
14890
15061
|
throw new Error(
|
|
14891
15062
|
"retain: embeddings unavailable \u2014 refusing to auto-merge against an inert cosine lane, which would create a duplicate instead of merging into the existing memory. Retry when embeddings recover, or pass enableAutoMerge: false to force a create."
|
|
@@ -14927,6 +15098,7 @@ async function retainWithPersistence(content, ctx, options = {}) {
|
|
|
14927
15098
|
const resurrect = resurrectFields(existing);
|
|
14928
15099
|
const updated = await ctx.persistence.update(targetId, {
|
|
14929
15100
|
content: existing.content,
|
|
15101
|
+
freeFormOnly: true,
|
|
14930
15102
|
proofCountIncrement: 1,
|
|
14931
15103
|
observationSourceIds: options.sourceChunkIds,
|
|
14932
15104
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -15055,6 +15227,17 @@ async function retainWithPersistence(content, ctx, options = {}) {
|
|
|
15055
15227
|
...consolidationDecidedCreate && { consolidation: "create" }
|
|
15056
15228
|
};
|
|
15057
15229
|
}
|
|
15230
|
+
function withoutKindedRows(prepared) {
|
|
15231
|
+
const kinded = new Set(
|
|
15232
|
+
prepared.memories.filter((m) => m.kind !== null && m.kind !== void 0).map((m) => m.uniqueId)
|
|
15233
|
+
);
|
|
15234
|
+
if (kinded.size === 0) return prepared;
|
|
15235
|
+
return {
|
|
15236
|
+
...prepared,
|
|
15237
|
+
memories: prepared.memories.filter((m) => !kinded.has(m.uniqueId)),
|
|
15238
|
+
embeddedItems: prepared.embeddedItems.filter((item) => !kinded.has(item.id))
|
|
15239
|
+
};
|
|
15240
|
+
}
|
|
15058
15241
|
function unionStrings(a, b) {
|
|
15059
15242
|
return [.../* @__PURE__ */ new Set([...a, ...b])];
|
|
15060
15243
|
}
|
|
@@ -15154,6 +15337,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15154
15337
|
const resurrect = resurrectFields(existing);
|
|
15155
15338
|
const updated = await ctx.persistence.update(decision.targetId, {
|
|
15156
15339
|
content: existing.content,
|
|
15340
|
+
freeFormOnly: true,
|
|
15157
15341
|
proofCountIncrement: 1,
|
|
15158
15342
|
observationSourceIds: options.sourceChunkIds,
|
|
15159
15343
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -15199,6 +15383,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15199
15383
|
const resurrect = resurrectFields(existing);
|
|
15200
15384
|
const updated = await ctx.persistence.update(decision.targetId, {
|
|
15201
15385
|
content: decision.content,
|
|
15386
|
+
freeFormOnly: true,
|
|
15202
15387
|
proofCountIncrement: 1,
|
|
15203
15388
|
observationSourceIds: options.sourceChunkIds,
|
|
15204
15389
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -15242,7 +15427,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
15242
15427
|
}
|
|
15243
15428
|
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
15244
15429
|
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
15245
|
-
if (stillExists) {
|
|
15430
|
+
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
|
|
15246
15431
|
throw new Error(`retain: merge into memory ${targetId} failed to persist`);
|
|
15247
15432
|
}
|
|
15248
15433
|
}
|
|
@@ -17884,6 +18069,65 @@ function createLocalMemoryStore(options) {
|
|
|
17884
18069
|
};
|
|
17885
18070
|
}
|
|
17886
18071
|
|
|
18072
|
+
// src/lib/memory/store/memoryKeys.ts
|
|
18073
|
+
var KEY_ID_DOMAIN = "anuma-private-memory-key-id-v1";
|
|
18074
|
+
var MemoryKeyError = class extends Error {
|
|
18075
|
+
constructor(message) {
|
|
18076
|
+
super(message);
|
|
18077
|
+
this.name = "MemoryKeyError";
|
|
18078
|
+
}
|
|
18079
|
+
};
|
|
18080
|
+
async function importAesKey(hex) {
|
|
18081
|
+
return crypto.subtle.importKey(
|
|
18082
|
+
"raw",
|
|
18083
|
+
hexToBytes(hex).buffer,
|
|
18084
|
+
{ name: "AES-GCM" },
|
|
18085
|
+
false,
|
|
18086
|
+
["encrypt", "decrypt"]
|
|
18087
|
+
);
|
|
18088
|
+
}
|
|
18089
|
+
async function deriveMemoryKeyRing(signatureHex) {
|
|
18090
|
+
const v3Hex = await deriveKeyFromSignatureV3(signatureHex);
|
|
18091
|
+
const digest = await crypto.subtle.digest(
|
|
18092
|
+
"SHA-256",
|
|
18093
|
+
new TextEncoder().encode(`${KEY_ID_DOMAIN}:${v3Hex}`)
|
|
18094
|
+
);
|
|
18095
|
+
const keyId = "v3:" + Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
18096
|
+
return {
|
|
18097
|
+
keyId,
|
|
18098
|
+
v3: await importAesKey(v3Hex),
|
|
18099
|
+
v2: await importAesKey(await deriveKeyFromSignature(signatureHex))
|
|
18100
|
+
};
|
|
18101
|
+
}
|
|
18102
|
+
async function decryptWith(value, rings) {
|
|
18103
|
+
const version = value.startsWith("enc:v3:") ? "v3" : "v2";
|
|
18104
|
+
for (const ring of rings) {
|
|
18105
|
+
try {
|
|
18106
|
+
return await decryptDataWithKey(value.slice(`enc:${version}:`.length), ring[version]);
|
|
18107
|
+
} catch {
|
|
18108
|
+
continue;
|
|
18109
|
+
}
|
|
18110
|
+
}
|
|
18111
|
+
throw new MemoryKeyError(`No supplied key decrypts this enc:${version} field`);
|
|
18112
|
+
}
|
|
18113
|
+
function memoryCipher(canonical) {
|
|
18114
|
+
return {
|
|
18115
|
+
encrypt: async (plaintext) => `enc:v3:${await encryptDataWithKey(plaintext, canonical.v3)}`,
|
|
18116
|
+
decrypt: async (ciphertext) => {
|
|
18117
|
+
if (!ciphertext.startsWith("enc:v3:") || !isEncrypted(ciphertext))
|
|
18118
|
+
throw new MemoryKeyError("Remote memory content must be enc:v3 ciphertext");
|
|
18119
|
+
return decryptWith(ciphertext, [canonical]);
|
|
18120
|
+
}
|
|
18121
|
+
};
|
|
18122
|
+
}
|
|
18123
|
+
async function reencryptMemoryField(value, canonical, fallbacks = []) {
|
|
18124
|
+
const { encrypt } = memoryCipher(canonical);
|
|
18125
|
+
if (!value.startsWith("enc:")) return encrypt(value);
|
|
18126
|
+
if (!isEncrypted(value))
|
|
18127
|
+
throw new MemoryKeyError("Field has an encryption prefix but an invalid payload");
|
|
18128
|
+
return encrypt(await decryptWith(value, [canonical, ...fallbacks]));
|
|
18129
|
+
}
|
|
18130
|
+
|
|
17887
18131
|
// src/lib/memory/store/remotePersistence.ts
|
|
17888
18132
|
var RemoteMemoryError = class extends Error {
|
|
17889
18133
|
constructor(message, status, code) {
|
|
@@ -17936,6 +18180,30 @@ var candidateListLimits = [
|
|
|
17936
18180
|
["memory_ids", 1e3],
|
|
17937
18181
|
["force_ids", 100]
|
|
17938
18182
|
];
|
|
18183
|
+
var queryListLimits = [
|
|
18184
|
+
["scopes", 20],
|
|
18185
|
+
["fact_types", 20],
|
|
18186
|
+
["visibility", 20],
|
|
18187
|
+
["memory_ids", 1e3],
|
|
18188
|
+
["topics", 100]
|
|
18189
|
+
];
|
|
18190
|
+
var queryFields = [
|
|
18191
|
+
"include_deleted",
|
|
18192
|
+
"include_archived",
|
|
18193
|
+
"include_quarantined",
|
|
18194
|
+
"include_superseded",
|
|
18195
|
+
"archived_only",
|
|
18196
|
+
"scopes",
|
|
18197
|
+
"fact_types",
|
|
18198
|
+
"visibility",
|
|
18199
|
+
"memory_ids",
|
|
18200
|
+
"topics",
|
|
18201
|
+
"updated_after",
|
|
18202
|
+
"order",
|
|
18203
|
+
"cursor",
|
|
18204
|
+
"limit",
|
|
18205
|
+
"include_embeddings"
|
|
18206
|
+
];
|
|
17939
18207
|
function record(value) {
|
|
17940
18208
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17941
18209
|
}
|
|
@@ -18270,6 +18538,35 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
18270
18538
|
throw new Error("Invalid nearby batch response");
|
|
18271
18539
|
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
18272
18540
|
},
|
|
18541
|
+
query: async (queryOptions = {}) => {
|
|
18542
|
+
const { signal, ...query } = queryOptions;
|
|
18543
|
+
if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200))
|
|
18544
|
+
throw new Error("Page limit must be 1\u2013200");
|
|
18545
|
+
for (const [key, max] of queryListLimits) {
|
|
18546
|
+
const values = query[key];
|
|
18547
|
+
if (values && values.length > max)
|
|
18548
|
+
throw new Error(`Query ${key} accepts at most ${max} entries (got ${values.length})`);
|
|
18549
|
+
}
|
|
18550
|
+
const page = await request(
|
|
18551
|
+
"/memories/query",
|
|
18552
|
+
{
|
|
18553
|
+
method: "POST",
|
|
18554
|
+
body: JSON.stringify(
|
|
18555
|
+
Object.fromEntries(
|
|
18556
|
+
queryFields.filter((key) => query[key] !== void 0).map((key) => [key, query[key]])
|
|
18557
|
+
)
|
|
18558
|
+
)
|
|
18559
|
+
},
|
|
18560
|
+
signal
|
|
18561
|
+
);
|
|
18562
|
+
if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string" || page.changes_cursor !== void 0 && typeof page.changes_cursor !== "string")
|
|
18563
|
+
throw new Error("Invalid nearby private-memory page");
|
|
18564
|
+
return {
|
|
18565
|
+
...await decodeAll(page.items),
|
|
18566
|
+
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor },
|
|
18567
|
+
...page.changes_cursor !== void 0 && { changes_cursor: page.changes_cursor }
|
|
18568
|
+
};
|
|
18569
|
+
},
|
|
18273
18570
|
candidateSet,
|
|
18274
18571
|
candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
|
|
18275
18572
|
};
|
|
@@ -18294,6 +18591,9 @@ function sourceIds(value) {
|
|
|
18294
18591
|
return [];
|
|
18295
18592
|
}
|
|
18296
18593
|
}
|
|
18594
|
+
function isMemoryLevel(value) {
|
|
18595
|
+
return MEMORY_LEVELS.includes(value);
|
|
18596
|
+
}
|
|
18297
18597
|
function stored(row) {
|
|
18298
18598
|
return {
|
|
18299
18599
|
uniqueId: row.memory_id,
|
|
@@ -18301,6 +18601,9 @@ function stored(row) {
|
|
|
18301
18601
|
scope: row.scope,
|
|
18302
18602
|
folderId: row.folder_id ?? null,
|
|
18303
18603
|
userId: null,
|
|
18604
|
+
kind: row.kind ?? null,
|
|
18605
|
+
kindValue: row.kind_value ?? null,
|
|
18606
|
+
...isMemoryLevel(row.level) && { level: row.level },
|
|
18304
18607
|
embedding: row.embedding ? JSON.stringify(row.embedding) : null,
|
|
18305
18608
|
embeddingModel: row.embedding_model ?? null,
|
|
18306
18609
|
sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
|
|
@@ -18522,7 +18825,8 @@ function createRemoteMemoryPipeline(options) {
|
|
|
18522
18825
|
create: (input) => write(createRow(input), 0),
|
|
18523
18826
|
update: async (id, patch) => {
|
|
18524
18827
|
const existing = await get(id);
|
|
18525
|
-
if (!existing
|
|
18828
|
+
if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
18829
|
+
return null;
|
|
18526
18830
|
const snapshot = snapshots.get(id);
|
|
18527
18831
|
const memory = {
|
|
18528
18832
|
...snapshot.memory,
|
|
@@ -18651,6 +18955,489 @@ function createRemoteMemoryPipeline(options) {
|
|
|
18651
18955
|
};
|
|
18652
18956
|
}
|
|
18653
18957
|
|
|
18958
|
+
// src/lib/memory/store/remoteStore.ts
|
|
18959
|
+
import { v7 as uuidv75 } from "uuid";
|
|
18960
|
+
function relevant(change, options) {
|
|
18961
|
+
return options.includeDeleted ? change === "membership" : change !== "embedding" || !!options.embeddings;
|
|
18962
|
+
}
|
|
18963
|
+
function safely(onChange) {
|
|
18964
|
+
try {
|
|
18965
|
+
onChange();
|
|
18966
|
+
} catch (error) {
|
|
18967
|
+
getLogger().warn("[memory/remote-store] Subscriber threw:", error);
|
|
18968
|
+
}
|
|
18969
|
+
}
|
|
18970
|
+
var MAX_BATCH = 50;
|
|
18971
|
+
var MAX_QUERY_IDS = 1e3;
|
|
18972
|
+
var MAX_QUERY_TOPICS = 100;
|
|
18973
|
+
var MAX_QUERY_FILTER = 20;
|
|
18974
|
+
var RemoteMemoryPartialCreateError = class extends Error {
|
|
18975
|
+
constructor(created, cause) {
|
|
18976
|
+
super(`createMany stored ${created.length} memories before a batch failed`);
|
|
18977
|
+
this.created = created;
|
|
18978
|
+
this.cause = cause;
|
|
18979
|
+
this.name = "RemoteMemoryPartialCreateError";
|
|
18980
|
+
}
|
|
18981
|
+
};
|
|
18982
|
+
function warnFailed(failed) {
|
|
18983
|
+
if (failed.length)
|
|
18984
|
+
getLogger().warn(
|
|
18985
|
+
`[memory/remote-store] Skipping ${failed.length} undecryptable row(s)`,
|
|
18986
|
+
failed.map((failure) => failure.memory_id)
|
|
18987
|
+
);
|
|
18988
|
+
}
|
|
18989
|
+
function bounded(filters, key) {
|
|
18990
|
+
const values = filters[key];
|
|
18991
|
+
if (!values || values.length <= MAX_QUERY_FILTER) return [filters];
|
|
18992
|
+
return chunks(values, MAX_QUERY_FILTER).map((chunk) => ({ ...filters, [key]: chunk }));
|
|
18993
|
+
}
|
|
18994
|
+
function chunks(values, size) {
|
|
18995
|
+
const out = [];
|
|
18996
|
+
for (let i = 0; i < values.length; i += size) out.push(values.slice(i, i + size));
|
|
18997
|
+
return out;
|
|
18998
|
+
}
|
|
18999
|
+
function stateFilters(options) {
|
|
19000
|
+
return {
|
|
19001
|
+
include_deleted: options.includeDeleted,
|
|
19002
|
+
include_archived: options.includeArchived,
|
|
19003
|
+
include_quarantined: options.includeQuarantined,
|
|
19004
|
+
include_superseded: options.includeSuperseded
|
|
19005
|
+
};
|
|
19006
|
+
}
|
|
19007
|
+
function hidden(memory, options) {
|
|
19008
|
+
if (memory.trust_tier === "quarantined") return true;
|
|
19009
|
+
if (options.includeDeleted) return false;
|
|
19010
|
+
return !!memory.is_deleted || memory.archived_at !== void 0 && memory.archived_at !== null || !!memory.superseded_by;
|
|
19011
|
+
}
|
|
19012
|
+
function subscriptionKey({ memory, version }, options) {
|
|
19013
|
+
if (hidden(memory, options)) return void 0;
|
|
19014
|
+
if (options.includeDeleted) return String(!!memory.is_deleted);
|
|
19015
|
+
return JSON.stringify([
|
|
19016
|
+
options.embeddings ? version : null,
|
|
19017
|
+
memory.content,
|
|
19018
|
+
memory.scope,
|
|
19019
|
+
memory.updated_at,
|
|
19020
|
+
memory.fact_type,
|
|
19021
|
+
memory.event_time_start,
|
|
19022
|
+
memory.event_time_end,
|
|
19023
|
+
memory.event_time_kind,
|
|
19024
|
+
memory.trust_tier,
|
|
19025
|
+
memory.visibility,
|
|
19026
|
+
memory.published_at,
|
|
19027
|
+
memory.geohash,
|
|
19028
|
+
memory.topics,
|
|
19029
|
+
memory.topics_user_managed,
|
|
19030
|
+
memory.media,
|
|
19031
|
+
memory.source
|
|
19032
|
+
]);
|
|
19033
|
+
}
|
|
19034
|
+
function topicInputs(topics, source) {
|
|
19035
|
+
return topics.flatMap((topic) => {
|
|
19036
|
+
const name = (typeof topic === "string" ? topic : topic.name).trim();
|
|
19037
|
+
const kind = typeof topic === "string" ? void 0 : topic.kind;
|
|
19038
|
+
return name ? [{ name, ...kind && { kind }, source }] : [];
|
|
19039
|
+
});
|
|
19040
|
+
}
|
|
19041
|
+
function mergeTopics(existing, added) {
|
|
19042
|
+
const byName = /* @__PURE__ */ new Map();
|
|
19043
|
+
for (const topic of [...existing, ...added]) {
|
|
19044
|
+
const key = normalizeEntityName(topic.name);
|
|
19045
|
+
if (!byName.has(key)) byName.set(key, topic);
|
|
19046
|
+
}
|
|
19047
|
+
return [...byName.values()];
|
|
19048
|
+
}
|
|
19049
|
+
function canonicalTopics(row) {
|
|
19050
|
+
return new Set((parseTopics(row.topics) ?? []).map((topic) => normalizeEntityName(topic.name)));
|
|
19051
|
+
}
|
|
19052
|
+
function createRemoteMemoryStore(options) {
|
|
19053
|
+
const { persistence, embeddingOptions } = options;
|
|
19054
|
+
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
19055
|
+
const pollIntervalMs = options.pollIntervalMs ?? 6e4;
|
|
19056
|
+
const pipeline = createRemoteMemoryPipeline(options);
|
|
19057
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
19058
|
+
const seen = /* @__PURE__ */ new Map();
|
|
19059
|
+
let timer;
|
|
19060
|
+
const notify = (change, records = []) => {
|
|
19061
|
+
if (timer) for (const record2 of records) seen.set(record2.memory.memory_id, record2);
|
|
19062
|
+
for (const subscriber of [...subscribers])
|
|
19063
|
+
if (relevant(change, subscriber.options)) safely(subscriber.onChange);
|
|
19064
|
+
};
|
|
19065
|
+
const enumerate = async (filters, max = Infinity) => {
|
|
19066
|
+
const records = [];
|
|
19067
|
+
let cursor2;
|
|
19068
|
+
do {
|
|
19069
|
+
const page = await persistence.query({
|
|
19070
|
+
...filters,
|
|
19071
|
+
limit: Math.min(200, Math.max(1, max - records.length)),
|
|
19072
|
+
...cursor2 && { cursor: cursor2 }
|
|
19073
|
+
});
|
|
19074
|
+
warnFailed(page.failed);
|
|
19075
|
+
records.push(...page.items);
|
|
19076
|
+
cursor2 = page.next_cursor;
|
|
19077
|
+
} while (cursor2 && records.length < max);
|
|
19078
|
+
return records.slice(0, max);
|
|
19079
|
+
};
|
|
19080
|
+
const enumerateIds = async (ids, filters) => (await Promise.all(
|
|
19081
|
+
chunks([...new Set(ids)], MAX_QUERY_IDS).map(
|
|
19082
|
+
(memory_ids) => enumerate({ ...filters, memory_ids })
|
|
19083
|
+
)
|
|
19084
|
+
)).flat();
|
|
19085
|
+
const queues = /* @__PURE__ */ new Map();
|
|
19086
|
+
const serialized = (id, task) => {
|
|
19087
|
+
const run = (queues.get(id) ?? Promise.resolve()).then(task, task);
|
|
19088
|
+
const settled = run.catch(() => void 0);
|
|
19089
|
+
queues.set(id, settled);
|
|
19090
|
+
void settled.then(() => {
|
|
19091
|
+
if (queues.get(id) === settled) queues.delete(id);
|
|
19092
|
+
});
|
|
19093
|
+
return run;
|
|
19094
|
+
};
|
|
19095
|
+
const live = async (id) => {
|
|
19096
|
+
const record2 = await persistence.get(id);
|
|
19097
|
+
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
19098
|
+
};
|
|
19099
|
+
const mutate = async (id, change, edit) => serialized(id, async () => {
|
|
19100
|
+
const record2 = await live(id);
|
|
19101
|
+
if (!record2) return null;
|
|
19102
|
+
const next = edit(structuredClone(record2.memory));
|
|
19103
|
+
if (!next) return null;
|
|
19104
|
+
const saved = await persistence.put(next, record2);
|
|
19105
|
+
notify(change, [saved]);
|
|
19106
|
+
return saved;
|
|
19107
|
+
});
|
|
19108
|
+
const embedInBackground = ({ memory: { memory_id: id, content } }) => {
|
|
19109
|
+
generateEmbedding(content, embeddingOptions).then(
|
|
19110
|
+
(vector) => serialized(id, async () => {
|
|
19111
|
+
const current = await live(id);
|
|
19112
|
+
if (!current || current.memory.content !== content || current.memory.embedding?.length)
|
|
19113
|
+
return;
|
|
19114
|
+
const saved = await persistence.put(
|
|
19115
|
+
{ ...current.memory, embedding: storedVector(vector), embedding_model: model },
|
|
19116
|
+
current
|
|
19117
|
+
);
|
|
19118
|
+
notify("embedding", [saved]);
|
|
19119
|
+
})
|
|
19120
|
+
).catch((error) => {
|
|
19121
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
19122
|
+
});
|
|
19123
|
+
};
|
|
19124
|
+
const newRow = (input) => {
|
|
19125
|
+
const now = Date.now();
|
|
19126
|
+
const scope = input.scope ?? "private";
|
|
19127
|
+
return {
|
|
19128
|
+
memory_id: uuidv75(),
|
|
19129
|
+
content: input.content,
|
|
19130
|
+
scope,
|
|
19131
|
+
level: levelFromScope(scope),
|
|
19132
|
+
created_at: now,
|
|
19133
|
+
updated_at: now,
|
|
19134
|
+
is_deleted: false,
|
|
19135
|
+
...input.embedding !== void 0 && {
|
|
19136
|
+
embedding: storedVector(JSON.parse(input.embedding)),
|
|
19137
|
+
embedding_model: input.embeddingModel ?? model
|
|
19138
|
+
},
|
|
19139
|
+
proof_count: 1,
|
|
19140
|
+
source: "manual",
|
|
19141
|
+
...input.eventTime && {
|
|
19142
|
+
event_time_start: input.eventTime.start ?? void 0,
|
|
19143
|
+
event_time_end: input.eventTime.end ?? void 0,
|
|
19144
|
+
event_time_kind: input.eventTime.kind ?? void 0
|
|
19145
|
+
},
|
|
19146
|
+
fact_type: input.factType,
|
|
19147
|
+
geohash: input.geohash,
|
|
19148
|
+
visibility: "private",
|
|
19149
|
+
twin_opt_in: false
|
|
19150
|
+
};
|
|
19151
|
+
};
|
|
19152
|
+
const created = (records, inputs) => {
|
|
19153
|
+
records.forEach((record2, i) => {
|
|
19154
|
+
if (inputs[i].embedding === void 0) embedInBackground(record2);
|
|
19155
|
+
});
|
|
19156
|
+
notify("membership", records);
|
|
19157
|
+
return records.map((record2) => stored(record2.memory));
|
|
19158
|
+
};
|
|
19159
|
+
const asStored = (record2) => record2 ? stored(record2.memory) : null;
|
|
19160
|
+
const everyState = {
|
|
19161
|
+
include_deleted: true,
|
|
19162
|
+
include_archived: true,
|
|
19163
|
+
include_quarantined: true,
|
|
19164
|
+
include_superseded: true
|
|
19165
|
+
};
|
|
19166
|
+
const changesSince = async (cursor2, pending2) => {
|
|
19167
|
+
const records = [];
|
|
19168
|
+
const failed = /* @__PURE__ */ new Set();
|
|
19169
|
+
const collect = (page) => {
|
|
19170
|
+
warnFailed(page.failed);
|
|
19171
|
+
records.push(...page.items);
|
|
19172
|
+
for (const failure of page.failed) failed.add(failure.memory_id);
|
|
19173
|
+
};
|
|
19174
|
+
let resume = cursor2;
|
|
19175
|
+
let next;
|
|
19176
|
+
do {
|
|
19177
|
+
const page = await persistence.query({
|
|
19178
|
+
...everyState,
|
|
19179
|
+
order: "changed",
|
|
19180
|
+
limit: 200,
|
|
19181
|
+
...(next ?? resume) && { cursor: next ?? resume }
|
|
19182
|
+
});
|
|
19183
|
+
collect(page);
|
|
19184
|
+
resume = page.changes_cursor ?? resume;
|
|
19185
|
+
next = page.next_cursor;
|
|
19186
|
+
} while (next);
|
|
19187
|
+
for (const memory_ids of chunks([...pending2], MAX_QUERY_IDS)) {
|
|
19188
|
+
let retry;
|
|
19189
|
+
do {
|
|
19190
|
+
const page = await persistence.query({
|
|
19191
|
+
...everyState,
|
|
19192
|
+
memory_ids,
|
|
19193
|
+
limit: 200,
|
|
19194
|
+
...retry && { cursor: retry }
|
|
19195
|
+
});
|
|
19196
|
+
collect(page);
|
|
19197
|
+
retry = page.next_cursor;
|
|
19198
|
+
} while (retry);
|
|
19199
|
+
}
|
|
19200
|
+
return { records, resume, failed };
|
|
19201
|
+
};
|
|
19202
|
+
let generation = 0;
|
|
19203
|
+
let ready = false;
|
|
19204
|
+
let cursor;
|
|
19205
|
+
let pending = /* @__PURE__ */ new Set();
|
|
19206
|
+
let polling = false;
|
|
19207
|
+
const poll = () => {
|
|
19208
|
+
if (polling) return;
|
|
19209
|
+
polling = true;
|
|
19210
|
+
const current = generation;
|
|
19211
|
+
changesSince(cursor, pending).then(({ records, resume, failed }) => {
|
|
19212
|
+
if (current !== generation) return;
|
|
19213
|
+
const changed = /* @__PURE__ */ new Set();
|
|
19214
|
+
for (const record2 of records) {
|
|
19215
|
+
const id = record2.memory.memory_id;
|
|
19216
|
+
const previous = seen.get(id);
|
|
19217
|
+
seen.set(id, record2);
|
|
19218
|
+
if (!ready) continue;
|
|
19219
|
+
for (const subscriber of subscribers) {
|
|
19220
|
+
const before = previous && subscriptionKey(previous, subscriber.options);
|
|
19221
|
+
if (before !== subscriptionKey(record2, subscriber.options)) changed.add(subscriber);
|
|
19222
|
+
}
|
|
19223
|
+
}
|
|
19224
|
+
ready = true;
|
|
19225
|
+
cursor = resume;
|
|
19226
|
+
pending = failed;
|
|
19227
|
+
for (const subscriber of changed)
|
|
19228
|
+
if (subscribers.has(subscriber)) safely(subscriber.onChange);
|
|
19229
|
+
}).catch((error) => {
|
|
19230
|
+
getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
|
|
19231
|
+
}).finally(() => {
|
|
19232
|
+
polling = false;
|
|
19233
|
+
});
|
|
19234
|
+
};
|
|
19235
|
+
return {
|
|
19236
|
+
list: async (listOptions = {}) => {
|
|
19237
|
+
const order = listOptions.since ? "updated" : "created";
|
|
19238
|
+
const filters = {
|
|
19239
|
+
...stateFilters(listOptions),
|
|
19240
|
+
include_embeddings: true,
|
|
19241
|
+
order,
|
|
19242
|
+
...listOptions.scopes?.length && { scopes: listOptions.scopes },
|
|
19243
|
+
...listOptions.factTypes?.length && { fact_types: listOptions.factTypes },
|
|
19244
|
+
...listOptions.visibility?.length && { visibility: listOptions.visibility },
|
|
19245
|
+
...listOptions.since && { updated_after: listOptions.since.getTime() }
|
|
19246
|
+
};
|
|
19247
|
+
const max = listOptions.limit && listOptions.limit > 0 ? listOptions.limit : Infinity;
|
|
19248
|
+
const variants = bounded(filters, "scopes").flatMap((f) => bounded(f, "fact_types"));
|
|
19249
|
+
if (!listOptions.memoryIds && variants.length === 1)
|
|
19250
|
+
return (await enumerate(filters, max)).map((r) => stored(r.memory));
|
|
19251
|
+
const fetched = await Promise.all(
|
|
19252
|
+
variants.map(
|
|
19253
|
+
(variant) => listOptions.memoryIds ? enumerateIds(listOptions.memoryIds, variant) : enumerate(variant, max)
|
|
19254
|
+
)
|
|
19255
|
+
);
|
|
19256
|
+
const rows = [...new Map(fetched.flat().map((r) => [r.memory.memory_id, r])).values()].map((record2) => stored(record2.memory)).sort(
|
|
19257
|
+
(a, b) => order === "updated" ? b.updatedAt.getTime() - a.updatedAt.getTime() || (a.uniqueId < b.uniqueId ? 1 : -1) : b.createdAt.getTime() - a.createdAt.getTime() || (a.uniqueId < b.uniqueId ? 1 : -1)
|
|
19258
|
+
);
|
|
19259
|
+
return rows.slice(0, max);
|
|
19260
|
+
},
|
|
19261
|
+
get: async (id) => asStored(await live(id)),
|
|
19262
|
+
listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
|
|
19263
|
+
(record2) => stored(record2.memory)
|
|
19264
|
+
),
|
|
19265
|
+
memoriesByTopics: async (names) => {
|
|
19266
|
+
const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
|
|
19267
|
+
const out = /* @__PURE__ */ new Map();
|
|
19268
|
+
const pages = await Promise.all(
|
|
19269
|
+
chunks([...wanted], MAX_QUERY_TOPICS).map((topics) => enumerate({ topics }))
|
|
19270
|
+
);
|
|
19271
|
+
for (const { memory } of pages.flat()) {
|
|
19272
|
+
const matched = [...canonicalTopics(memory)].filter((name) => wanted.has(name));
|
|
19273
|
+
if (matched.length) out.set(memory.memory_id, new Set(matched));
|
|
19274
|
+
}
|
|
19275
|
+
return out;
|
|
19276
|
+
},
|
|
19277
|
+
topicsByMemories: async (memoryIds) => {
|
|
19278
|
+
const out = /* @__PURE__ */ new Map();
|
|
19279
|
+
for (const { memory } of await enumerateIds(memoryIds, {
|
|
19280
|
+
include_archived: true,
|
|
19281
|
+
include_superseded: true,
|
|
19282
|
+
include_quarantined: true
|
|
19283
|
+
})) {
|
|
19284
|
+
const topics = canonicalTopics(memory);
|
|
19285
|
+
if (topics.size) out.set(memory.memory_id, topics);
|
|
19286
|
+
}
|
|
19287
|
+
return out;
|
|
19288
|
+
},
|
|
19289
|
+
create: async (input) => {
|
|
19290
|
+
const record2 = await persistence.put(newRow(input), 0);
|
|
19291
|
+
return created([record2], [input])[0];
|
|
19292
|
+
},
|
|
19293
|
+
createMany: async (inputs) => {
|
|
19294
|
+
const out = [];
|
|
19295
|
+
for (const batch of chunks(inputs, MAX_BATCH)) {
|
|
19296
|
+
let records;
|
|
19297
|
+
try {
|
|
19298
|
+
records = await persistence.putMany(
|
|
19299
|
+
batch.map((input) => ({ memory: newRow(input), expectedVersion: 0 }))
|
|
19300
|
+
);
|
|
19301
|
+
} catch (error) {
|
|
19302
|
+
if (out.length === 0) throw error;
|
|
19303
|
+
throw new RemoteMemoryPartialCreateError(out, error);
|
|
19304
|
+
}
|
|
19305
|
+
out.push(...created(records, batch));
|
|
19306
|
+
}
|
|
19307
|
+
return out;
|
|
19308
|
+
},
|
|
19309
|
+
update: async (id, patch) => {
|
|
19310
|
+
const saved = await mutate(id, "edit", (memory) => {
|
|
19311
|
+
if (memory.superseded_by) return null;
|
|
19312
|
+
memory.content = patch.content;
|
|
19313
|
+
memory.updated_at = Date.now();
|
|
19314
|
+
if (patch.scope !== void 0) {
|
|
19315
|
+
memory.level = levelForScopeChange(
|
|
19316
|
+
{ level: memory.level, scope: memory.scope },
|
|
19317
|
+
patch.scope
|
|
19318
|
+
);
|
|
19319
|
+
memory.scope = patch.scope;
|
|
19320
|
+
}
|
|
19321
|
+
if (patch.factType !== void 0) memory.fact_type = patch.factType ?? void 0;
|
|
19322
|
+
if (patch.eventTime !== void 0) {
|
|
19323
|
+
memory.event_time_start = patch.eventTime?.start ?? void 0;
|
|
19324
|
+
memory.event_time_end = patch.eventTime?.end ?? void 0;
|
|
19325
|
+
memory.event_time_kind = patch.eventTime?.kind ?? void 0;
|
|
19326
|
+
}
|
|
19327
|
+
if (patch.embedding === void 0 || patch.embedding === null) {
|
|
19328
|
+
memory.embedding = [];
|
|
19329
|
+
delete memory.embedding_model;
|
|
19330
|
+
} else {
|
|
19331
|
+
memory.embedding = storedVector(JSON.parse(patch.embedding));
|
|
19332
|
+
memory.embedding_model = patch.embeddingModel ?? model;
|
|
19333
|
+
}
|
|
19334
|
+
return memory;
|
|
19335
|
+
});
|
|
19336
|
+
if (saved && patch.embedding === void 0) embedInBackground(saved);
|
|
19337
|
+
return asStored(saved);
|
|
19338
|
+
},
|
|
19339
|
+
delete: async (id) => !!await mutate(id, "membership", (memory) => ({ ...memory, is_deleted: true })),
|
|
19340
|
+
supersede: async (id, supersededById) => {
|
|
19341
|
+
if (id === supersededById) return false;
|
|
19342
|
+
const [first, second] = [id, supersededById].sort();
|
|
19343
|
+
return serialized(
|
|
19344
|
+
first,
|
|
19345
|
+
() => serialized(second, async () => {
|
|
19346
|
+
const [old, next] = await Promise.all([live(id), live(supersededById)]);
|
|
19347
|
+
if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
|
|
19348
|
+
if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
|
|
19349
|
+
const saved = await persistence.putMany([
|
|
19350
|
+
{
|
|
19351
|
+
memory: { ...old.memory, superseded_by: supersededById, superseded_at: Date.now() },
|
|
19352
|
+
expectedVersion: old
|
|
19353
|
+
},
|
|
19354
|
+
{ memory: next.memory, expectedVersion: next }
|
|
19355
|
+
]);
|
|
19356
|
+
notify("membership", saved);
|
|
19357
|
+
return true;
|
|
19358
|
+
})
|
|
19359
|
+
);
|
|
19360
|
+
},
|
|
19361
|
+
archive: async (id) => !!await mutate(
|
|
19362
|
+
id,
|
|
19363
|
+
"edit",
|
|
19364
|
+
(memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
|
|
19365
|
+
),
|
|
19366
|
+
restore: (id) => serialized(id, async () => {
|
|
19367
|
+
const record2 = await live(id);
|
|
19368
|
+
if (!record2) return false;
|
|
19369
|
+
if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
|
|
19370
|
+
return true;
|
|
19371
|
+
const { archived_at: _archivedAt, ...memory } = record2.memory;
|
|
19372
|
+
notify("edit", [await persistence.put(memory, record2)]);
|
|
19373
|
+
return true;
|
|
19374
|
+
}),
|
|
19375
|
+
setTopics: async (memoryId, topics) => asStored(
|
|
19376
|
+
await mutate(memoryId, "edit", (memory) => ({
|
|
19377
|
+
...memory,
|
|
19378
|
+
topics: serializeTopics(mergeTopics([], topicInputs(topics, "user"))),
|
|
19379
|
+
topics_user_managed: true,
|
|
19380
|
+
topics_updated_at: Date.now()
|
|
19381
|
+
}))
|
|
19382
|
+
),
|
|
19383
|
+
addTopics: async (memoryId, topics) => {
|
|
19384
|
+
const added = topicInputs(topics, "auto");
|
|
19385
|
+
const saved = await mutate(memoryId, "edit", (memory) => ({
|
|
19386
|
+
...memory,
|
|
19387
|
+
topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
|
|
19388
|
+
topics_updated_at: Date.now()
|
|
19389
|
+
}));
|
|
19390
|
+
if (!saved) return [];
|
|
19391
|
+
const now = /* @__PURE__ */ new Date();
|
|
19392
|
+
return mergeTopics([], added).map(
|
|
19393
|
+
(topic) => ({
|
|
19394
|
+
uniqueId: normalizeEntityName(topic.name),
|
|
19395
|
+
canonicalName: normalizeEntityName(topic.name),
|
|
19396
|
+
kind: topic.kind ?? null,
|
|
19397
|
+
createdAt: now,
|
|
19398
|
+
updatedAt: now
|
|
19399
|
+
})
|
|
19400
|
+
);
|
|
19401
|
+
},
|
|
19402
|
+
setVisibility: async (id, visibility, visibilityOptions) => asStored(
|
|
19403
|
+
await mutate(id, "edit", (memory) => {
|
|
19404
|
+
memory.visibility = visibility;
|
|
19405
|
+
if (visibility === "private") delete memory.published_at;
|
|
19406
|
+
else memory.published_at ?? (memory.published_at = Date.now());
|
|
19407
|
+
if (visibilityOptions?.twinOptIn !== void 0)
|
|
19408
|
+
memory.twin_opt_in = visibilityOptions.twinOptIn;
|
|
19409
|
+
return memory;
|
|
19410
|
+
})
|
|
19411
|
+
),
|
|
19412
|
+
recall: (query, recallOptions) => pipeline.recall(query, recallOptions),
|
|
19413
|
+
retain: async (content, retainOptions) => {
|
|
19414
|
+
const result = await pipeline.retain(content, retainOptions);
|
|
19415
|
+
if (result.action === "create" || result.action === "supersede") notify("membership");
|
|
19416
|
+
else if (result.action === "update" || result.action === "merge") notify("edit");
|
|
19417
|
+
return result;
|
|
19418
|
+
},
|
|
19419
|
+
subscribe: (onChange, subscribeOptions = {}) => {
|
|
19420
|
+
const subscriber = { onChange, options: subscribeOptions };
|
|
19421
|
+
subscribers.add(subscriber);
|
|
19422
|
+
if (pollIntervalMs > 0 && !timer) {
|
|
19423
|
+
timer = setInterval(poll, pollIntervalMs);
|
|
19424
|
+
poll();
|
|
19425
|
+
}
|
|
19426
|
+
return () => {
|
|
19427
|
+
subscribers.delete(subscriber);
|
|
19428
|
+
if (subscribers.size || !timer) return;
|
|
19429
|
+
clearInterval(timer);
|
|
19430
|
+
timer = void 0;
|
|
19431
|
+
generation++;
|
|
19432
|
+
seen.clear();
|
|
19433
|
+
ready = false;
|
|
19434
|
+
cursor = void 0;
|
|
19435
|
+
pending = /* @__PURE__ */ new Set();
|
|
19436
|
+
};
|
|
19437
|
+
}
|
|
19438
|
+
};
|
|
19439
|
+
}
|
|
19440
|
+
|
|
18654
19441
|
// src/lib/memory/synthesizeProfile.ts
|
|
18655
19442
|
var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
|
|
18656
19443
|
var DEFAULT_FACET_RECALL_LIMIT = 20;
|
|
@@ -22061,7 +22848,7 @@ function useChat(options) {
|
|
|
22061
22848
|
|
|
22062
22849
|
// src/expo/useChatStorage.ts
|
|
22063
22850
|
import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
|
|
22064
|
-
import { v7 as
|
|
22851
|
+
import { v7 as uuidv77 } from "uuid";
|
|
22065
22852
|
|
|
22066
22853
|
// src/lib/chat/assembleMessages.ts
|
|
22067
22854
|
function assembleMessagesWithHistory(historyMessages, callerMessages, summarySystemMessage) {
|
|
@@ -22718,9 +23505,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
|
|
|
22718
23505
|
}
|
|
22719
23506
|
|
|
22720
23507
|
// src/lib/db/media/types.ts
|
|
22721
|
-
import { v7 as
|
|
23508
|
+
import { v7 as uuidv76 } from "uuid";
|
|
22722
23509
|
function generateMediaId() {
|
|
22723
|
-
return `media_${
|
|
23510
|
+
return `media_${uuidv76()}`;
|
|
22724
23511
|
}
|
|
22725
23512
|
|
|
22726
23513
|
// src/lib/db/media/operations.ts
|
|
@@ -23676,7 +24463,7 @@ function useChatStorage(options) {
|
|
|
23676
24463
|
};
|
|
23677
24464
|
};
|
|
23678
24465
|
pendingResumeRef.current = null;
|
|
23679
|
-
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${
|
|
24466
|
+
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv77()}` : void 0);
|
|
23680
24467
|
const embedToolText = (text12, mask, masked, token) => {
|
|
23681
24468
|
const opts = {
|
|
23682
24469
|
getToken: token,
|
|
@@ -24194,7 +24981,7 @@ function useChatStorage(options) {
|
|
|
24194
24981
|
const detachedResult = result;
|
|
24195
24982
|
if (detachedResult.detached) {
|
|
24196
24983
|
recordToolSetTurn(database, convId, matchedToolSets);
|
|
24197
|
-
const rowId = effectiveAssistantUniqueId ?? `msg_${
|
|
24984
|
+
const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv77()}`;
|
|
24198
24985
|
pendingResumeRef.current = {
|
|
24199
24986
|
handle: detachedResult.resume ?? null,
|
|
24200
24987
|
convId,
|
|
@@ -24703,6 +25490,10 @@ export {
|
|
|
24703
25490
|
LoggerProvider,
|
|
24704
25491
|
MAX_HOPS,
|
|
24705
25492
|
MEDIUM_TTL_MS,
|
|
25493
|
+
MEMORY_KINDS,
|
|
25494
|
+
MEMORY_LEVELS,
|
|
25495
|
+
MemoryKeyError,
|
|
25496
|
+
MemoryLevelError,
|
|
24706
25497
|
NEVER_TTL_MS,
|
|
24707
25498
|
NODE_BUDGET,
|
|
24708
25499
|
NOTION_OAUTH_CONFIG,
|
|
@@ -24714,6 +25505,7 @@ export {
|
|
|
24714
25505
|
RECALL_MAX_LIMIT,
|
|
24715
25506
|
RECALL_TOOL_NAME,
|
|
24716
25507
|
RemoteMemoryError,
|
|
25508
|
+
RemoteMemoryPartialCreateError,
|
|
24717
25509
|
RerankerUnavailableError,
|
|
24718
25510
|
SDK_SCHEMA_VERSION,
|
|
24719
25511
|
SHORT_TTL_MS,
|
|
@@ -24779,6 +25571,7 @@ export {
|
|
|
24779
25571
|
createRecallTool,
|
|
24780
25572
|
createRemoteMemoryPersistence,
|
|
24781
25573
|
createRemoteMemoryPipeline,
|
|
25574
|
+
createRemoteMemoryStore,
|
|
24782
25575
|
createStockPricePreProcessor,
|
|
24783
25576
|
createStreamingDeAnonymizer,
|
|
24784
25577
|
createVaultEmbeddingCache,
|
|
@@ -24795,6 +25588,7 @@ export {
|
|
|
24795
25588
|
deleteVaultMemoryOp,
|
|
24796
25589
|
dequantizeEmbedding,
|
|
24797
25590
|
deriveKeyFromSignatureBytes,
|
|
25591
|
+
deriveMemoryKeyRing,
|
|
24798
25592
|
discoverNotionOAuthEndpoints,
|
|
24799
25593
|
eagerEmbedContent,
|
|
24800
25594
|
embedAllMessages,
|
|
@@ -24838,6 +25632,7 @@ export {
|
|
|
24838
25632
|
isPiiRedactor,
|
|
24839
25633
|
isRerankerAvailable,
|
|
24840
25634
|
maskScopedEmbeddingCache,
|
|
25635
|
+
memoryCipher,
|
|
24841
25636
|
moveMemoriesToFolderOp,
|
|
24842
25637
|
noopLogger,
|
|
24843
25638
|
onKeyAvailable,
|
|
@@ -24847,6 +25642,7 @@ export {
|
|
|
24847
25642
|
queueManager,
|
|
24848
25643
|
rankProfileCandidates,
|
|
24849
25644
|
recall,
|
|
25645
|
+
reencryptMemoryField,
|
|
24850
25646
|
reflect,
|
|
24851
25647
|
refreshEncryptionKeyIfMatches,
|
|
24852
25648
|
refreshNotionAccessToken,
|