@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.cjs
CHANGED
|
@@ -1399,6 +1399,7 @@ __export(index_exports, {
|
|
|
1399
1399
|
QueueManager: () => QueueManager,
|
|
1400
1400
|
RECALL_MAX_LIMIT: () => RECALL_MAX_LIMIT,
|
|
1401
1401
|
RECALL_TOOL_NAME: () => RECALL_TOOL_NAME,
|
|
1402
|
+
RemoteMemoryError: () => RemoteMemoryError,
|
|
1402
1403
|
RerankerUnavailableError: () => RerankerUnavailableError,
|
|
1403
1404
|
SDK_SCHEMA_VERSION: () => SDK_SCHEMA_VERSION,
|
|
1404
1405
|
SHORT_TTL_MS: () => SHORT_TTL_MS,
|
|
@@ -1462,6 +1463,8 @@ __export(index_exports, {
|
|
|
1462
1463
|
createNotionTools: () => createNotionTools,
|
|
1463
1464
|
createPlatformCursorStore: () => createPlatformCursorStore,
|
|
1464
1465
|
createRecallTool: () => createRecallTool,
|
|
1466
|
+
createRemoteMemoryPersistence: () => createRemoteMemoryPersistence,
|
|
1467
|
+
createRemoteMemoryPipeline: () => createRemoteMemoryPipeline,
|
|
1465
1468
|
createStockPricePreProcessor: () => createStockPricePreProcessor,
|
|
1466
1469
|
createStreamingDeAnonymizer: () => createStreamingDeAnonymizer,
|
|
1467
1470
|
createVaultEmbeddingCache: () => createVaultEmbeddingCache,
|
|
@@ -4177,13 +4180,13 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4177
4180
|
const storedById = new Map(
|
|
4178
4181
|
await Promise.all(
|
|
4179
4182
|
Array.from(uniqueMessages, async ([id, m]) => {
|
|
4180
|
-
const
|
|
4183
|
+
const stored2 = await messageRawToStored(
|
|
4181
4184
|
m,
|
|
4182
4185
|
ctx.walletAddress,
|
|
4183
4186
|
ctx.signMessage,
|
|
4184
4187
|
ctx.embeddedWalletSigner
|
|
4185
4188
|
);
|
|
4186
|
-
return [id,
|
|
4189
|
+
return [id, stored2];
|
|
4187
4190
|
})
|
|
4188
4191
|
)
|
|
4189
4192
|
);
|
|
@@ -4201,18 +4204,18 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4201
4204
|
})
|
|
4202
4205
|
);
|
|
4203
4206
|
return topK.map(({ message, similarity, chunkTextSource }) => {
|
|
4204
|
-
const
|
|
4207
|
+
const stored2 = { ...storedById.get(message.id) };
|
|
4205
4208
|
let chunkText2;
|
|
4206
4209
|
if (chunkTextSource.kind === "chunk") {
|
|
4207
|
-
chunkText2 = resolveChunkText(
|
|
4210
|
+
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
4208
4211
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
4209
4212
|
const state = chunkStateByMsgId.get(message.id);
|
|
4210
4213
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
4211
|
-
chunkText2 = resolveChunkText(
|
|
4214
|
+
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
4212
4215
|
} else {
|
|
4213
|
-
chunkText2 =
|
|
4216
|
+
chunkText2 = stored2.content;
|
|
4214
4217
|
}
|
|
4215
|
-
return { chunkText: chunkText2, message:
|
|
4218
|
+
return { chunkText: chunkText2, message: stored2, similarity };
|
|
4216
4219
|
});
|
|
4217
4220
|
}
|
|
4218
4221
|
function makeSyntheticStoredMessage(opts) {
|
|
@@ -5336,7 +5339,7 @@ async function embedOne(text12, options, outer) {
|
|
|
5336
5339
|
}
|
|
5337
5340
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
5338
5341
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
5339
|
-
async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs) {
|
|
5342
|
+
async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs, outer) {
|
|
5340
5343
|
const response = await withEmbeddingRetry(
|
|
5341
5344
|
() => withDeadline(
|
|
5342
5345
|
(signal) => postApiV1Embeddings({
|
|
@@ -5346,8 +5349,10 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
|
|
|
5346
5349
|
...signal && { signal }
|
|
5347
5350
|
}),
|
|
5348
5351
|
timeoutMs,
|
|
5349
|
-
"embedding batch request"
|
|
5350
|
-
|
|
5352
|
+
"embedding batch request",
|
|
5353
|
+
outer
|
|
5354
|
+
),
|
|
5355
|
+
outer
|
|
5351
5356
|
);
|
|
5352
5357
|
if (response.error) {
|
|
5353
5358
|
throw embeddingErrorFrom(response);
|
|
@@ -5365,6 +5370,11 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
|
|
|
5365
5370
|
}
|
|
5366
5371
|
async function generateEmbeddings(texts, options) {
|
|
5367
5372
|
if (texts.length === 0) return [];
|
|
5373
|
+
const total = options.totalTimeoutMs;
|
|
5374
|
+
if (total === void 0) return embedMany(texts, options, void 0);
|
|
5375
|
+
return withDeadline((signal) => embedMany(texts, options, signal), total, "embedding batch");
|
|
5376
|
+
}
|
|
5377
|
+
async function embedMany(texts, options, outer) {
|
|
5368
5378
|
const { baseUrl = BASE_URL, model, batchSize, cache } = options;
|
|
5369
5379
|
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
5370
5380
|
const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
|
|
@@ -5385,7 +5395,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
5385
5395
|
if (uncachedTexts.length === 0) {
|
|
5386
5396
|
return results;
|
|
5387
5397
|
}
|
|
5388
|
-
const headers = await resolveAuthHeaders(options);
|
|
5398
|
+
const headers = await resolveAuthHeaders(options, outer);
|
|
5399
|
+
if (outer?.aborted) throw outer.reason;
|
|
5389
5400
|
const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
5390
5401
|
let newEmbeddings;
|
|
5391
5402
|
if (uncachedTexts.length <= chunkSize) {
|
|
@@ -5396,7 +5407,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
5396
5407
|
embeddingModel,
|
|
5397
5408
|
options.onUsage,
|
|
5398
5409
|
options.maskInput,
|
|
5399
|
-
timeoutMs
|
|
5410
|
+
timeoutMs,
|
|
5411
|
+
outer
|
|
5400
5412
|
);
|
|
5401
5413
|
} else {
|
|
5402
5414
|
const chunks = [];
|
|
@@ -5407,6 +5419,7 @@ async function generateEmbeddings(texts, options) {
|
|
|
5407
5419
|
let nextIndex = 0;
|
|
5408
5420
|
const worker = async () => {
|
|
5409
5421
|
while (nextIndex < chunks.length) {
|
|
5422
|
+
if (outer?.aborted) throw outer.reason;
|
|
5410
5423
|
const idx = nextIndex++;
|
|
5411
5424
|
allEmbeddings[idx] = await generateEmbeddingsBatch(
|
|
5412
5425
|
chunks[idx],
|
|
@@ -5415,7 +5428,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
5415
5428
|
embeddingModel,
|
|
5416
5429
|
options.onUsage,
|
|
5417
5430
|
options.maskInput,
|
|
5418
|
-
timeoutMs
|
|
5431
|
+
timeoutMs,
|
|
5432
|
+
outer
|
|
5419
5433
|
);
|
|
5420
5434
|
}
|
|
5421
5435
|
};
|
|
@@ -5426,6 +5440,7 @@ async function generateEmbeddings(texts, options) {
|
|
|
5426
5440
|
await Promise.all(workers);
|
|
5427
5441
|
newEmbeddings = allEmbeddings.flat();
|
|
5428
5442
|
}
|
|
5443
|
+
if (outer?.aborted) throw outer.reason;
|
|
5429
5444
|
for (let i = 0; i < uncachedIndices.length; i++) {
|
|
5430
5445
|
const f32Embedding = Float32Array.from(newEmbeddings[i]);
|
|
5431
5446
|
results[uncachedIndices[i]] = Array.from(f32Embedding);
|
|
@@ -10514,15 +10529,15 @@ function createSummaryContext(database) {
|
|
|
10514
10529
|
summariesCollection: database.get("conversation_summaries")
|
|
10515
10530
|
};
|
|
10516
10531
|
}
|
|
10517
|
-
function modelToStored(
|
|
10532
|
+
function modelToStored(record2) {
|
|
10518
10533
|
return {
|
|
10519
|
-
uniqueId:
|
|
10520
|
-
conversationId:
|
|
10521
|
-
summary:
|
|
10522
|
-
summarizedUpTo:
|
|
10523
|
-
tokenCount:
|
|
10524
|
-
createdAt:
|
|
10525
|
-
updatedAt:
|
|
10534
|
+
uniqueId: record2.id,
|
|
10535
|
+
conversationId: record2.conversationId,
|
|
10536
|
+
summary: record2.summary,
|
|
10537
|
+
summarizedUpTo: record2.summarizedUpTo,
|
|
10538
|
+
tokenCount: record2.tokenCount,
|
|
10539
|
+
createdAt: record2.createdAt,
|
|
10540
|
+
updatedAt: record2.updatedAt
|
|
10526
10541
|
};
|
|
10527
10542
|
}
|
|
10528
10543
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
@@ -10531,17 +10546,17 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
10531
10546
|
return modelToStored(results[0]);
|
|
10532
10547
|
}
|
|
10533
10548
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
10534
|
-
let
|
|
10549
|
+
let record2;
|
|
10535
10550
|
await ctx.database.write(async () => {
|
|
10536
10551
|
const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
10537
10552
|
if (existing.length > 0) {
|
|
10538
|
-
|
|
10553
|
+
record2 = await existing[0].update((rec) => {
|
|
10539
10554
|
rec.summary = summary;
|
|
10540
10555
|
rec.summarizedUpTo = summarizedUpTo;
|
|
10541
10556
|
rec.tokenCount = tokenCount;
|
|
10542
10557
|
});
|
|
10543
10558
|
} else {
|
|
10544
|
-
|
|
10559
|
+
record2 = await ctx.summariesCollection.create((rec) => {
|
|
10545
10560
|
rec.conversationId = conversationId;
|
|
10546
10561
|
rec.summary = summary;
|
|
10547
10562
|
rec.summarizedUpTo = summarizedUpTo;
|
|
@@ -10549,13 +10564,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
|
|
|
10549
10564
|
});
|
|
10550
10565
|
}
|
|
10551
10566
|
});
|
|
10552
|
-
return modelToStored(
|
|
10567
|
+
return modelToStored(record2);
|
|
10553
10568
|
}
|
|
10554
10569
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
10555
10570
|
await ctx.database.write(async () => {
|
|
10556
10571
|
const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
10557
|
-
for (const
|
|
10558
|
-
await
|
|
10572
|
+
for (const record2 of existing) {
|
|
10573
|
+
await record2.destroyPermanently();
|
|
10559
10574
|
}
|
|
10560
10575
|
});
|
|
10561
10576
|
}
|
|
@@ -12056,25 +12071,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
12056
12071
|
const kindBackfills = existing.filter((e) => {
|
|
12057
12072
|
const incoming = kindByName.get(e.canonicalName);
|
|
12058
12073
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
12059
|
-
}).map((
|
|
12074
|
+
}).map((record2) => ({ record: record2, kind: kindByName.get(record2.canonicalName) }));
|
|
12060
12075
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
12061
12076
|
const created = missing.map(
|
|
12062
|
-
(name) => ctx.entityCollection.prepareCreate((
|
|
12063
|
-
|
|
12077
|
+
(name) => ctx.entityCollection.prepareCreate((record2) => {
|
|
12078
|
+
record2._setRaw("canonical_name", name);
|
|
12064
12079
|
const kind = kindByName.get(name);
|
|
12065
|
-
if (kind !== void 0)
|
|
12080
|
+
if (kind !== void 0) record2._setRaw("kind", kind);
|
|
12066
12081
|
})
|
|
12067
12082
|
);
|
|
12068
12083
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
12069
|
-
for (const
|
|
12070
|
-
for (const { record, kind } of kindBackfills) {
|
|
12071
|
-
out.set(
|
|
12084
|
+
for (const record2 of created) out.set(record2.canonicalName, entityToStored(record2));
|
|
12085
|
+
for (const { record: record2, kind } of kindBackfills) {
|
|
12086
|
+
out.set(record2.canonicalName, { ...entityToStored(record2), kind });
|
|
12072
12087
|
}
|
|
12073
12088
|
return { entities: out, operations: created, kindBackfills };
|
|
12074
12089
|
}
|
|
12075
12090
|
function prepareKindBackfills(backfills) {
|
|
12076
12091
|
return backfills.map(
|
|
12077
|
-
({ record, kind }) =>
|
|
12092
|
+
({ record: record2, kind }) => record2.prepareUpdate((r) => {
|
|
12078
12093
|
r._setRaw("kind", kind);
|
|
12079
12094
|
})
|
|
12080
12095
|
);
|
|
@@ -12105,10 +12120,10 @@ function displayNamesOf(entities) {
|
|
|
12105
12120
|
}
|
|
12106
12121
|
return out;
|
|
12107
12122
|
}
|
|
12108
|
-
function topicsEqual(
|
|
12109
|
-
if (
|
|
12123
|
+
function topicsEqual(stored2, computed) {
|
|
12124
|
+
if (stored2 === null || stored2.length !== computed.length) return false;
|
|
12110
12125
|
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
12111
|
-
const storedKeys =
|
|
12126
|
+
const storedKeys = stored2.map(key).sort();
|
|
12112
12127
|
const computedKeys = computed.map(key).sort();
|
|
12113
12128
|
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
12114
12129
|
}
|
|
@@ -12174,10 +12189,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
12174
12189
|
return;
|
|
12175
12190
|
}
|
|
12176
12191
|
const linkOps = toCreate.map(
|
|
12177
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
if (userId !== void 0)
|
|
12192
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
12193
|
+
record2._setRaw("memory_id", memoryId);
|
|
12194
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
12195
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
12181
12196
|
})
|
|
12182
12197
|
);
|
|
12183
12198
|
await ctx.database.batch(
|
|
@@ -12245,10 +12260,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
12245
12260
|
...entityOps,
|
|
12246
12261
|
...prepareKindBackfills(kindBackfills),
|
|
12247
12262
|
...toCreate.map(
|
|
12248
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
if (userId !== void 0)
|
|
12263
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
12264
|
+
record2._setRaw("memory_id", memoryId);
|
|
12265
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
12266
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
12252
12267
|
})
|
|
12253
12268
|
),
|
|
12254
12269
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
@@ -12402,8 +12417,8 @@ function visibilityConditions(requested) {
|
|
|
12402
12417
|
if (excluded.length === 0) return [];
|
|
12403
12418
|
return [import_watermelondb20.Q.or(import_watermelondb20.Q.where("visibility", null), import_watermelondb20.Q.where("visibility", import_watermelondb20.Q.notIn(excluded)))];
|
|
12404
12419
|
}
|
|
12405
|
-
function isOwnedByCtxUser(ctx,
|
|
12406
|
-
return ctx.userId === void 0 ||
|
|
12420
|
+
function isOwnedByCtxUser(ctx, record2) {
|
|
12421
|
+
return ctx.userId === void 0 || record2.userId === ctx.userId;
|
|
12407
12422
|
}
|
|
12408
12423
|
function baseVaultConditions(ctx, options) {
|
|
12409
12424
|
return [
|
|
@@ -12483,39 +12498,39 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
12483
12498
|
}
|
|
12484
12499
|
return raw;
|
|
12485
12500
|
}
|
|
12486
|
-
function populateNewVaultMemory(
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12501
|
+
function populateNewVaultMemory(record2, ctx, opts, encryptedContent) {
|
|
12502
|
+
record2._setRaw("content", encryptedContent);
|
|
12503
|
+
record2._setRaw("scope", opts.scope ?? "private");
|
|
12504
|
+
record2._setRaw("folder_id", opts.folderId ?? null);
|
|
12505
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
12506
|
+
record2._setRaw("is_deleted", false);
|
|
12492
12507
|
if (opts.embedding !== void 0) {
|
|
12493
|
-
|
|
12494
|
-
|
|
12508
|
+
record2._setRaw("embedding", opts.embedding);
|
|
12509
|
+
record2._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
12495
12510
|
}
|
|
12496
12511
|
if (opts.sourceChunkIds !== void 0) {
|
|
12497
|
-
|
|
12512
|
+
record2._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
12498
12513
|
}
|
|
12499
|
-
|
|
12500
|
-
|
|
12514
|
+
record2._setRaw("proof_count", opts.proofCount ?? 1);
|
|
12515
|
+
record2._setRaw("source", opts.source ?? "manual");
|
|
12501
12516
|
if (opts.eventTime) {
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12517
|
+
record2._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
12518
|
+
record2._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
12519
|
+
record2._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
12505
12520
|
}
|
|
12506
12521
|
if (opts.factType !== void 0) {
|
|
12507
|
-
|
|
12522
|
+
record2._setRaw("fact_type", opts.factType);
|
|
12508
12523
|
}
|
|
12509
12524
|
if (opts.trustTier !== void 0) {
|
|
12510
|
-
|
|
12525
|
+
record2._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
12511
12526
|
}
|
|
12512
|
-
|
|
12513
|
-
|
|
12527
|
+
record2._setRaw("visibility", opts.visibility ?? "private");
|
|
12528
|
+
record2._setRaw(
|
|
12514
12529
|
"published_at",
|
|
12515
12530
|
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
12516
12531
|
);
|
|
12517
12532
|
if (opts.geohash !== void 0) {
|
|
12518
|
-
|
|
12533
|
+
record2._setRaw("geohash", opts.geohash);
|
|
12519
12534
|
}
|
|
12520
12535
|
}
|
|
12521
12536
|
async function createVaultMemoryOp(ctx, opts) {
|
|
@@ -12529,7 +12544,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
12529
12544
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
12530
12545
|
throw new Error("Memory source is no longer eligible");
|
|
12531
12546
|
return ctx.vaultMemoryCollection.create(
|
|
12532
|
-
(
|
|
12547
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
|
|
12533
12548
|
);
|
|
12534
12549
|
});
|
|
12535
12550
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
@@ -12554,7 +12569,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
12554
12569
|
}
|
|
12555
12570
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
12556
12571
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
12557
|
-
(
|
|
12572
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
|
|
12558
12573
|
);
|
|
12559
12574
|
await target.update((r) => {
|
|
12560
12575
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -12636,7 +12651,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
12636
12651
|
throw new Error("Memory source is no longer eligible");
|
|
12637
12652
|
const prepared = optionsArray.map(
|
|
12638
12653
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
12639
|
-
(
|
|
12654
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i])
|
|
12640
12655
|
)
|
|
12641
12656
|
);
|
|
12642
12657
|
await ctx.database.batch(...prepared);
|
|
@@ -12644,16 +12659,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
12644
12659
|
});
|
|
12645
12660
|
return Promise.all(
|
|
12646
12661
|
created.map(
|
|
12647
|
-
(
|
|
12662
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
12648
12663
|
)
|
|
12649
12664
|
);
|
|
12650
12665
|
}
|
|
12651
12666
|
async function getVaultMemoryOp(ctx, id) {
|
|
12652
12667
|
try {
|
|
12653
|
-
const
|
|
12654
|
-
if (
|
|
12668
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
12669
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
12655
12670
|
return vaultMemoryToStored(
|
|
12656
|
-
|
|
12671
|
+
record2,
|
|
12657
12672
|
ctx.walletAddress,
|
|
12658
12673
|
ctx.signMessage,
|
|
12659
12674
|
ctx.embeddedWalletSigner
|
|
@@ -12711,11 +12726,11 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
12711
12726
|
};
|
|
12712
12727
|
}
|
|
12713
12728
|
async function vaultMemoryRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner) {
|
|
12714
|
-
const
|
|
12729
|
+
const stored2 = vaultMemoryRawToStoredRaw(raw);
|
|
12715
12730
|
if (walletAddress) {
|
|
12716
|
-
return decryptVaultMemoryFields(
|
|
12731
|
+
return decryptVaultMemoryFields(stored2, walletAddress, signMessage, embeddedWalletSigner);
|
|
12717
12732
|
}
|
|
12718
|
-
return
|
|
12733
|
+
return stored2;
|
|
12719
12734
|
}
|
|
12720
12735
|
async function getAllVaultMemoriesOp(ctx, options) {
|
|
12721
12736
|
const conditions = [
|
|
@@ -12867,13 +12882,13 @@ async function getVaultMemoriesByIdsOp(ctx, ids, options) {
|
|
|
12867
12882
|
async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
12868
12883
|
const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, options)).unsafeFetchRaw();
|
|
12869
12884
|
return mapInBatches(results, async (raw) => {
|
|
12870
|
-
const
|
|
12885
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
12871
12886
|
raw,
|
|
12872
12887
|
ctx.walletAddress,
|
|
12873
12888
|
ctx.signMessage,
|
|
12874
12889
|
ctx.embeddedWalletSigner
|
|
12875
12890
|
);
|
|
12876
|
-
return
|
|
12891
|
+
return stored2.content;
|
|
12877
12892
|
});
|
|
12878
12893
|
}
|
|
12879
12894
|
async function countActiveVaultMemoriesOp(ctx) {
|
|
@@ -12895,12 +12910,12 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12895
12910
|
ctx.embeddedWalletSigner
|
|
12896
12911
|
) : opts.content;
|
|
12897
12912
|
let stale = false;
|
|
12898
|
-
const
|
|
12899
|
-
const originalUpdatedAt =
|
|
12913
|
+
const record2 = probe;
|
|
12914
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12900
12915
|
await ctx.database.write(async () => {
|
|
12901
12916
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
12902
12917
|
throw new Error("Memory source is no longer eligible");
|
|
12903
|
-
if (
|
|
12918
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
12904
12919
|
stale = true;
|
|
12905
12920
|
return;
|
|
12906
12921
|
}
|
|
@@ -12908,14 +12923,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12908
12923
|
let replayedObservation = false;
|
|
12909
12924
|
if (opts.observationSourceIds?.length) {
|
|
12910
12925
|
try {
|
|
12911
|
-
const parsed = JSON.parse(
|
|
12926
|
+
const parsed = JSON.parse(record2.sourceChunkIds ?? "[]");
|
|
12912
12927
|
if (Array.isArray(parsed))
|
|
12913
12928
|
observedSources = parsed.filter((id2) => typeof id2 === "string");
|
|
12914
12929
|
} catch {
|
|
12915
12930
|
}
|
|
12916
12931
|
replayedObservation = opts.observationSourceIds.every((id2) => observedSources.includes(id2));
|
|
12917
12932
|
}
|
|
12918
|
-
await
|
|
12933
|
+
await record2.update((r) => {
|
|
12919
12934
|
r._setRaw("content", encryptedContent);
|
|
12920
12935
|
if (opts.scope !== void 0) {
|
|
12921
12936
|
r._setRaw("scope", opts.scope);
|
|
@@ -12972,7 +12987,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12972
12987
|
});
|
|
12973
12988
|
if (stale) return null;
|
|
12974
12989
|
return vaultMemoryToStored(
|
|
12975
|
-
|
|
12990
|
+
record2,
|
|
12976
12991
|
ctx.walletAddress,
|
|
12977
12992
|
ctx.signMessage,
|
|
12978
12993
|
ctx.embeddedWalletSigner
|
|
@@ -12986,21 +13001,21 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
12986
13001
|
if (!entityCtx) {
|
|
12987
13002
|
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
12988
13003
|
}
|
|
12989
|
-
let
|
|
13004
|
+
let record2;
|
|
12990
13005
|
try {
|
|
12991
|
-
|
|
13006
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
12992
13007
|
} catch {
|
|
12993
13008
|
return null;
|
|
12994
13009
|
}
|
|
12995
|
-
if (
|
|
13010
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
12996
13011
|
let stale = false;
|
|
12997
|
-
const originalUpdatedAt =
|
|
13012
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12998
13013
|
await ctx.database.write(async (writer) => {
|
|
12999
|
-
if (
|
|
13014
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13000
13015
|
stale = true;
|
|
13001
13016
|
return;
|
|
13002
13017
|
}
|
|
13003
|
-
await
|
|
13018
|
+
await record2.update((r) => {
|
|
13004
13019
|
r._setRaw("topics_user_managed", true);
|
|
13005
13020
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
13006
13021
|
});
|
|
@@ -13024,25 +13039,25 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
13024
13039
|
);
|
|
13025
13040
|
});
|
|
13026
13041
|
if (stale) return null;
|
|
13027
|
-
return vaultMemoryToStored(
|
|
13042
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
13028
13043
|
}
|
|
13029
13044
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
13030
|
-
let
|
|
13045
|
+
let record2;
|
|
13031
13046
|
try {
|
|
13032
|
-
|
|
13047
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
13033
13048
|
} catch {
|
|
13034
13049
|
return false;
|
|
13035
13050
|
}
|
|
13036
|
-
if (
|
|
13037
|
-
const originalUpdatedAt =
|
|
13051
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13052
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13038
13053
|
let cleared = false;
|
|
13039
13054
|
await ctx.database.write(async () => {
|
|
13040
|
-
if (options?.unlessTopicsRecorded && parseTopics(
|
|
13055
|
+
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
13041
13056
|
cleared = true;
|
|
13042
|
-
await
|
|
13057
|
+
await record2.update((r) => {
|
|
13043
13058
|
r._setRaw("topics_user_managed", false);
|
|
13044
13059
|
r._setRaw("topics_extracted_version", null);
|
|
13045
|
-
if (
|
|
13060
|
+
if (record2.topicsExtractedAt === null) {
|
|
13046
13061
|
r._setRaw("topics_extracted_at", originalUpdatedAt);
|
|
13047
13062
|
}
|
|
13048
13063
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -13051,22 +13066,22 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
13051
13066
|
return cleared;
|
|
13052
13067
|
}
|
|
13053
13068
|
async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
13054
|
-
let
|
|
13069
|
+
let record2;
|
|
13055
13070
|
try {
|
|
13056
|
-
|
|
13071
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13057
13072
|
} catch {
|
|
13058
13073
|
return null;
|
|
13059
13074
|
}
|
|
13060
|
-
if (
|
|
13075
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
13061
13076
|
let stale = false;
|
|
13062
13077
|
await ctx.database.write(async () => {
|
|
13063
|
-
if (
|
|
13078
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13064
13079
|
stale = true;
|
|
13065
13080
|
return;
|
|
13066
13081
|
}
|
|
13067
|
-
const currentUpdatedAt =
|
|
13068
|
-
const currentPublishedAt =
|
|
13069
|
-
await
|
|
13082
|
+
const currentUpdatedAt = record2.updatedAt.getTime();
|
|
13083
|
+
const currentPublishedAt = record2.publishedAt ?? null;
|
|
13084
|
+
await record2.update((r) => {
|
|
13070
13085
|
r._setRaw("visibility", opts.visibility);
|
|
13071
13086
|
if (opts.visibility === "private") {
|
|
13072
13087
|
r._setRaw("published_at", null);
|
|
@@ -13080,19 +13095,19 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
13080
13095
|
});
|
|
13081
13096
|
});
|
|
13082
13097
|
if (stale) return null;
|
|
13083
|
-
return vaultMemoryToStored(
|
|
13098
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
13084
13099
|
}
|
|
13085
13100
|
async function deleteVaultMemoryOp(ctx, id) {
|
|
13086
13101
|
try {
|
|
13087
|
-
const
|
|
13088
|
-
if (
|
|
13102
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13103
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13089
13104
|
let stale = false;
|
|
13090
13105
|
await ctx.database.write(async () => {
|
|
13091
|
-
if (
|
|
13106
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13092
13107
|
stale = true;
|
|
13093
13108
|
return;
|
|
13094
13109
|
}
|
|
13095
|
-
await
|
|
13110
|
+
await record2.update((r) => {
|
|
13096
13111
|
r._setRaw("is_deleted", true);
|
|
13097
13112
|
});
|
|
13098
13113
|
});
|
|
@@ -13111,8 +13126,8 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
13111
13126
|
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
13112
13127
|
if (id === supersededById) return false;
|
|
13113
13128
|
try {
|
|
13114
|
-
const
|
|
13115
|
-
if (
|
|
13129
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13130
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13116
13131
|
let successor;
|
|
13117
13132
|
try {
|
|
13118
13133
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -13126,7 +13141,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
13126
13141
|
await ctx.database.write(async () => {
|
|
13127
13142
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
13128
13143
|
throw new Error("Memory source is no longer eligible");
|
|
13129
|
-
if (
|
|
13144
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
13130
13145
|
stale = true;
|
|
13131
13146
|
return;
|
|
13132
13147
|
}
|
|
@@ -13134,7 +13149,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
13134
13149
|
stale = true;
|
|
13135
13150
|
return;
|
|
13136
13151
|
}
|
|
13137
|
-
await
|
|
13152
|
+
await record2.update((r) => {
|
|
13138
13153
|
r._setRaw("superseded_by", supersededById);
|
|
13139
13154
|
r._setRaw("superseded_at", Date.now());
|
|
13140
13155
|
});
|
|
@@ -13153,7 +13168,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
13153
13168
|
const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
|
|
13154
13169
|
return mapInBatches(
|
|
13155
13170
|
results,
|
|
13156
|
-
(
|
|
13171
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
13157
13172
|
);
|
|
13158
13173
|
}
|
|
13159
13174
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
@@ -13295,17 +13310,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
13295
13310
|
}
|
|
13296
13311
|
}
|
|
13297
13312
|
const eligible = records.filter(
|
|
13298
|
-
(
|
|
13313
|
+
(record2) => !record2.isDeleted && isOwnedByCtxUser(ctx, record2) && !record2.topicsUserManaged
|
|
13299
13314
|
);
|
|
13300
|
-
const prepared = eligible.map((
|
|
13301
|
-
const originalUpdatedAt =
|
|
13302
|
-
return
|
|
13315
|
+
const prepared = eligible.map((record2) => {
|
|
13316
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13317
|
+
return record2.prepareUpdate((r) => {
|
|
13303
13318
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
13304
13319
|
r._setRaw("topics_extracted_version", version);
|
|
13305
13320
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
13306
13321
|
});
|
|
13307
13322
|
});
|
|
13308
|
-
for (const
|
|
13323
|
+
for (const record2 of eligible) stamped.push(record2.id);
|
|
13309
13324
|
if (prepared.length > 0) await ctx.database.batch(...prepared);
|
|
13310
13325
|
});
|
|
13311
13326
|
}
|
|
@@ -13320,14 +13335,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
13320
13335
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
13321
13336
|
try {
|
|
13322
13337
|
await ctx.database.write(async (writer) => {
|
|
13323
|
-
let
|
|
13338
|
+
let record2;
|
|
13324
13339
|
try {
|
|
13325
|
-
|
|
13340
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13326
13341
|
} catch {
|
|
13327
13342
|
return;
|
|
13328
13343
|
}
|
|
13329
|
-
if (
|
|
13330
|
-
const topics = parseTopics(
|
|
13344
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
13345
|
+
const topics = parseTopics(record2.topics);
|
|
13331
13346
|
if (topics === null) return;
|
|
13332
13347
|
await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics));
|
|
13333
13348
|
relinked.push(id);
|
|
@@ -13352,20 +13367,20 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
13352
13367
|
await ctx.database.write(async () => {
|
|
13353
13368
|
const writes = [];
|
|
13354
13369
|
for (const id of chunkIds) {
|
|
13355
|
-
let
|
|
13370
|
+
let record2;
|
|
13356
13371
|
try {
|
|
13357
|
-
|
|
13372
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13358
13373
|
} catch {
|
|
13359
13374
|
continue;
|
|
13360
13375
|
}
|
|
13361
|
-
if (
|
|
13362
|
-
if (parseTopics(
|
|
13376
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) continue;
|
|
13377
|
+
if (parseTopics(record2.topics) !== null) continue;
|
|
13363
13378
|
const links = await entityCtx.memoryEntityCollection.query(import_watermelondb20.Q.where("memory_id", id)).unsafeFetchRaw();
|
|
13364
13379
|
const entityIds = links.map((l) => String(l.entity_id));
|
|
13365
13380
|
if (entityIds.length === 0) continue;
|
|
13366
13381
|
const entities = await entityCtx.entityCollection.query(import_watermelondb20.Q.where("id", import_watermelondb20.Q.oneOf(entityIds))).fetch();
|
|
13367
13382
|
if (entities.length === 0) continue;
|
|
13368
|
-
const source =
|
|
13383
|
+
const source = record2.topicsUserManaged ? "user" : "auto";
|
|
13369
13384
|
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
13370
13385
|
if (write) writes.push(write);
|
|
13371
13386
|
}
|
|
@@ -13383,7 +13398,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
13383
13398
|
if (records.length === 0) return 0;
|
|
13384
13399
|
await ctx.database.write(async () => {
|
|
13385
13400
|
const prepared = records.map(
|
|
13386
|
-
(
|
|
13401
|
+
(record2) => record2.prepareUpdate((r) => {
|
|
13387
13402
|
r._setRaw("is_deleted", true);
|
|
13388
13403
|
})
|
|
13389
13404
|
);
|
|
@@ -13428,20 +13443,20 @@ async function getDecayCandidatesRawOp(ctx) {
|
|
|
13428
13443
|
}
|
|
13429
13444
|
async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
13430
13445
|
try {
|
|
13431
|
-
const
|
|
13432
|
-
if (
|
|
13446
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13447
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13433
13448
|
let stale = false;
|
|
13434
13449
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
13435
13450
|
await ctx.database.write(async () => {
|
|
13436
|
-
if (
|
|
13451
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
13437
13452
|
stale = true;
|
|
13438
13453
|
return;
|
|
13439
13454
|
}
|
|
13440
|
-
if (opts?.expectedUpdatedAt !== void 0 &&
|
|
13455
|
+
if (opts?.expectedUpdatedAt !== void 0 && record2.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record2.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
|
|
13441
13456
|
stale = true;
|
|
13442
13457
|
return;
|
|
13443
13458
|
}
|
|
13444
|
-
await
|
|
13459
|
+
await record2.update((r) => {
|
|
13445
13460
|
r._setRaw("archived_at", archivedAtValue);
|
|
13446
13461
|
});
|
|
13447
13462
|
});
|
|
@@ -13452,15 +13467,15 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
13452
13467
|
}
|
|
13453
13468
|
async function restoreVaultMemoryOp(ctx, id) {
|
|
13454
13469
|
try {
|
|
13455
|
-
const
|
|
13456
|
-
if (
|
|
13470
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13471
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13457
13472
|
let stale = false;
|
|
13458
13473
|
await ctx.database.write(async () => {
|
|
13459
|
-
if (
|
|
13474
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13460
13475
|
stale = true;
|
|
13461
13476
|
return;
|
|
13462
13477
|
}
|
|
13463
|
-
await
|
|
13478
|
+
await record2.update((r) => {
|
|
13464
13479
|
r._setRaw("archived_at", null);
|
|
13465
13480
|
});
|
|
13466
13481
|
});
|
|
@@ -13471,17 +13486,17 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
13471
13486
|
}
|
|
13472
13487
|
async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
13473
13488
|
try {
|
|
13474
|
-
const
|
|
13475
|
-
if (
|
|
13489
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13490
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13476
13491
|
const now = opts.now ?? Date.now();
|
|
13477
13492
|
let stale = false;
|
|
13478
13493
|
await ctx.database.write(async () => {
|
|
13479
|
-
const archivedAt =
|
|
13480
|
-
if (
|
|
13494
|
+
const archivedAt = record2.archivedAt;
|
|
13495
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
13481
13496
|
stale = true;
|
|
13482
13497
|
return;
|
|
13483
13498
|
}
|
|
13484
|
-
await
|
|
13499
|
+
await record2.update((r) => {
|
|
13485
13500
|
r._setRaw("is_deleted", true);
|
|
13486
13501
|
});
|
|
13487
13502
|
});
|
|
@@ -13499,14 +13514,14 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
13499
13514
|
}
|
|
13500
13515
|
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
13501
13516
|
try {
|
|
13502
|
-
const
|
|
13503
|
-
if (
|
|
13504
|
-
const readUpdatedAt =
|
|
13505
|
-
const readStoredContent =
|
|
13517
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13518
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13519
|
+
const readUpdatedAt = record2.updatedAt.getTime();
|
|
13520
|
+
const readStoredContent = record2._getRaw("content");
|
|
13506
13521
|
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
13507
13522
|
if (expected?.content !== void 0) {
|
|
13508
13523
|
const current = await vaultMemoryToStored(
|
|
13509
|
-
|
|
13524
|
+
record2,
|
|
13510
13525
|
ctx.walletAddress,
|
|
13511
13526
|
ctx.signMessage,
|
|
13512
13527
|
ctx.embeddedWalletSigner
|
|
@@ -13515,11 +13530,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
13515
13530
|
}
|
|
13516
13531
|
let written = false;
|
|
13517
13532
|
await ctx.database.write(async () => {
|
|
13518
|
-
if (
|
|
13519
|
-
const originalUpdatedAt =
|
|
13520
|
-
if (originalUpdatedAt !== readUpdatedAt ||
|
|
13533
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
13534
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13535
|
+
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
13521
13536
|
return;
|
|
13522
|
-
await
|
|
13537
|
+
await record2.update((r) => {
|
|
13523
13538
|
r._setRaw("embedding", embedding);
|
|
13524
13539
|
r._setRaw("embedding_model", embeddingModel);
|
|
13525
13540
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -13534,8 +13549,8 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
13534
13549
|
function normalizeForDedupe(content) {
|
|
13535
13550
|
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
13536
13551
|
}
|
|
13537
|
-
async function findQuarantinedDuplicateOp(ctx, content,
|
|
13538
|
-
const wanted = [...new Set(
|
|
13552
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds2, where) {
|
|
13553
|
+
const wanted = [...new Set(sourceIds2)].sort().join("\0");
|
|
13539
13554
|
const target = normalizeForDedupe(content);
|
|
13540
13555
|
const rows = await ctx.vaultMemoryCollection.query(
|
|
13541
13556
|
import_watermelondb20.Q.where("trust_tier", "quarantined"),
|
|
@@ -13554,13 +13569,13 @@ async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
|
13554
13569
|
if (!Array.isArray(ids)) continue;
|
|
13555
13570
|
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
13556
13571
|
if (key !== wanted) continue;
|
|
13557
|
-
const
|
|
13572
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
13558
13573
|
raw,
|
|
13559
13574
|
ctx.walletAddress,
|
|
13560
13575
|
ctx.signMessage,
|
|
13561
13576
|
ctx.embeddedWalletSigner
|
|
13562
13577
|
);
|
|
13563
|
-
if (normalizeForDedupe(
|
|
13578
|
+
if (normalizeForDedupe(stored2.content) === target) return stored2.uniqueId;
|
|
13564
13579
|
}
|
|
13565
13580
|
return null;
|
|
13566
13581
|
}
|
|
@@ -13670,25 +13685,25 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
13670
13685
|
inserted = writable.length;
|
|
13671
13686
|
if (writable.length === 0) return;
|
|
13672
13687
|
const prepared = writable.map(
|
|
13673
|
-
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13688
|
+
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record2) => {
|
|
13689
|
+
record2._raw.id = row.memoryId;
|
|
13690
|
+
record2._setRaw("content", content);
|
|
13691
|
+
record2._setRaw("scope", "shared");
|
|
13692
|
+
record2._setRaw("folder_id", null);
|
|
13693
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
13694
|
+
record2._setRaw("is_deleted", false);
|
|
13695
|
+
record2._setRaw("proof_count", 1);
|
|
13696
|
+
record2._setRaw("source", SOURCE_PHOTO);
|
|
13697
|
+
record2._setRaw(
|
|
13683
13698
|
"media",
|
|
13684
13699
|
row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
|
|
13685
13700
|
);
|
|
13686
|
-
|
|
13687
|
-
|
|
13701
|
+
record2._setRaw("visibility", "public");
|
|
13702
|
+
record2._setRaw("published_at", now);
|
|
13688
13703
|
if (row.eventTime) {
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13704
|
+
record2._setRaw("event_time_start", row.eventTime.start ?? null);
|
|
13705
|
+
record2._setRaw("event_time_end", row.eventTime.end ?? null);
|
|
13706
|
+
record2._setRaw("event_time_kind", row.eventTime.kind ?? null);
|
|
13692
13707
|
}
|
|
13693
13708
|
})
|
|
13694
13709
|
);
|
|
@@ -14053,11 +14068,11 @@ function folderToStored(folder) {
|
|
|
14053
14068
|
}
|
|
14054
14069
|
async function createVaultFolderOp(ctx, opts) {
|
|
14055
14070
|
const created = await ctx.database.write(async () => {
|
|
14056
|
-
return ctx.vaultFolderCollection.create((
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14071
|
+
return ctx.vaultFolderCollection.create((record2) => {
|
|
14072
|
+
record2._setRaw("name", opts.name);
|
|
14073
|
+
record2._setRaw("scope", opts.scope ?? "private");
|
|
14074
|
+
record2._setRaw("is_system", opts.isSystem ?? false);
|
|
14075
|
+
record2._setRaw("is_deleted", false);
|
|
14061
14076
|
});
|
|
14062
14077
|
});
|
|
14063
14078
|
return folderToStored(created);
|
|
@@ -14068,14 +14083,14 @@ async function getAllVaultFoldersOp(ctx) {
|
|
|
14068
14083
|
}
|
|
14069
14084
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
14070
14085
|
try {
|
|
14071
|
-
const
|
|
14072
|
-
if (
|
|
14073
|
-
const scopeChanged = opts.scope !== void 0 && opts.scope !==
|
|
14086
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
14087
|
+
if (record2.isDeleted) return null;
|
|
14088
|
+
const scopeChanged = opts.scope !== void 0 && opts.scope !== record2.scope;
|
|
14074
14089
|
const updated = await ctx.database.write(async () => {
|
|
14075
14090
|
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.where("folder_id", id), import_watermelondb21.Q.where("is_deleted", false)).fetch() : [];
|
|
14076
14091
|
const updates = [];
|
|
14077
14092
|
updates.push(
|
|
14078
|
-
|
|
14093
|
+
record2.prepareUpdate((r) => {
|
|
14079
14094
|
if (opts.name !== void 0) r._setRaw("name", opts.name);
|
|
14080
14095
|
if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
|
|
14081
14096
|
})
|
|
@@ -14097,8 +14112,8 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
14097
14112
|
}
|
|
14098
14113
|
async function deleteVaultFolderOp(ctx, id) {
|
|
14099
14114
|
try {
|
|
14100
|
-
const
|
|
14101
|
-
if (
|
|
14115
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
14116
|
+
if (record2.isDeleted) return false;
|
|
14102
14117
|
await ctx.database.write(async () => {
|
|
14103
14118
|
const memories = await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.where("folder_id", id), import_watermelondb21.Q.where("is_deleted", false)).fetch();
|
|
14104
14119
|
const preparedMemories = memories.map(
|
|
@@ -14107,7 +14122,7 @@ async function deleteVaultFolderOp(ctx, id) {
|
|
|
14107
14122
|
r._setRaw("scope", "private");
|
|
14108
14123
|
})
|
|
14109
14124
|
);
|
|
14110
|
-
const preparedFolder =
|
|
14125
|
+
const preparedFolder = record2.prepareUpdate((r) => {
|
|
14111
14126
|
r._setRaw("is_deleted", true);
|
|
14112
14127
|
});
|
|
14113
14128
|
await ctx.database.batch(...preparedMemories, preparedFolder);
|
|
@@ -14153,11 +14168,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
14153
14168
|
}
|
|
14154
14169
|
async function updateVaultFolderContextOp(ctx, id, context) {
|
|
14155
14170
|
try {
|
|
14156
|
-
const
|
|
14157
|
-
if (
|
|
14171
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
14172
|
+
if (record2.isDeleted) return null;
|
|
14158
14173
|
const updated = await ctx.database.write(async () => {
|
|
14159
14174
|
await ctx.database.batch(
|
|
14160
|
-
|
|
14175
|
+
record2.prepareUpdate((r) => {
|
|
14161
14176
|
r._setRaw("context", context);
|
|
14162
14177
|
})
|
|
14163
14178
|
);
|
|
@@ -16235,7 +16250,7 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
16235
16250
|
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
16236
16251
|
let subEmbeddings;
|
|
16237
16252
|
try {
|
|
16238
|
-
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
16253
|
+
subEmbeddings = prepared.facetEmbeddings ?? await generateEmbeddings(facetQueries, embeddingOptions);
|
|
16239
16254
|
} catch (err) {
|
|
16240
16255
|
getLogger().warn(
|
|
16241
16256
|
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
@@ -16421,6 +16436,35 @@ var DEFAULT_SCOPE = "private";
|
|
|
16421
16436
|
var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
|
|
16422
16437
|
var DEFAULT_CONSOLIDATE_TOP_K = 20;
|
|
16423
16438
|
async function retain(content, ctx, options = {}) {
|
|
16439
|
+
return retainWithPersistence(
|
|
16440
|
+
content,
|
|
16441
|
+
{
|
|
16442
|
+
embeddingOptions: ctx.embeddingOptions,
|
|
16443
|
+
vaultCache: ctx.vaultCache,
|
|
16444
|
+
persistence: {
|
|
16445
|
+
prepare: (query, searchOptions) => prepareVaultCandidates(
|
|
16446
|
+
query,
|
|
16447
|
+
ctx.vaultCtx,
|
|
16448
|
+
ctx.embeddingOptions,
|
|
16449
|
+
ctx.vaultCache,
|
|
16450
|
+
searchOptions
|
|
16451
|
+
),
|
|
16452
|
+
get: (id) => getVaultMemoryOp(ctx.vaultCtx, id),
|
|
16453
|
+
tombstones: (_embedding, _model, scope, folderId) => getAllVaultMemoriesOp(ctx.vaultCtx, {
|
|
16454
|
+
includeDeleted: true,
|
|
16455
|
+
scopes: [scope],
|
|
16456
|
+
...folderId !== void 0 && { folderId }
|
|
16457
|
+
}),
|
|
16458
|
+
create: (input) => createVaultMemoryOp(ctx.vaultCtx, input),
|
|
16459
|
+
update: (id, patch) => updateVaultMemoryOp(ctx.vaultCtx, id, patch),
|
|
16460
|
+
supersede: (id, successor) => supersedeVaultMemoryOp(ctx.vaultCtx, id, successor),
|
|
16461
|
+
createSuperseding: (input, target) => createSupersedingMemoryOp(ctx.vaultCtx, input, target)
|
|
16462
|
+
}
|
|
16463
|
+
},
|
|
16464
|
+
options
|
|
16465
|
+
);
|
|
16466
|
+
}
|
|
16467
|
+
async function retainWithPersistence(content, ctx, options = {}) {
|
|
16424
16468
|
const trimmed = content.trim();
|
|
16425
16469
|
if (trimmed.length === 0) {
|
|
16426
16470
|
throw new Error("retain: content cannot be empty");
|
|
@@ -16433,19 +16477,13 @@ async function retain(content, ctx, options = {}) {
|
|
|
16433
16477
|
let supersedeContent;
|
|
16434
16478
|
let prepared;
|
|
16435
16479
|
if (enableAutoMerge) {
|
|
16436
|
-
prepared = await
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
{
|
|
16442
|
-
|
|
16443
|
-
useFusion: false,
|
|
16444
|
-
scopes: [resolvedScope],
|
|
16445
|
-
includeArchived: true,
|
|
16446
|
-
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
16447
|
-
}
|
|
16448
|
-
);
|
|
16480
|
+
prepared = await ctx.persistence.prepare(trimmed, {
|
|
16481
|
+
limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
|
|
16482
|
+
useFusion: false,
|
|
16483
|
+
scopes: [resolvedScope],
|
|
16484
|
+
includeArchived: true,
|
|
16485
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
16486
|
+
});
|
|
16449
16487
|
if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
|
|
16450
16488
|
throw new Error(
|
|
16451
16489
|
"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."
|
|
@@ -16476,7 +16514,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16476
16514
|
);
|
|
16477
16515
|
if (matches.length > 0) {
|
|
16478
16516
|
const targetId = matches[0].uniqueId;
|
|
16479
|
-
const existing = await
|
|
16517
|
+
const existing = await ctx.persistence.get(targetId);
|
|
16480
16518
|
if (existing && !existing.supersededBy) {
|
|
16481
16519
|
const mergedSourceIds = unionStrings(
|
|
16482
16520
|
existing.sourceChunkIds ?? [],
|
|
@@ -16485,7 +16523,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16485
16523
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
16486
16524
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
16487
16525
|
const resurrect = resurrectFields(existing);
|
|
16488
|
-
const updated = await
|
|
16526
|
+
const updated = await ctx.persistence.update(targetId, {
|
|
16489
16527
|
content: existing.content,
|
|
16490
16528
|
proofCountIncrement: 1,
|
|
16491
16529
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -16512,7 +16550,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
16512
16550
|
}
|
|
16513
16551
|
const contentToWrite = supersedeContent ?? trimmed;
|
|
16514
16552
|
const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
|
|
16515
|
-
const
|
|
16553
|
+
const generatedEmbedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
16554
|
+
const embedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
16516
16555
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
16517
16556
|
if (options.respectTombstones) {
|
|
16518
16557
|
const tombstone = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -16552,8 +16591,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16552
16591
|
};
|
|
16553
16592
|
if (supersedeTargetIds.length > 0) {
|
|
16554
16593
|
const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
|
|
16555
|
-
const { created: created2, retired } = await
|
|
16556
|
-
ctx.vaultCtx,
|
|
16594
|
+
const { created: created2, retired } = await ctx.persistence.createSuperseding(
|
|
16557
16595
|
createOpts,
|
|
16558
16596
|
primaryTargetId
|
|
16559
16597
|
);
|
|
@@ -16569,11 +16607,11 @@ async function retain(content, ctx, options = {}) {
|
|
|
16569
16607
|
for (const staleId of restTargetIds) {
|
|
16570
16608
|
let ok = false;
|
|
16571
16609
|
try {
|
|
16572
|
-
ok = await
|
|
16610
|
+
ok = await ctx.persistence.supersede(staleId, created2.uniqueId) === true;
|
|
16573
16611
|
} catch {
|
|
16574
16612
|
}
|
|
16575
16613
|
if (ok) continue;
|
|
16576
|
-
const stillLive = await
|
|
16614
|
+
const stillLive = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(staleId) : ctx.persistence.get(staleId)).catch(() => null);
|
|
16577
16615
|
if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
|
|
16578
16616
|
}
|
|
16579
16617
|
if (liveLeftovers.length > 0) {
|
|
@@ -16600,7 +16638,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16600
16638
|
`supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
|
|
16601
16639
|
);
|
|
16602
16640
|
}
|
|
16603
|
-
const created = await
|
|
16641
|
+
const created = await ctx.persistence.create(createOpts);
|
|
16604
16642
|
cacheRowVector(
|
|
16605
16643
|
ctx.vaultCache,
|
|
16606
16644
|
created.uniqueId,
|
|
@@ -16619,11 +16657,7 @@ function unionStrings(a, b) {
|
|
|
16619
16657
|
return [.../* @__PURE__ */ new Set([...a, ...b])];
|
|
16620
16658
|
}
|
|
16621
16659
|
async function findTombstoneMatch(embedding, embeddingModel, scope, ctx, opts) {
|
|
16622
|
-
const rows = await
|
|
16623
|
-
includeDeleted: true,
|
|
16624
|
-
scopes: [scope],
|
|
16625
|
-
...opts.folderId !== void 0 && { folderId: opts.folderId }
|
|
16626
|
-
});
|
|
16660
|
+
const rows = await ctx.persistence.tombstones(embedding, embeddingModel, scope, opts.folderId);
|
|
16627
16661
|
let bestId = null;
|
|
16628
16662
|
let bestSim = opts.threshold;
|
|
16629
16663
|
for (const row of rows) {
|
|
@@ -16690,7 +16724,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16690
16724
|
if (requestedIds.length === 0) return null;
|
|
16691
16725
|
const valid = [];
|
|
16692
16726
|
for (const id of requestedIds) {
|
|
16693
|
-
const existing = await
|
|
16727
|
+
const existing = await ctx.persistence.get(id);
|
|
16694
16728
|
if (existing && !existing.supersededBy) valid.push(id);
|
|
16695
16729
|
}
|
|
16696
16730
|
if (valid.length === 0) {
|
|
@@ -16702,7 +16736,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16702
16736
|
return { supersede: valid, content: decision.content };
|
|
16703
16737
|
}
|
|
16704
16738
|
if (decision.action === "noop" && decision.targetId) {
|
|
16705
|
-
const existing = await
|
|
16739
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
16706
16740
|
if (!existing || existing.supersededBy) {
|
|
16707
16741
|
return abandonToRace(
|
|
16708
16742
|
options,
|
|
@@ -16716,7 +16750,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16716
16750
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
16717
16751
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
16718
16752
|
const resurrect = resurrectFields(existing);
|
|
16719
|
-
const updated = await
|
|
16753
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
16720
16754
|
content: existing.content,
|
|
16721
16755
|
proofCountIncrement: 1,
|
|
16722
16756
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -16744,7 +16778,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16744
16778
|
};
|
|
16745
16779
|
}
|
|
16746
16780
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
16747
|
-
const existing = await
|
|
16781
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
16748
16782
|
if (!existing || existing.supersededBy) {
|
|
16749
16783
|
return abandonToRace(
|
|
16750
16784
|
options,
|
|
@@ -16755,12 +16789,13 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16755
16789
|
existing.sourceChunkIds ?? [],
|
|
16756
16790
|
options.sourceChunkIds ?? []
|
|
16757
16791
|
);
|
|
16758
|
-
const
|
|
16792
|
+
const generatedEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
|
|
16793
|
+
const newEmbedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
16759
16794
|
const consolidatedModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
16760
16795
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
16761
16796
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
16762
16797
|
const resurrect = resurrectFields(existing);
|
|
16763
|
-
const updated = await
|
|
16798
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
16764
16799
|
content: decision.content,
|
|
16765
16800
|
proofCountIncrement: 1,
|
|
16766
16801
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -16804,7 +16839,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16804
16839
|
return null;
|
|
16805
16840
|
}
|
|
16806
16841
|
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
16807
|
-
const stillExists = await
|
|
16842
|
+
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
16808
16843
|
if (stillExists) {
|
|
16809
16844
|
throw new Error(`retain: merge into memory ${targetId} failed to persist`);
|
|
16810
16845
|
}
|
|
@@ -17321,9 +17356,9 @@ function createAutoExtractor(options) {
|
|
|
17321
17356
|
const persistCursor = (conversationId, messages, advancedToId, contiguous) => {
|
|
17322
17357
|
if (!cursorStore || conversationId === void 0 || !contiguous) return;
|
|
17323
17358
|
try {
|
|
17324
|
-
const
|
|
17325
|
-
if (
|
|
17326
|
-
const storedIdx = messages.findIndex((m) => m.id ===
|
|
17359
|
+
const stored2 = cursorStore.get(conversationId);
|
|
17360
|
+
if (stored2 && stored2 !== advancedToId) {
|
|
17361
|
+
const storedIdx = messages.findIndex((m) => m.id === stored2);
|
|
17327
17362
|
const newIdx = messages.findIndex((m) => m.id === advancedToId);
|
|
17328
17363
|
if (storedIdx !== -1 && newIdx !== -1 && storedIdx >= newIdx) return;
|
|
17329
17364
|
}
|
|
@@ -18303,7 +18338,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
18303
18338
|
if (graphLaneFailed) degraded.push("graph-lane-failed");
|
|
18304
18339
|
if (temporalLaneFailed) degraded.push("temporal-lane-failed");
|
|
18305
18340
|
if (chunksScopeRestricted) degraded.push("chunks-scope-restricted");
|
|
18306
|
-
const laneRan = types.includes("fact") && !!ctx.vaultCtx && !!ctx.vaultCache || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
|
|
18341
|
+
const laneRan = types.includes("fact") && (!!ctx.factSource || !!ctx.vaultCtx && !!ctx.vaultCache) || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
|
|
18307
18342
|
const scores = admitted.map((m) => m.score);
|
|
18308
18343
|
const minScoreApplied = factResults.length > 0 ? factFloor : chunkResults.length > 0 ? chunkFloor : factFloor >= 0 ? factFloor : chunkFloor;
|
|
18309
18344
|
const diagnostics = {
|
|
@@ -18345,7 +18380,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
18345
18380
|
return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
|
|
18346
18381
|
}
|
|
18347
18382
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
18348
|
-
const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
|
|
18383
|
+
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
18349
18384
|
const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
|
|
18350
18385
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
18351
18386
|
const prepStart = nowMs2();
|
|
@@ -18375,7 +18410,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
18375
18410
|
safeLane(
|
|
18376
18411
|
"graph",
|
|
18377
18412
|
() => graphLaneFailed = true,
|
|
18378
|
-
() => buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
18413
|
+
() => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
18379
18414
|
...options.maxHops !== void 0 && { maxHops: options.maxHops },
|
|
18380
18415
|
...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
|
|
18381
18416
|
...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
|
|
@@ -18386,13 +18421,13 @@ async function recall(query, ctx, options = {}) {
|
|
|
18386
18421
|
wantsTemporal ? safeLane(
|
|
18387
18422
|
"temporal",
|
|
18388
18423
|
() => temporalLaneFailed = true,
|
|
18389
|
-
() => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
18424
|
+
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
18390
18425
|
) : Promise.resolve([])
|
|
18391
18426
|
]);
|
|
18392
18427
|
prepMs = nowMs2() - prepStart;
|
|
18393
18428
|
graphLaneCount = entityRanking.length;
|
|
18394
18429
|
temporalLaneCount = temporalRanking.length;
|
|
18395
|
-
if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
|
|
18430
|
+
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
18396
18431
|
const factStart = nowMs2();
|
|
18397
18432
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
18398
18433
|
factFloor = vaultMinScore;
|
|
@@ -18408,50 +18443,50 @@ async function recall(query, ctx, options = {}) {
|
|
|
18408
18443
|
rankedOnCosine: factRankedOnCosine,
|
|
18409
18444
|
decryptLast: factDecryptLast,
|
|
18410
18445
|
rowsDecrypted: factRowsDecrypted
|
|
18411
|
-
} = await searchVaultMemoriesWithSize(
|
|
18412
|
-
|
|
18446
|
+
} = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
|
|
18447
|
+
searchQuery,
|
|
18413
18448
|
ctx.vaultCtx,
|
|
18414
18449
|
ctx.embeddingOptions,
|
|
18415
18450
|
ctx.vaultCache,
|
|
18416
|
-
|
|
18417
|
-
|
|
18418
|
-
|
|
18419
|
-
|
|
18420
|
-
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18432
|
-
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
18436
|
-
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
|
|
18443
|
-
|
|
18444
|
-
|
|
18445
|
-
|
|
18446
|
-
|
|
18447
|
-
|
|
18448
|
-
|
|
18449
|
-
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
);
|
|
18451
|
+
searchOptions
|
|
18452
|
+
)))(query, {
|
|
18453
|
+
limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
|
|
18454
|
+
minSimilarity: vaultMinScore,
|
|
18455
|
+
useFusion: true,
|
|
18456
|
+
rerank: flags.rerank,
|
|
18457
|
+
...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
|
|
18458
|
+
...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
|
|
18459
|
+
...options.rerankLoadTimeoutMs !== void 0 && {
|
|
18460
|
+
rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
|
|
18461
|
+
},
|
|
18462
|
+
...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
|
|
18463
|
+
...options.recency && { recency: options.recency },
|
|
18464
|
+
...options.mmr !== void 0 && { mmr: options.mmr },
|
|
18465
|
+
...options.supersessionBoost !== void 0 && {
|
|
18466
|
+
supersessionBoost: options.supersessionBoost
|
|
18467
|
+
},
|
|
18468
|
+
...options.supersessionWindow !== void 0 && {
|
|
18469
|
+
supersessionWindow: options.supersessionWindow
|
|
18470
|
+
},
|
|
18471
|
+
...options.proofCountAlpha !== void 0 && {
|
|
18472
|
+
proofCountAlpha: options.proofCountAlpha
|
|
18473
|
+
},
|
|
18474
|
+
...options.bm25AdmissionDivisor !== void 0 && {
|
|
18475
|
+
bm25AdmissionDivisor: options.bm25AdmissionDivisor
|
|
18476
|
+
},
|
|
18477
|
+
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
18478
|
+
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
18479
|
+
...subQueries && { subQueries },
|
|
18480
|
+
...options.scopes && { scopes: options.scopes },
|
|
18481
|
+
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
18482
|
+
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
18483
|
+
...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
|
|
18484
|
+
...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
|
|
18485
|
+
...entityRanking.length > 0 && { entityRanking },
|
|
18486
|
+
...temporalRanking.length > 0 && { temporalRanking },
|
|
18487
|
+
...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
|
|
18488
|
+
queryEmbedTotalTimeoutMs
|
|
18489
|
+
});
|
|
18455
18490
|
factResults.push(
|
|
18456
18491
|
...dedupeBy(
|
|
18457
18492
|
results,
|
|
@@ -19264,26 +19299,26 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
|
19264
19299
|
};
|
|
19265
19300
|
const inputs = [];
|
|
19266
19301
|
for (const id of new Set(memoryIds)) {
|
|
19267
|
-
let
|
|
19302
|
+
let record2;
|
|
19268
19303
|
try {
|
|
19269
|
-
|
|
19304
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
19270
19305
|
} catch (err) {
|
|
19271
19306
|
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
19272
19307
|
skip(id, "not-found");
|
|
19273
19308
|
continue;
|
|
19274
19309
|
}
|
|
19275
|
-
if (
|
|
19310
|
+
if (record2.isDeleted || ctx.userId !== void 0 && record2.userId !== ctx.userId || record2.topicsUserManaged) {
|
|
19276
19311
|
skip(id, "excluded");
|
|
19277
19312
|
continue;
|
|
19278
19313
|
}
|
|
19279
19314
|
try {
|
|
19280
|
-
const
|
|
19281
|
-
|
|
19315
|
+
const stored2 = await vaultMemoryToStored(
|
|
19316
|
+
record2,
|
|
19282
19317
|
ctx.walletAddress,
|
|
19283
19318
|
ctx.signMessage,
|
|
19284
19319
|
ctx.embeddedWalletSigner
|
|
19285
19320
|
);
|
|
19286
|
-
inputs.push({ id, content:
|
|
19321
|
+
inputs.push({ id, content: stored2.content });
|
|
19287
19322
|
} catch (err) {
|
|
19288
19323
|
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
19289
19324
|
skip(id, "unreadable");
|
|
@@ -19468,6 +19503,774 @@ function createLocalMemoryStore(options) {
|
|
|
19468
19503
|
};
|
|
19469
19504
|
}
|
|
19470
19505
|
|
|
19506
|
+
// src/lib/memory/store/remotePersistence.ts
|
|
19507
|
+
var RemoteMemoryError = class extends Error {
|
|
19508
|
+
constructor(message, status, code) {
|
|
19509
|
+
super(message);
|
|
19510
|
+
this.status = status;
|
|
19511
|
+
this.code = code;
|
|
19512
|
+
this.name = "RemoteMemoryError";
|
|
19513
|
+
}
|
|
19514
|
+
};
|
|
19515
|
+
var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
|
|
19516
|
+
var memoryFields = {
|
|
19517
|
+
memory_id: true,
|
|
19518
|
+
content: true,
|
|
19519
|
+
scope: true,
|
|
19520
|
+
created_at: true,
|
|
19521
|
+
updated_at: true,
|
|
19522
|
+
is_deleted: true,
|
|
19523
|
+
embedding: true,
|
|
19524
|
+
embedding_model: true,
|
|
19525
|
+
kind: true,
|
|
19526
|
+
kind_value: true,
|
|
19527
|
+
level: true,
|
|
19528
|
+
folder_id: true,
|
|
19529
|
+
source_chunk_ids: true,
|
|
19530
|
+
proof_count: true,
|
|
19531
|
+
source: true,
|
|
19532
|
+
event_time_start: true,
|
|
19533
|
+
event_time_end: true,
|
|
19534
|
+
event_time_kind: true,
|
|
19535
|
+
topics_user_managed: true,
|
|
19536
|
+
topics: true,
|
|
19537
|
+
topics_updated_at: true,
|
|
19538
|
+
media: true,
|
|
19539
|
+
topics_extracted_at: true,
|
|
19540
|
+
topics_extracted_version: true,
|
|
19541
|
+
superseded_by: true,
|
|
19542
|
+
superseded_at: true,
|
|
19543
|
+
last_observed_at: true,
|
|
19544
|
+
fact_type: true,
|
|
19545
|
+
archived_at: true,
|
|
19546
|
+
trust_tier: true,
|
|
19547
|
+
visibility: true,
|
|
19548
|
+
twin_opt_in: true,
|
|
19549
|
+
published_at: true,
|
|
19550
|
+
geohash: true
|
|
19551
|
+
};
|
|
19552
|
+
var candidateListLimits = [
|
|
19553
|
+
["scopes", 20],
|
|
19554
|
+
["fact_types", 20],
|
|
19555
|
+
["memory_ids", 1e3],
|
|
19556
|
+
["force_ids", 100]
|
|
19557
|
+
];
|
|
19558
|
+
function record(value) {
|
|
19559
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19560
|
+
}
|
|
19561
|
+
function memoryRecord(value) {
|
|
19562
|
+
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))) {
|
|
19563
|
+
throw new Error("Invalid nearby private-memory response");
|
|
19564
|
+
}
|
|
19565
|
+
return value;
|
|
19566
|
+
}
|
|
19567
|
+
async function createRemoteMemoryPersistence(options) {
|
|
19568
|
+
const base = new URL(options.baseUrl);
|
|
19569
|
+
if (!/^https?:$/.test(base.protocol) || base.username || base.password || base.search || base.hash) {
|
|
19570
|
+
throw new Error(
|
|
19571
|
+
"baseUrl must be an HTTP(S) origin or base path without credentials, query or fragment"
|
|
19572
|
+
);
|
|
19573
|
+
}
|
|
19574
|
+
if (!options.keyId || options.keyId.length > 256)
|
|
19575
|
+
throw new Error("A canonical keyId is required");
|
|
19576
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
19577
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
19578
|
+
throw new Error("timeoutMs must be a positive number");
|
|
19579
|
+
const root = base.href.replace(/\/$/, "") + "/api/private-memories";
|
|
19580
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
19581
|
+
const request = async (path, init = {}, signal) => {
|
|
19582
|
+
const controller = new AbortController();
|
|
19583
|
+
let timedOut = false;
|
|
19584
|
+
const timer = setTimeout(() => {
|
|
19585
|
+
timedOut = true;
|
|
19586
|
+
controller.abort();
|
|
19587
|
+
}, timeoutMs);
|
|
19588
|
+
const forwardAbort = () => controller.abort(signal?.reason);
|
|
19589
|
+
if (signal?.aborted) forwardAbort();
|
|
19590
|
+
else signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
19591
|
+
let rejectAborted;
|
|
19592
|
+
const aborted = new Promise((_, reject) => {
|
|
19593
|
+
rejectAborted = () => reject(
|
|
19594
|
+
controller.signal.reason instanceof Error ? controller.signal.reason : new Error("Nearby request aborted")
|
|
19595
|
+
);
|
|
19596
|
+
if (controller.signal.aborted) rejectAborted();
|
|
19597
|
+
else controller.signal.addEventListener("abort", rejectAborted, { once: true });
|
|
19598
|
+
});
|
|
19599
|
+
aborted.catch(() => void 0);
|
|
19600
|
+
try {
|
|
19601
|
+
const token = await Promise.race([options.getToken(), aborted]);
|
|
19602
|
+
if (controller.signal.aborted) await aborted;
|
|
19603
|
+
if (!token) throw new RemoteMemoryError("Authentication required", 401);
|
|
19604
|
+
const response = await fetcher(root + path, {
|
|
19605
|
+
...init,
|
|
19606
|
+
headers: {
|
|
19607
|
+
Authorization: `Bearer ${token}`,
|
|
19608
|
+
...init.body ? { "Content-Type": "application/json" } : {}
|
|
19609
|
+
},
|
|
19610
|
+
redirect: "error",
|
|
19611
|
+
signal: controller.signal
|
|
19612
|
+
});
|
|
19613
|
+
if (!response.ok) {
|
|
19614
|
+
const body = await response.json().catch(() => null);
|
|
19615
|
+
throw new RemoteMemoryError(
|
|
19616
|
+
record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
19617
|
+
response.status,
|
|
19618
|
+
record(body) && typeof body.code === "string" ? body.code : void 0
|
|
19619
|
+
);
|
|
19620
|
+
}
|
|
19621
|
+
return await response.json();
|
|
19622
|
+
} catch (error) {
|
|
19623
|
+
if (timedOut) throw new RemoteMemoryError("Nearby request timed out", 408, "timeout");
|
|
19624
|
+
throw error;
|
|
19625
|
+
} finally {
|
|
19626
|
+
clearTimeout(timer);
|
|
19627
|
+
signal?.removeEventListener("abort", forwardAbort);
|
|
19628
|
+
if (rejectAborted) controller.signal.removeEventListener("abort", rejectAborted);
|
|
19629
|
+
}
|
|
19630
|
+
};
|
|
19631
|
+
const account = await request("/account", {}, options.signal);
|
|
19632
|
+
if (!record(account) || account.state !== "active") {
|
|
19633
|
+
throw new RemoteMemoryError(
|
|
19634
|
+
"Complete and verify migration before using remote memories",
|
|
19635
|
+
409,
|
|
19636
|
+
"memory_not_active"
|
|
19637
|
+
);
|
|
19638
|
+
}
|
|
19639
|
+
if (account.key_id !== options.keyId) {
|
|
19640
|
+
throw new RemoteMemoryError(
|
|
19641
|
+
"The canonical memory key does not match this account",
|
|
19642
|
+
409,
|
|
19643
|
+
"key_mismatch"
|
|
19644
|
+
);
|
|
19645
|
+
}
|
|
19646
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
19647
|
+
const decode = async (value) => {
|
|
19648
|
+
const item = memoryRecord(value);
|
|
19649
|
+
const decrypt = async (ciphertext) => {
|
|
19650
|
+
if (!ciphertextPattern.test(ciphertext))
|
|
19651
|
+
throw new Error("Nearby returned unencrypted memory content");
|
|
19652
|
+
const plaintext = await options.decrypt(ciphertext);
|
|
19653
|
+
if (plaintext === ciphertext) throw new Error("Memory decryption failed");
|
|
19654
|
+
return plaintext;
|
|
19655
|
+
};
|
|
19656
|
+
const decoded = {
|
|
19657
|
+
...item,
|
|
19658
|
+
memory: {
|
|
19659
|
+
...item.memory,
|
|
19660
|
+
content: await decrypt(item.memory.content),
|
|
19661
|
+
...item.memory.kind_value !== void 0 && {
|
|
19662
|
+
kind_value: await decrypt(item.memory.kind_value)
|
|
19663
|
+
}
|
|
19664
|
+
}
|
|
19665
|
+
};
|
|
19666
|
+
return remember(decoded, item);
|
|
19667
|
+
};
|
|
19668
|
+
const remember = (decoded, item) => {
|
|
19669
|
+
snapshots.set(decoded, {
|
|
19670
|
+
id: item.memory.memory_id,
|
|
19671
|
+
version: item.version,
|
|
19672
|
+
content: decoded.memory.content,
|
|
19673
|
+
kindValue: decoded.memory.kind_value,
|
|
19674
|
+
encryptedContent: item.memory.content,
|
|
19675
|
+
encryptedKindValue: item.memory.kind_value
|
|
19676
|
+
});
|
|
19677
|
+
return decoded;
|
|
19678
|
+
};
|
|
19679
|
+
const decodeAll = async (values) => {
|
|
19680
|
+
const records = values.map(memoryRecord);
|
|
19681
|
+
const settled = await Promise.allSettled(records.map(decode));
|
|
19682
|
+
const items = [];
|
|
19683
|
+
const failed = [];
|
|
19684
|
+
settled.forEach((result, i) => {
|
|
19685
|
+
if (result.status === "fulfilled") items.push(result.value);
|
|
19686
|
+
else
|
|
19687
|
+
failed.push({
|
|
19688
|
+
memory_id: records[i].memory.memory_id,
|
|
19689
|
+
version: records[i].version,
|
|
19690
|
+
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
19691
|
+
});
|
|
19692
|
+
});
|
|
19693
|
+
return { items, failed };
|
|
19694
|
+
};
|
|
19695
|
+
const decodeCommitted = async (value, write) => {
|
|
19696
|
+
const item = memoryRecord(value);
|
|
19697
|
+
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)
|
|
19698
|
+
return decode(item);
|
|
19699
|
+
return remember(
|
|
19700
|
+
{
|
|
19701
|
+
...item,
|
|
19702
|
+
memory: {
|
|
19703
|
+
...item.memory,
|
|
19704
|
+
content: write.content,
|
|
19705
|
+
...write.kindValue !== void 0 && { kind_value: write.kindValue }
|
|
19706
|
+
}
|
|
19707
|
+
},
|
|
19708
|
+
item
|
|
19709
|
+
);
|
|
19710
|
+
};
|
|
19711
|
+
const encryptField2 = async (plaintext) => {
|
|
19712
|
+
const ciphertext = await options.encrypt(plaintext);
|
|
19713
|
+
if (ciphertext === plaintext || !ciphertextPattern.test(ciphertext))
|
|
19714
|
+
throw new Error("Field encryption must return SDK ciphertext; refusing to upload plaintext");
|
|
19715
|
+
return ciphertext;
|
|
19716
|
+
};
|
|
19717
|
+
const memoryPath = (id) => {
|
|
19718
|
+
if (!id || id.length > 128) throw new Error("memory_id must be 1\u2013128 characters");
|
|
19719
|
+
return "/memories/" + encodeURIComponent(id);
|
|
19720
|
+
};
|
|
19721
|
+
const prepareWrite = async (memory, expectedVersion, signal) => {
|
|
19722
|
+
const unknown = Object.keys(memory).filter(
|
|
19723
|
+
(key) => !Object.prototype.hasOwnProperty.call(memoryFields, key)
|
|
19724
|
+
);
|
|
19725
|
+
if (unknown.length) {
|
|
19726
|
+
throw new RemoteMemoryError(
|
|
19727
|
+
`Unknown private-memory fields (${unknown.join(", ")}); refusing to forward them`,
|
|
19728
|
+
400,
|
|
19729
|
+
"unknown_field"
|
|
19730
|
+
);
|
|
19731
|
+
}
|
|
19732
|
+
memory = { ...memory, ...memory.embedding && { embedding: [...memory.embedding] } };
|
|
19733
|
+
const path = memoryPath(memory.memory_id);
|
|
19734
|
+
const snapshot = typeof expectedVersion === "number" ? void 0 : snapshots.get(expectedVersion);
|
|
19735
|
+
if (typeof expectedVersion !== "number" && (!snapshot || snapshot.id !== memory.memory_id || snapshot.version !== expectedVersion.version))
|
|
19736
|
+
throw new Error(
|
|
19737
|
+
"Expected snapshot must be an unmodified version from this persistence instance"
|
|
19738
|
+
);
|
|
19739
|
+
expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
|
|
19740
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
19741
|
+
throw new Error("expectedVersion must be a nonnegative integer");
|
|
19742
|
+
const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
|
|
19743
|
+
let existing;
|
|
19744
|
+
if (expectedVersion !== 0 && !snapshot) {
|
|
19745
|
+
try {
|
|
19746
|
+
existing = memoryRecord(await request(path, {}, signal));
|
|
19747
|
+
} catch (error) {
|
|
19748
|
+
if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
|
|
19749
|
+
throw error;
|
|
19750
|
+
}
|
|
19751
|
+
}
|
|
19752
|
+
if (existing && existing.version !== expectedVersion) throw conflict();
|
|
19753
|
+
const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
|
|
19754
|
+
const content = (snapshot?.content ?? decoded?.memory.content) === memory.content ? snapshot?.encryptedContent ?? existing.memory.content : await encryptField2(memory.content);
|
|
19755
|
+
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);
|
|
19756
|
+
return {
|
|
19757
|
+
body: {
|
|
19758
|
+
expected_version: expectedVersion,
|
|
19759
|
+
memory: { ...memory, content, ...kindValue !== void 0 && { kind_value: kindValue } }
|
|
19760
|
+
},
|
|
19761
|
+
content: memory.content,
|
|
19762
|
+
kindValue: memory.kind_value
|
|
19763
|
+
};
|
|
19764
|
+
};
|
|
19765
|
+
const fetchCandidates = async (embedding, candidateOptions, withCounts) => {
|
|
19766
|
+
const limit = candidateOptions.limit ?? 100;
|
|
19767
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
19768
|
+
throw new Error("Candidate limit must be 1\u2013100");
|
|
19769
|
+
for (const [key, max] of candidateListLimits) {
|
|
19770
|
+
const values = candidateOptions[key];
|
|
19771
|
+
if (values && values.length > max)
|
|
19772
|
+
throw new Error(`Candidate ${key} accepts at most ${max} entries (got ${values.length})`);
|
|
19773
|
+
}
|
|
19774
|
+
const result = await request(
|
|
19775
|
+
"/candidates",
|
|
19776
|
+
{
|
|
19777
|
+
method: "POST",
|
|
19778
|
+
body: JSON.stringify({
|
|
19779
|
+
embedding,
|
|
19780
|
+
limit,
|
|
19781
|
+
force_ids: candidateOptions.force_ids ?? [],
|
|
19782
|
+
...withCounts && { with_counts: true },
|
|
19783
|
+
...Object.fromEntries(
|
|
19784
|
+
[
|
|
19785
|
+
"scopes",
|
|
19786
|
+
"memory_ids",
|
|
19787
|
+
"embedding_model",
|
|
19788
|
+
"strict_model",
|
|
19789
|
+
"include_deleted",
|
|
19790
|
+
"deleted_only"
|
|
19791
|
+
].filter(
|
|
19792
|
+
(key) => candidateOptions[key] !== void 0
|
|
19793
|
+
).map((key) => [key, candidateOptions[key]])
|
|
19794
|
+
),
|
|
19795
|
+
...candidateOptions.fact_types !== void 0 && {
|
|
19796
|
+
fact_types: candidateOptions.fact_types
|
|
19797
|
+
},
|
|
19798
|
+
...candidateOptions.include_archived !== void 0 && {
|
|
19799
|
+
include_archived: candidateOptions.include_archived
|
|
19800
|
+
},
|
|
19801
|
+
...candidateOptions.include_quarantined !== void 0 && {
|
|
19802
|
+
include_quarantined: candidateOptions.include_quarantined
|
|
19803
|
+
},
|
|
19804
|
+
...candidateOptions.include_superseded !== void 0 && {
|
|
19805
|
+
include_superseded: candidateOptions.include_superseded
|
|
19806
|
+
}
|
|
19807
|
+
})
|
|
19808
|
+
},
|
|
19809
|
+
candidateOptions.signal
|
|
19810
|
+
);
|
|
19811
|
+
if (!record(result) || !Array.isArray(result.items))
|
|
19812
|
+
throw new Error("Invalid nearby candidate response");
|
|
19813
|
+
return result;
|
|
19814
|
+
};
|
|
19815
|
+
const candidateSet = async (embedding, candidateOptions = {}) => {
|
|
19816
|
+
const result = await fetchCandidates(embedding, candidateOptions, true);
|
|
19817
|
+
if (!Number.isSafeInteger(result.total_count) || result.total_count < 0 || !Number.isSafeInteger(result.unavailable_count) || result.unavailable_count < 0)
|
|
19818
|
+
throw new Error("Invalid nearby candidate response");
|
|
19819
|
+
return {
|
|
19820
|
+
...await decodeAll(result.items),
|
|
19821
|
+
total_count: result.total_count,
|
|
19822
|
+
unavailable_count: result.unavailable_count
|
|
19823
|
+
};
|
|
19824
|
+
};
|
|
19825
|
+
return {
|
|
19826
|
+
get: async (id, signal) => {
|
|
19827
|
+
try {
|
|
19828
|
+
return await decode(await request(memoryPath(id), {}, signal));
|
|
19829
|
+
} catch (error) {
|
|
19830
|
+
if (error instanceof RemoteMemoryError && error.status === 404) return null;
|
|
19831
|
+
throw error;
|
|
19832
|
+
}
|
|
19833
|
+
},
|
|
19834
|
+
list: async (listOptions = {}) => {
|
|
19835
|
+
const { signal, ...query } = listOptions;
|
|
19836
|
+
if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) {
|
|
19837
|
+
throw new Error("Page limit must be 1\u2013200");
|
|
19838
|
+
}
|
|
19839
|
+
const params = new URLSearchParams();
|
|
19840
|
+
for (const key of [
|
|
19841
|
+
"cursor",
|
|
19842
|
+
"limit",
|
|
19843
|
+
"include_deleted",
|
|
19844
|
+
"include_archived",
|
|
19845
|
+
"include_quarantined",
|
|
19846
|
+
"include_superseded",
|
|
19847
|
+
"include_embeddings"
|
|
19848
|
+
]) {
|
|
19849
|
+
if (query[key] !== void 0) params.set(key, String(query[key]));
|
|
19850
|
+
}
|
|
19851
|
+
const page = await request("/memories?" + params.toString(), {}, signal);
|
|
19852
|
+
if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
|
|
19853
|
+
throw new Error("Invalid nearby private-memory page");
|
|
19854
|
+
}
|
|
19855
|
+
return {
|
|
19856
|
+
...await decodeAll(page.items),
|
|
19857
|
+
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
|
|
19858
|
+
};
|
|
19859
|
+
},
|
|
19860
|
+
put: async (memory, expectedVersion, signal) => {
|
|
19861
|
+
const write = await prepareWrite(memory, expectedVersion, signal);
|
|
19862
|
+
return decodeCommitted(
|
|
19863
|
+
await request(
|
|
19864
|
+
memoryPath(write.body.memory.memory_id),
|
|
19865
|
+
{
|
|
19866
|
+
method: "PUT",
|
|
19867
|
+
body: JSON.stringify({ key_id: options.keyId, ...write.body })
|
|
19868
|
+
},
|
|
19869
|
+
signal
|
|
19870
|
+
),
|
|
19871
|
+
write
|
|
19872
|
+
);
|
|
19873
|
+
},
|
|
19874
|
+
putMany: async (writes, signal) => {
|
|
19875
|
+
if (writes.length < 1 || writes.length > 50 || new Set(writes.map((w) => w.memory.memory_id)).size !== writes.length)
|
|
19876
|
+
throw new Error("Batch must contain 1\u201350 distinct memory ids");
|
|
19877
|
+
const prepared = await Promise.all(
|
|
19878
|
+
writes.map((w) => prepareWrite(w.memory, w.expectedVersion, signal))
|
|
19879
|
+
);
|
|
19880
|
+
const result = await request(
|
|
19881
|
+
"/memories/batch",
|
|
19882
|
+
{
|
|
19883
|
+
method: "POST",
|
|
19884
|
+
body: JSON.stringify({ key_id: options.keyId, writes: prepared.map((w) => w.body) })
|
|
19885
|
+
},
|
|
19886
|
+
signal
|
|
19887
|
+
);
|
|
19888
|
+
if (!record(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
|
|
19889
|
+
throw new Error("Invalid nearby batch response");
|
|
19890
|
+
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
19891
|
+
},
|
|
19892
|
+
candidateSet,
|
|
19893
|
+
candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
|
|
19894
|
+
};
|
|
19895
|
+
}
|
|
19896
|
+
|
|
19897
|
+
// src/lib/memory/store/remotePipeline.ts
|
|
19898
|
+
var import_uuid4 = require("uuid");
|
|
19899
|
+
init_logger();
|
|
19900
|
+
function storedVector(vector) {
|
|
19901
|
+
if (!Array.isArray(vector) || vector.length !== 1536 && vector.length !== 4096 || vector.some((v) => !Number.isFinite(v)))
|
|
19902
|
+
throw new Error("Remote memories require a finite 1536/4096-dimensional vector");
|
|
19903
|
+
const out = vector.slice(0, 1536);
|
|
19904
|
+
const norm = Math.sqrt(out.reduce((sum, v) => sum + v * v, 0));
|
|
19905
|
+
if (!norm) throw new Error("Remote query/content vector has no direction after MRL truncation");
|
|
19906
|
+
return out.map((v) => v / norm);
|
|
19907
|
+
}
|
|
19908
|
+
function sourceIds(value) {
|
|
19909
|
+
if (!value) return [];
|
|
19910
|
+
try {
|
|
19911
|
+
const parsed = JSON.parse(value);
|
|
19912
|
+
return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
|
|
19913
|
+
} catch {
|
|
19914
|
+
return [];
|
|
19915
|
+
}
|
|
19916
|
+
}
|
|
19917
|
+
function stored(row) {
|
|
19918
|
+
return {
|
|
19919
|
+
uniqueId: row.memory_id,
|
|
19920
|
+
content: row.content,
|
|
19921
|
+
scope: row.scope,
|
|
19922
|
+
folderId: row.folder_id ?? null,
|
|
19923
|
+
userId: null,
|
|
19924
|
+
embedding: row.embedding ? JSON.stringify(row.embedding) : null,
|
|
19925
|
+
embeddingModel: row.embedding_model ?? null,
|
|
19926
|
+
sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
|
|
19927
|
+
proofCount: row.proof_count ?? null,
|
|
19928
|
+
source: row.source ?? null,
|
|
19929
|
+
media: parseMedia(row.media),
|
|
19930
|
+
eventTimeStart: row.event_time_start ?? null,
|
|
19931
|
+
eventTimeEnd: row.event_time_end ?? null,
|
|
19932
|
+
eventTimeKind: row.event_time_kind ?? null,
|
|
19933
|
+
topicsUserManaged: row.topics_user_managed ?? false,
|
|
19934
|
+
topics: parseTopics(row.topics),
|
|
19935
|
+
topicsUpdatedAt: row.topics_updated_at ?? null,
|
|
19936
|
+
topicsExtractedAt: row.topics_extracted_at ?? null,
|
|
19937
|
+
topicsExtractedVersion: row.topics_extracted_version ?? null,
|
|
19938
|
+
supersededBy: row.superseded_by ?? null,
|
|
19939
|
+
supersededAt: row.superseded_at ?? null,
|
|
19940
|
+
lastObservedAt: row.last_observed_at ?? null,
|
|
19941
|
+
factType: row.fact_type ?? null,
|
|
19942
|
+
archivedAt: row.archived_at ?? null,
|
|
19943
|
+
trustTier: row.trust_tier ?? null,
|
|
19944
|
+
visibility: row.visibility === "public" ? "public" : "private",
|
|
19945
|
+
twinOptIn: row.twin_opt_in ?? false,
|
|
19946
|
+
publishedAt: row.published_at ?? null,
|
|
19947
|
+
geohash: row.geohash ?? null,
|
|
19948
|
+
createdAt: new Date(row.created_at),
|
|
19949
|
+
updatedAt: new Date(row.updated_at),
|
|
19950
|
+
isDeleted: row.is_deleted
|
|
19951
|
+
};
|
|
19952
|
+
}
|
|
19953
|
+
function createRemoteMemoryPipeline(options) {
|
|
19954
|
+
const { persistence, embeddingOptions } = options;
|
|
19955
|
+
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
19956
|
+
const operation = (mode) => {
|
|
19957
|
+
const rejectUndecryptable = (failed) => {
|
|
19958
|
+
if (!failed.length) return;
|
|
19959
|
+
if (mode === "retain")
|
|
19960
|
+
throw new Error(
|
|
19961
|
+
`Remote memories could not decrypt ${failed.length} candidate row(s); refusing to retain until they are repaired`
|
|
19962
|
+
);
|
|
19963
|
+
getLogger().warn(
|
|
19964
|
+
`[memory/remote] Skipping ${failed.length} undecryptable candidate row(s)`,
|
|
19965
|
+
failed.map((failure) => failure.memory_id)
|
|
19966
|
+
);
|
|
19967
|
+
};
|
|
19968
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
19969
|
+
const remember = (items) => {
|
|
19970
|
+
items.forEach((item) => snapshots.set(item.memory.memory_id, item));
|
|
19971
|
+
return items.map((item) => stored(item.memory));
|
|
19972
|
+
};
|
|
19973
|
+
const get = async (id) => {
|
|
19974
|
+
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
19975
|
+
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
19976
|
+
snapshots.set(id, snapshot);
|
|
19977
|
+
return stored(snapshot.memory);
|
|
19978
|
+
};
|
|
19979
|
+
const prepare = async (query, search = {}) => {
|
|
19980
|
+
if (search.folderId !== void 0)
|
|
19981
|
+
throw new Error("Remote memories do not support folder filters");
|
|
19982
|
+
const facets = normalizeSubQueries(search.subQueries);
|
|
19983
|
+
const facetQueries = facets.length >= 2 ? facets : [];
|
|
19984
|
+
const start = Date.now();
|
|
19985
|
+
const budgetMs = search.queryEmbedTotalTimeoutMs ?? 8e3;
|
|
19986
|
+
const embed = (texts) => generateEmbeddings(texts, {
|
|
19987
|
+
...embeddingOptions,
|
|
19988
|
+
totalTimeoutMs: budgetMs
|
|
19989
|
+
});
|
|
19990
|
+
const embedFacets = async () => {
|
|
19991
|
+
if (!facetQueries.length) return [];
|
|
19992
|
+
try {
|
|
19993
|
+
const vectors2 = await embed(facetQueries);
|
|
19994
|
+
if (vectors2.length !== facetQueries.length)
|
|
19995
|
+
throw new Error("Incomplete facet embeddings");
|
|
19996
|
+
return vectors2.map(storedVector);
|
|
19997
|
+
} catch (error) {
|
|
19998
|
+
getLogger().warn(
|
|
19999
|
+
"[memory/remote] Facet embeddings unavailable; using primary query",
|
|
20000
|
+
error
|
|
20001
|
+
);
|
|
20002
|
+
return [];
|
|
20003
|
+
}
|
|
20004
|
+
};
|
|
20005
|
+
const [primary, facetEmbeddings] = await Promise.all([
|
|
20006
|
+
search.queryEmbedding ?? embed([query]).then((vectors2) => vectors2[0]),
|
|
20007
|
+
embedFacets()
|
|
20008
|
+
]);
|
|
20009
|
+
const queryEmbedding = storedVector(primary);
|
|
20010
|
+
const queryEmbedMs = Date.now() - start;
|
|
20011
|
+
const graph = search.entityRanking ?? [];
|
|
20012
|
+
const temporal = search.temporalRanking ?? [];
|
|
20013
|
+
const forced = /* @__PURE__ */ new Set();
|
|
20014
|
+
for (let i = 0; i < Math.max(graph.length, temporal.length) && forced.size < 100; i++) {
|
|
20015
|
+
if (graph[i] !== void 0) forced.add(graph[i]);
|
|
20016
|
+
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
20017
|
+
}
|
|
20018
|
+
const forceIds = [...forced];
|
|
20019
|
+
const windowOptions = (i, signal) => ({
|
|
20020
|
+
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
20021
|
+
force_ids: i === 0 ? forceIds : [],
|
|
20022
|
+
...search.scopes && { scopes: search.scopes },
|
|
20023
|
+
...search.factTypes && { fact_types: search.factTypes },
|
|
20024
|
+
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
20025
|
+
include_archived: search.includeArchived,
|
|
20026
|
+
embedding_model: model,
|
|
20027
|
+
...signal && { signal }
|
|
20028
|
+
});
|
|
20029
|
+
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
20030
|
+
let windows;
|
|
20031
|
+
if (mode === "retain") {
|
|
20032
|
+
windows = await Promise.all(
|
|
20033
|
+
vectors.map((embedding, i) => persistence.candidateSet(embedding, windowOptions(i)))
|
|
20034
|
+
);
|
|
20035
|
+
} else {
|
|
20036
|
+
const deadline = new AbortController();
|
|
20037
|
+
const timer = setTimeout(
|
|
20038
|
+
() => deadline.abort(
|
|
20039
|
+
new RemoteMemoryError("Remote recall exceeded its query budget", 408, "timeout")
|
|
20040
|
+
),
|
|
20041
|
+
Math.max(0, start + budgetMs - Date.now())
|
|
20042
|
+
);
|
|
20043
|
+
try {
|
|
20044
|
+
windows = await Promise.all(
|
|
20045
|
+
vectors.map(
|
|
20046
|
+
(embedding, i) => persistence.candidates(embedding, windowOptions(i, deadline.signal))
|
|
20047
|
+
)
|
|
20048
|
+
);
|
|
20049
|
+
} finally {
|
|
20050
|
+
clearTimeout(timer);
|
|
20051
|
+
}
|
|
20052
|
+
}
|
|
20053
|
+
rejectUndecryptable([
|
|
20054
|
+
...new Map(
|
|
20055
|
+
windows.flatMap((window2) => window2.failed).map((failure) => [failure.memory_id, failure])
|
|
20056
|
+
).values()
|
|
20057
|
+
]);
|
|
20058
|
+
const items = [
|
|
20059
|
+
...new Map(
|
|
20060
|
+
windows.flatMap((window2) => window2.items).map((item) => [item.memory.memory_id, item])
|
|
20061
|
+
).values()
|
|
20062
|
+
];
|
|
20063
|
+
const memories = remember(items);
|
|
20064
|
+
return {
|
|
20065
|
+
memories,
|
|
20066
|
+
embeddedItems: memories.map((memory) => ({
|
|
20067
|
+
id: memory.uniqueId,
|
|
20068
|
+
content: memory.content,
|
|
20069
|
+
embedding: JSON.parse(memory.embedding ?? "[]"),
|
|
20070
|
+
createdAt: memory.createdAt,
|
|
20071
|
+
updatedAt: memory.updatedAt,
|
|
20072
|
+
proofCount: memory.proofCount,
|
|
20073
|
+
lastObservedAt: memory.lastObservedAt,
|
|
20074
|
+
eventTimeStart: memory.eventTimeStart,
|
|
20075
|
+
eventTimeEnd: memory.eventTimeEnd,
|
|
20076
|
+
eventTimeKind: memory.eventTimeKind === "point" || memory.eventTimeKind === "range" || memory.eventTimeKind === "ongoing" ? memory.eventTimeKind : null,
|
|
20077
|
+
factType: memory.factType,
|
|
20078
|
+
sourceChunkIds: memory.sourceChunkIds
|
|
20079
|
+
})),
|
|
20080
|
+
queryEmbedding,
|
|
20081
|
+
facetEmbeddings,
|
|
20082
|
+
vaultSize: Math.max(windows[0].total_count ?? 0, items.length),
|
|
20083
|
+
embeddingFailure: windows.some((window2) => (window2.unavailable_count ?? 0) > 0),
|
|
20084
|
+
embeddingsUnavailable: (windows[0].total_count ?? items.length) > 0 && !memories.some((memory) => memory.embedding),
|
|
20085
|
+
decryptLast: true,
|
|
20086
|
+
rowsDecrypted: items.length,
|
|
20087
|
+
queryEmbedMs,
|
|
20088
|
+
rowsEmbedded: 0
|
|
20089
|
+
};
|
|
20090
|
+
};
|
|
20091
|
+
const createRow = (input) => {
|
|
20092
|
+
if (input.folderId !== void 0 && input.folderId !== null)
|
|
20093
|
+
throw new Error("Remote memories do not support folders");
|
|
20094
|
+
const now = Date.now();
|
|
20095
|
+
return {
|
|
20096
|
+
memory_id: (0, import_uuid4.v7)(),
|
|
20097
|
+
content: input.content,
|
|
20098
|
+
scope: input.scope ?? "private",
|
|
20099
|
+
created_at: now,
|
|
20100
|
+
updated_at: now,
|
|
20101
|
+
is_deleted: false,
|
|
20102
|
+
...input.embedding !== void 0 && {
|
|
20103
|
+
embedding: storedVector(JSON.parse(input.embedding)),
|
|
20104
|
+
embedding_model: input.embeddingModel
|
|
20105
|
+
},
|
|
20106
|
+
source_chunk_ids: JSON.stringify(input.sourceChunkIds ?? []),
|
|
20107
|
+
proof_count: input.proofCount ?? 1,
|
|
20108
|
+
source: input.source ?? "manual",
|
|
20109
|
+
...input.eventTime && {
|
|
20110
|
+
event_time_start: input.eventTime.start ?? void 0,
|
|
20111
|
+
event_time_end: input.eventTime.end ?? void 0,
|
|
20112
|
+
event_time_kind: input.eventTime.kind ?? void 0
|
|
20113
|
+
},
|
|
20114
|
+
fact_type: input.factType,
|
|
20115
|
+
trust_tier: normalizeTrustTier(input.trustTier) ?? void 0,
|
|
20116
|
+
geohash: input.geohash,
|
|
20117
|
+
visibility: "private",
|
|
20118
|
+
twin_opt_in: false
|
|
20119
|
+
};
|
|
20120
|
+
};
|
|
20121
|
+
const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
|
|
20122
|
+
const port = {
|
|
20123
|
+
prepare,
|
|
20124
|
+
get,
|
|
20125
|
+
getFresh: async (id) => {
|
|
20126
|
+
const current = await persistence.get(id);
|
|
20127
|
+
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
20128
|
+
},
|
|
20129
|
+
tombstones: async (embedding, embeddingModel, scope, folderId) => {
|
|
20130
|
+
if (folderId !== void 0) throw new Error("Remote memories do not support folders");
|
|
20131
|
+
const window2 = await persistence.candidateSet(storedVector(embedding), {
|
|
20132
|
+
limit: 1,
|
|
20133
|
+
scopes: [scope],
|
|
20134
|
+
embedding_model: embeddingModel,
|
|
20135
|
+
strict_model: true,
|
|
20136
|
+
include_deleted: true,
|
|
20137
|
+
deleted_only: true
|
|
20138
|
+
});
|
|
20139
|
+
rejectUndecryptable(window2.failed);
|
|
20140
|
+
return remember(window2.items);
|
|
20141
|
+
},
|
|
20142
|
+
create: (input) => write(createRow(input), 0),
|
|
20143
|
+
update: async (id, patch) => {
|
|
20144
|
+
const existing = await get(id);
|
|
20145
|
+
if (!existing) return null;
|
|
20146
|
+
const snapshot = snapshots.get(id);
|
|
20147
|
+
const memory = {
|
|
20148
|
+
...snapshot.memory,
|
|
20149
|
+
content: patch.content,
|
|
20150
|
+
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
|
|
20151
|
+
};
|
|
20152
|
+
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
20153
|
+
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
20154
|
+
delete memory.embedding;
|
|
20155
|
+
delete memory.embedding_model;
|
|
20156
|
+
}
|
|
20157
|
+
if (patch.embedding !== void 0) {
|
|
20158
|
+
memory.embedding = patch.embedding === null ? [] : storedVector(JSON.parse(patch.embedding));
|
|
20159
|
+
memory.embedding_model = patch.embeddingModel ?? void 0;
|
|
20160
|
+
}
|
|
20161
|
+
const observed = sourceIds(memory.source_chunk_ids);
|
|
20162
|
+
const replay = !!patch.observationSourceIds?.length && patch.observationSourceIds.every((id2) => observed.includes(id2));
|
|
20163
|
+
if (patch.sourceChunkIds !== void 0)
|
|
20164
|
+
memory.source_chunk_ids = JSON.stringify(
|
|
20165
|
+
patch.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observed, ...patch.sourceChunkIds])] : patch.sourceChunkIds
|
|
20166
|
+
);
|
|
20167
|
+
if (!replay) {
|
|
20168
|
+
if (patch.proofCountIncrement !== void 0)
|
|
20169
|
+
memory.proof_count = (memory.proof_count ?? 1) + patch.proofCountIncrement;
|
|
20170
|
+
else if (patch.proofCount !== void 0) memory.proof_count = patch.proofCount;
|
|
20171
|
+
if (patch.lastObservedAt !== void 0) memory.last_observed_at = patch.lastObservedAt;
|
|
20172
|
+
}
|
|
20173
|
+
if (patch.source !== void 0) memory.source = patch.source;
|
|
20174
|
+
if (patch.factType !== void 0) memory.fact_type = patch.factType;
|
|
20175
|
+
if (patch.trustTier !== void 0)
|
|
20176
|
+
memory.trust_tier = normalizeTrustTier(patch.trustTier) ?? void 0;
|
|
20177
|
+
if (patch.topicsUserManaged !== void 0)
|
|
20178
|
+
memory.topics_user_managed = patch.topicsUserManaged;
|
|
20179
|
+
if (patch.eventTime !== void 0) {
|
|
20180
|
+
memory.event_time_start = patch.eventTime.start ?? void 0;
|
|
20181
|
+
memory.event_time_end = patch.eventTime.end ?? void 0;
|
|
20182
|
+
memory.event_time_kind = patch.eventTime.kind ?? void 0;
|
|
20183
|
+
}
|
|
20184
|
+
if (patch.restore) memory.archived_at = void 0;
|
|
20185
|
+
return write(memory, snapshot);
|
|
20186
|
+
},
|
|
20187
|
+
supersede: async (id, successor) => {
|
|
20188
|
+
const [target, newer] = await Promise.all([get(id), get(successor)]);
|
|
20189
|
+
if (!target || !newer || id === successor) return false;
|
|
20190
|
+
const old = snapshots.get(id);
|
|
20191
|
+
const next = snapshots.get(successor);
|
|
20192
|
+
remember(
|
|
20193
|
+
await persistence.putMany([
|
|
20194
|
+
{
|
|
20195
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
20196
|
+
expectedVersion: old
|
|
20197
|
+
},
|
|
20198
|
+
{ memory: next.memory, expectedVersion: next }
|
|
20199
|
+
])
|
|
20200
|
+
);
|
|
20201
|
+
return true;
|
|
20202
|
+
},
|
|
20203
|
+
createSuperseding: async (input, targetId) => {
|
|
20204
|
+
const target = await get(targetId);
|
|
20205
|
+
if (!target) return { created: null, retired: false };
|
|
20206
|
+
const snapshot = snapshots.get(targetId);
|
|
20207
|
+
const successor = createRow(input);
|
|
20208
|
+
const rows = remember(
|
|
20209
|
+
await persistence.putMany([
|
|
20210
|
+
{ memory: successor, expectedVersion: 0 },
|
|
20211
|
+
{
|
|
20212
|
+
memory: {
|
|
20213
|
+
...snapshot.memory,
|
|
20214
|
+
superseded_by: successor.memory_id,
|
|
20215
|
+
superseded_at: Date.now()
|
|
20216
|
+
},
|
|
20217
|
+
expectedVersion: snapshot
|
|
20218
|
+
}
|
|
20219
|
+
])
|
|
20220
|
+
);
|
|
20221
|
+
return { created: rows[0], retired: true };
|
|
20222
|
+
}
|
|
20223
|
+
};
|
|
20224
|
+
return { prepare, port };
|
|
20225
|
+
};
|
|
20226
|
+
return {
|
|
20227
|
+
recall: async (query, recallOptions = {}) => {
|
|
20228
|
+
const { prepare } = operation("recall");
|
|
20229
|
+
return recall(
|
|
20230
|
+
query,
|
|
20231
|
+
{
|
|
20232
|
+
embeddingOptions,
|
|
20233
|
+
factSource: {
|
|
20234
|
+
graphRanking: options.graphRanking,
|
|
20235
|
+
temporalRanking: options.temporalRanking,
|
|
20236
|
+
search: async (text12, searchOptions) => {
|
|
20237
|
+
const prepared = await prepare(text12, searchOptions);
|
|
20238
|
+
const ranked = await rankPreparedVaultCandidates(
|
|
20239
|
+
text12,
|
|
20240
|
+
prepared,
|
|
20241
|
+
embeddingOptions,
|
|
20242
|
+
searchOptions
|
|
20243
|
+
);
|
|
20244
|
+
return {
|
|
20245
|
+
...ranked,
|
|
20246
|
+
rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
|
|
20247
|
+
decryptLast: true,
|
|
20248
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
20249
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
20250
|
+
rowsEmbedded: 0
|
|
20251
|
+
};
|
|
20252
|
+
}
|
|
20253
|
+
}
|
|
20254
|
+
},
|
|
20255
|
+
{ ...recallOptions, types: ["fact"] }
|
|
20256
|
+
);
|
|
20257
|
+
},
|
|
20258
|
+
retain: async (content, retainOptions) => {
|
|
20259
|
+
const { port } = operation("retain");
|
|
20260
|
+
return retainWithPersistence(
|
|
20261
|
+
content,
|
|
20262
|
+
{
|
|
20263
|
+
persistence: port,
|
|
20264
|
+
embeddingOptions,
|
|
20265
|
+
vaultCache: /* @__PURE__ */ new Map(),
|
|
20266
|
+
normalizeEmbedding: storedVector
|
|
20267
|
+
},
|
|
20268
|
+
retainOptions
|
|
20269
|
+
);
|
|
20270
|
+
}
|
|
20271
|
+
};
|
|
20272
|
+
}
|
|
20273
|
+
|
|
19471
20274
|
// src/lib/memory/synthesizeProfile.ts
|
|
19472
20275
|
init_internalFlowMarker();
|
|
19473
20276
|
init_logger();
|
|
@@ -22893,7 +23696,7 @@ function useChat(options) {
|
|
|
22893
23696
|
|
|
22894
23697
|
// src/expo/useChatStorage.ts
|
|
22895
23698
|
var import_react5 = require("react");
|
|
22896
|
-
var
|
|
23699
|
+
var import_uuid6 = require("uuid");
|
|
22897
23700
|
init_clientConfig();
|
|
22898
23701
|
|
|
22899
23702
|
// src/lib/chat/assembleMessages.ts
|
|
@@ -23556,9 +24359,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
|
|
|
23556
24359
|
}
|
|
23557
24360
|
|
|
23558
24361
|
// src/lib/db/media/types.ts
|
|
23559
|
-
var
|
|
24362
|
+
var import_uuid5 = require("uuid");
|
|
23560
24363
|
function generateMediaId() {
|
|
23561
|
-
return `media_${(0,
|
|
24364
|
+
return `media_${(0, import_uuid5.v7)()}`;
|
|
23562
24365
|
}
|
|
23563
24366
|
|
|
23564
24367
|
// src/lib/db/media/operations.ts
|
|
@@ -23769,10 +24572,10 @@ function extractImageModelFromToolEvents(toolCallEvents) {
|
|
|
23769
24572
|
}
|
|
23770
24573
|
return void 0;
|
|
23771
24574
|
}
|
|
23772
|
-
function storedToLlmapiMessage(
|
|
23773
|
-
const content = [{ type: "text", text:
|
|
23774
|
-
if (
|
|
23775
|
-
for (const file of
|
|
24575
|
+
function storedToLlmapiMessage(stored2) {
|
|
24576
|
+
const content = [{ type: "text", text: stored2.content }];
|
|
24577
|
+
if (stored2.role !== "assistant" && stored2.files?.length) {
|
|
24578
|
+
for (const file of stored2.files) {
|
|
23776
24579
|
if (isSendableImageURL(file.url)) {
|
|
23777
24580
|
content.push({
|
|
23778
24581
|
type: "image_url",
|
|
@@ -23782,11 +24585,11 @@ function storedToLlmapiMessage(stored) {
|
|
|
23782
24585
|
}
|
|
23783
24586
|
}
|
|
23784
24587
|
const messages = [];
|
|
23785
|
-
if (
|
|
24588
|
+
if (stored2.role === "assistant" && stored2.toolCallEvents?.length) {
|
|
23786
24589
|
messages.push({
|
|
23787
|
-
role:
|
|
24590
|
+
role: stored2.role,
|
|
23788
24591
|
content: void 0,
|
|
23789
|
-
tool_calls:
|
|
24592
|
+
tool_calls: stored2.toolCallEvents.map((event) => ({
|
|
23790
24593
|
id: event.id,
|
|
23791
24594
|
type: "function",
|
|
23792
24595
|
function: {
|
|
@@ -23795,7 +24598,7 @@ function storedToLlmapiMessage(stored) {
|
|
|
23795
24598
|
}
|
|
23796
24599
|
}))
|
|
23797
24600
|
});
|
|
23798
|
-
for (const event of
|
|
24601
|
+
for (const event of stored2.toolCallEvents) {
|
|
23799
24602
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
23800
24603
|
messages.push({
|
|
23801
24604
|
role: "tool",
|
|
@@ -23804,14 +24607,14 @@ function storedToLlmapiMessage(stored) {
|
|
|
23804
24607
|
});
|
|
23805
24608
|
}
|
|
23806
24609
|
}
|
|
23807
|
-
const postToolText =
|
|
24610
|
+
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();
|
|
23808
24611
|
messages.push({
|
|
23809
|
-
role:
|
|
24612
|
+
role: stored2.role,
|
|
23810
24613
|
content: [{ type: "text", text: postToolText }]
|
|
23811
24614
|
});
|
|
23812
24615
|
} else {
|
|
23813
24616
|
messages.push({
|
|
23814
|
-
role:
|
|
24617
|
+
role: stored2.role,
|
|
23815
24618
|
content
|
|
23816
24619
|
});
|
|
23817
24620
|
}
|
|
@@ -24518,7 +25321,7 @@ function useChatStorage(options) {
|
|
|
24518
25321
|
};
|
|
24519
25322
|
};
|
|
24520
25323
|
pendingResumeRef.current = null;
|
|
24521
|
-
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0,
|
|
25324
|
+
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0, import_uuid6.v7)()}` : void 0);
|
|
24522
25325
|
const embedToolText = (text12, mask, masked, token) => {
|
|
24523
25326
|
const opts = {
|
|
24524
25327
|
getToken: token,
|
|
@@ -25036,7 +25839,7 @@ function useChatStorage(options) {
|
|
|
25036
25839
|
const detachedResult = result;
|
|
25037
25840
|
if (detachedResult.detached) {
|
|
25038
25841
|
recordToolSetTurn(database, convId, matchedToolSets);
|
|
25039
|
-
const rowId = effectiveAssistantUniqueId ?? `msg_${(0,
|
|
25842
|
+
const rowId = effectiveAssistantUniqueId ?? `msg_${(0, import_uuid6.v7)()}`;
|
|
25040
25843
|
pendingResumeRef.current = {
|
|
25041
25844
|
handle: detachedResult.resume ?? null,
|
|
25042
25845
|
convId,
|
|
@@ -25556,6 +26359,7 @@ function useChatStorage(options) {
|
|
|
25556
26359
|
QueueManager,
|
|
25557
26360
|
RECALL_MAX_LIMIT,
|
|
25558
26361
|
RECALL_TOOL_NAME,
|
|
26362
|
+
RemoteMemoryError,
|
|
25559
26363
|
RerankerUnavailableError,
|
|
25560
26364
|
SDK_SCHEMA_VERSION,
|
|
25561
26365
|
SHORT_TTL_MS,
|
|
@@ -25619,6 +26423,8 @@ function useChatStorage(options) {
|
|
|
25619
26423
|
createNotionTools,
|
|
25620
26424
|
createPlatformCursorStore,
|
|
25621
26425
|
createRecallTool,
|
|
26426
|
+
createRemoteMemoryPersistence,
|
|
26427
|
+
createRemoteMemoryPipeline,
|
|
25622
26428
|
createStockPricePreProcessor,
|
|
25623
26429
|
createStreamingDeAnonymizer,
|
|
25624
26430
|
createVaultEmbeddingCache,
|