@anuma/sdk 6.33.2 → 6.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +1304 -300
- package/dist/expo/index.d.mts +278 -11
- package/dist/expo/index.d.ts +278 -11
- package/dist/expo/index.mjs +1297 -300
- package/dist/index.cjs +18 -6
- package/dist/index.mjs +18 -6
- package/dist/memory/context.d.mts +21 -1
- package/dist/memory/context.d.ts +21 -1
- package/dist/react/index.cjs +1385 -381
- package/dist/react/index.d.mts +311 -11
- package/dist/react/index.d.ts +311 -11
- package/dist/react/index.mjs +1378 -381
- package/dist/server/index.cjs +319 -99
- package/dist/server/index.d.mts +138 -11
- package/dist/server/index.d.ts +138 -11
- package/dist/server/index.mjs +316 -99
- package/dist/telemetry/index.d.mts +3 -4
- package/dist/telemetry/index.d.ts +3 -4
- package/dist/tools/selection/index.cjs +18 -6
- package/dist/tools/selection/index.mjs +18 -6
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -1389,6 +1389,9 @@ __export(index_exports, {
|
|
|
1389
1389
|
LoggerProvider: () => LoggerProvider,
|
|
1390
1390
|
MAX_HOPS: () => MAX_HOPS,
|
|
1391
1391
|
MEDIUM_TTL_MS: () => MEDIUM_TTL_MS,
|
|
1392
|
+
MEMORY_KINDS: () => MEMORY_KINDS,
|
|
1393
|
+
MEMORY_LEVELS: () => MEMORY_LEVELS,
|
|
1394
|
+
MemoryLevelError: () => MemoryLevelError,
|
|
1392
1395
|
NEVER_TTL_MS: () => NEVER_TTL_MS,
|
|
1393
1396
|
NODE_BUDGET: () => NODE_BUDGET,
|
|
1394
1397
|
NOTION_OAUTH_CONFIG: () => NOTION_OAUTH_CONFIG,
|
|
@@ -1399,6 +1402,7 @@ __export(index_exports, {
|
|
|
1399
1402
|
QueueManager: () => QueueManager,
|
|
1400
1403
|
RECALL_MAX_LIMIT: () => RECALL_MAX_LIMIT,
|
|
1401
1404
|
RECALL_TOOL_NAME: () => RECALL_TOOL_NAME,
|
|
1405
|
+
RemoteMemoryError: () => RemoteMemoryError,
|
|
1402
1406
|
RerankerUnavailableError: () => RerankerUnavailableError,
|
|
1403
1407
|
SDK_SCHEMA_VERSION: () => SDK_SCHEMA_VERSION,
|
|
1404
1408
|
SHORT_TTL_MS: () => SHORT_TTL_MS,
|
|
@@ -1462,6 +1466,8 @@ __export(index_exports, {
|
|
|
1462
1466
|
createNotionTools: () => createNotionTools,
|
|
1463
1467
|
createPlatformCursorStore: () => createPlatformCursorStore,
|
|
1464
1468
|
createRecallTool: () => createRecallTool,
|
|
1469
|
+
createRemoteMemoryPersistence: () => createRemoteMemoryPersistence,
|
|
1470
|
+
createRemoteMemoryPipeline: () => createRemoteMemoryPipeline,
|
|
1465
1471
|
createStockPricePreProcessor: () => createStockPricePreProcessor,
|
|
1466
1472
|
createStreamingDeAnonymizer: () => createStreamingDeAnonymizer,
|
|
1467
1473
|
createVaultEmbeddingCache: () => createVaultEmbeddingCache,
|
|
@@ -4177,13 +4183,13 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4177
4183
|
const storedById = new Map(
|
|
4178
4184
|
await Promise.all(
|
|
4179
4185
|
Array.from(uniqueMessages, async ([id, m]) => {
|
|
4180
|
-
const
|
|
4186
|
+
const stored2 = await messageRawToStored(
|
|
4181
4187
|
m,
|
|
4182
4188
|
ctx.walletAddress,
|
|
4183
4189
|
ctx.signMessage,
|
|
4184
4190
|
ctx.embeddedWalletSigner
|
|
4185
4191
|
);
|
|
4186
|
-
return [id,
|
|
4192
|
+
return [id, stored2];
|
|
4187
4193
|
})
|
|
4188
4194
|
)
|
|
4189
4195
|
);
|
|
@@ -4201,18 +4207,18 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4201
4207
|
})
|
|
4202
4208
|
);
|
|
4203
4209
|
return topK.map(({ message, similarity, chunkTextSource }) => {
|
|
4204
|
-
const
|
|
4210
|
+
const stored2 = { ...storedById.get(message.id) };
|
|
4205
4211
|
let chunkText2;
|
|
4206
4212
|
if (chunkTextSource.kind === "chunk") {
|
|
4207
|
-
chunkText2 = resolveChunkText(
|
|
4213
|
+
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
4208
4214
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
4209
4215
|
const state = chunkStateByMsgId.get(message.id);
|
|
4210
4216
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
4211
|
-
chunkText2 = resolveChunkText(
|
|
4217
|
+
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
4212
4218
|
} else {
|
|
4213
|
-
chunkText2 =
|
|
4219
|
+
chunkText2 = stored2.content;
|
|
4214
4220
|
}
|
|
4215
|
-
return { chunkText: chunkText2, message:
|
|
4221
|
+
return { chunkText: chunkText2, message: stored2, similarity };
|
|
4216
4222
|
});
|
|
4217
4223
|
}
|
|
4218
4224
|
function makeSyntheticStoredMessage(opts) {
|
|
@@ -5336,7 +5342,7 @@ async function embedOne(text12, options, outer) {
|
|
|
5336
5342
|
}
|
|
5337
5343
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
5338
5344
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
5339
|
-
async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs) {
|
|
5345
|
+
async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs, outer) {
|
|
5340
5346
|
const response = await withEmbeddingRetry(
|
|
5341
5347
|
() => withDeadline(
|
|
5342
5348
|
(signal) => postApiV1Embeddings({
|
|
@@ -5346,8 +5352,10 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
|
|
|
5346
5352
|
...signal && { signal }
|
|
5347
5353
|
}),
|
|
5348
5354
|
timeoutMs,
|
|
5349
|
-
"embedding batch request"
|
|
5350
|
-
|
|
5355
|
+
"embedding batch request",
|
|
5356
|
+
outer
|
|
5357
|
+
),
|
|
5358
|
+
outer
|
|
5351
5359
|
);
|
|
5352
5360
|
if (response.error) {
|
|
5353
5361
|
throw embeddingErrorFrom(response);
|
|
@@ -5365,6 +5373,11 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
|
|
|
5365
5373
|
}
|
|
5366
5374
|
async function generateEmbeddings(texts, options) {
|
|
5367
5375
|
if (texts.length === 0) return [];
|
|
5376
|
+
const total = options.totalTimeoutMs;
|
|
5377
|
+
if (total === void 0) return embedMany(texts, options, void 0);
|
|
5378
|
+
return withDeadline((signal) => embedMany(texts, options, signal), total, "embedding batch");
|
|
5379
|
+
}
|
|
5380
|
+
async function embedMany(texts, options, outer) {
|
|
5368
5381
|
const { baseUrl = BASE_URL, model, batchSize, cache } = options;
|
|
5369
5382
|
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
5370
5383
|
const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
|
|
@@ -5385,7 +5398,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
5385
5398
|
if (uncachedTexts.length === 0) {
|
|
5386
5399
|
return results;
|
|
5387
5400
|
}
|
|
5388
|
-
const headers = await resolveAuthHeaders(options);
|
|
5401
|
+
const headers = await resolveAuthHeaders(options, outer);
|
|
5402
|
+
if (outer?.aborted) throw outer.reason;
|
|
5389
5403
|
const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
5390
5404
|
let newEmbeddings;
|
|
5391
5405
|
if (uncachedTexts.length <= chunkSize) {
|
|
@@ -5396,7 +5410,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
5396
5410
|
embeddingModel,
|
|
5397
5411
|
options.onUsage,
|
|
5398
5412
|
options.maskInput,
|
|
5399
|
-
timeoutMs
|
|
5413
|
+
timeoutMs,
|
|
5414
|
+
outer
|
|
5400
5415
|
);
|
|
5401
5416
|
} else {
|
|
5402
5417
|
const chunks = [];
|
|
@@ -5407,6 +5422,7 @@ async function generateEmbeddings(texts, options) {
|
|
|
5407
5422
|
let nextIndex = 0;
|
|
5408
5423
|
const worker = async () => {
|
|
5409
5424
|
while (nextIndex < chunks.length) {
|
|
5425
|
+
if (outer?.aborted) throw outer.reason;
|
|
5410
5426
|
const idx = nextIndex++;
|
|
5411
5427
|
allEmbeddings[idx] = await generateEmbeddingsBatch(
|
|
5412
5428
|
chunks[idx],
|
|
@@ -5415,7 +5431,8 @@ async function generateEmbeddings(texts, options) {
|
|
|
5415
5431
|
embeddingModel,
|
|
5416
5432
|
options.onUsage,
|
|
5417
5433
|
options.maskInput,
|
|
5418
|
-
timeoutMs
|
|
5434
|
+
timeoutMs,
|
|
5435
|
+
outer
|
|
5419
5436
|
);
|
|
5420
5437
|
}
|
|
5421
5438
|
};
|
|
@@ -5426,6 +5443,7 @@ async function generateEmbeddings(texts, options) {
|
|
|
5426
5443
|
await Promise.all(workers);
|
|
5427
5444
|
newEmbeddings = allEmbeddings.flat();
|
|
5428
5445
|
}
|
|
5446
|
+
if (outer?.aborted) throw outer.reason;
|
|
5429
5447
|
for (let i = 0; i < uncachedIndices.length; i++) {
|
|
5430
5448
|
const f32Embedding = Float32Array.from(newEmbeddings[i]);
|
|
5431
5449
|
results[uncachedIndices[i]] = Array.from(f32Embedding);
|
|
@@ -10514,15 +10532,15 @@ function createSummaryContext(database) {
|
|
|
10514
10532
|
summariesCollection: database.get("conversation_summaries")
|
|
10515
10533
|
};
|
|
10516
10534
|
}
|
|
10517
|
-
function modelToStored(
|
|
10535
|
+
function modelToStored(record2) {
|
|
10518
10536
|
return {
|
|
10519
|
-
uniqueId:
|
|
10520
|
-
conversationId:
|
|
10521
|
-
summary:
|
|
10522
|
-
summarizedUpTo:
|
|
10523
|
-
tokenCount:
|
|
10524
|
-
createdAt:
|
|
10525
|
-
updatedAt:
|
|
10537
|
+
uniqueId: record2.id,
|
|
10538
|
+
conversationId: record2.conversationId,
|
|
10539
|
+
summary: record2.summary,
|
|
10540
|
+
summarizedUpTo: record2.summarizedUpTo,
|
|
10541
|
+
tokenCount: record2.tokenCount,
|
|
10542
|
+
createdAt: record2.createdAt,
|
|
10543
|
+
updatedAt: record2.updatedAt
|
|
10526
10544
|
};
|
|
10527
10545
|
}
|
|
10528
10546
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
@@ -10531,17 +10549,17 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
10531
10549
|
return modelToStored(results[0]);
|
|
10532
10550
|
}
|
|
10533
10551
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
10534
|
-
let
|
|
10552
|
+
let record2;
|
|
10535
10553
|
await ctx.database.write(async () => {
|
|
10536
10554
|
const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
10537
10555
|
if (existing.length > 0) {
|
|
10538
|
-
|
|
10556
|
+
record2 = await existing[0].update((rec) => {
|
|
10539
10557
|
rec.summary = summary;
|
|
10540
10558
|
rec.summarizedUpTo = summarizedUpTo;
|
|
10541
10559
|
rec.tokenCount = tokenCount;
|
|
10542
10560
|
});
|
|
10543
10561
|
} else {
|
|
10544
|
-
|
|
10562
|
+
record2 = await ctx.summariesCollection.create((rec) => {
|
|
10545
10563
|
rec.conversationId = conversationId;
|
|
10546
10564
|
rec.summary = summary;
|
|
10547
10565
|
rec.summarizedUpTo = summarizedUpTo;
|
|
@@ -10549,13 +10567,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
|
|
|
10549
10567
|
});
|
|
10550
10568
|
}
|
|
10551
10569
|
});
|
|
10552
|
-
return modelToStored(
|
|
10570
|
+
return modelToStored(record2);
|
|
10553
10571
|
}
|
|
10554
10572
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
10555
10573
|
await ctx.database.write(async () => {
|
|
10556
10574
|
const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
10557
|
-
for (const
|
|
10558
|
-
await
|
|
10575
|
+
for (const record2 of existing) {
|
|
10576
|
+
await record2.destroyPermanently();
|
|
10559
10577
|
}
|
|
10560
10578
|
});
|
|
10561
10579
|
}
|
|
@@ -10803,6 +10821,15 @@ __decorateClass([
|
|
|
10803
10821
|
__decorateClass([
|
|
10804
10822
|
(0, import_decorators6.text)("scope")
|
|
10805
10823
|
], VaultMemory.prototype, "scope", 2);
|
|
10824
|
+
__decorateClass([
|
|
10825
|
+
(0, import_decorators6.field)("kind")
|
|
10826
|
+
], VaultMemory.prototype, "kind", 2);
|
|
10827
|
+
__decorateClass([
|
|
10828
|
+
(0, import_decorators6.field)("kind_value")
|
|
10829
|
+
], VaultMemory.prototype, "kindValue", 2);
|
|
10830
|
+
__decorateClass([
|
|
10831
|
+
(0, import_decorators6.field)("level")
|
|
10832
|
+
], VaultMemory.prototype, "level", 2);
|
|
10806
10833
|
__decorateClass([
|
|
10807
10834
|
(0, import_decorators6.field)("folder_id")
|
|
10808
10835
|
], VaultMemory.prototype, "folderId", 2);
|
|
@@ -11028,7 +11055,7 @@ __decorateClass([
|
|
|
11028
11055
|
], VaultFolder.prototype, "context", 2);
|
|
11029
11056
|
|
|
11030
11057
|
// src/lib/db/schema.ts
|
|
11031
|
-
var SDK_SCHEMA_VERSION =
|
|
11058
|
+
var SDK_SCHEMA_VERSION = 48;
|
|
11032
11059
|
var sdkSchema = (0, import_watermelondb17.appSchema)({
|
|
11033
11060
|
version: SDK_SCHEMA_VERSION,
|
|
11034
11061
|
tables: [
|
|
@@ -11123,6 +11150,9 @@ var sdkSchema = (0, import_watermelondb17.appSchema)({
|
|
|
11123
11150
|
columns: [
|
|
11124
11151
|
{ name: "content", type: "string" },
|
|
11125
11152
|
{ name: "scope", type: "string", isIndexed: true },
|
|
11153
|
+
{ name: "kind", type: "string", isOptional: true, isIndexed: true },
|
|
11154
|
+
{ name: "kind_value", type: "string", isOptional: true },
|
|
11155
|
+
{ name: "level", type: "string", isOptional: true, isIndexed: true },
|
|
11126
11156
|
{ name: "folder_id", type: "string", isOptional: true, isIndexed: true },
|
|
11127
11157
|
{ name: "created_at", type: "number", isIndexed: true },
|
|
11128
11158
|
{ name: "updated_at", type: "number", isIndexed: true },
|
|
@@ -11799,6 +11829,22 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
11799
11829
|
]
|
|
11800
11830
|
})
|
|
11801
11831
|
]
|
|
11832
|
+
},
|
|
11833
|
+
{
|
|
11834
|
+
toVersion: 48,
|
|
11835
|
+
steps: [
|
|
11836
|
+
(0, import_migrations2.addColumns)({
|
|
11837
|
+
table: "memory_vault",
|
|
11838
|
+
columns: [
|
|
11839
|
+
{ name: "kind", type: "string", isOptional: true, isIndexed: true },
|
|
11840
|
+
{ name: "kind_value", type: "string", isOptional: true },
|
|
11841
|
+
{ name: "level", type: "string", isOptional: true, isIndexed: true }
|
|
11842
|
+
]
|
|
11843
|
+
}),
|
|
11844
|
+
(0, import_migrations2.unsafeExecuteSql)(
|
|
11845
|
+
"UPDATE memory_vault SET level = CASE WHEN scope IN ('shared', 'public') THEN 'matching' ELSE 'private' END WHERE level IS NULL;"
|
|
11846
|
+
)
|
|
11847
|
+
]
|
|
11802
11848
|
}
|
|
11803
11849
|
]
|
|
11804
11850
|
});
|
|
@@ -12056,25 +12102,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
12056
12102
|
const kindBackfills = existing.filter((e) => {
|
|
12057
12103
|
const incoming = kindByName.get(e.canonicalName);
|
|
12058
12104
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
12059
|
-
}).map((
|
|
12105
|
+
}).map((record2) => ({ record: record2, kind: kindByName.get(record2.canonicalName) }));
|
|
12060
12106
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
12061
12107
|
const created = missing.map(
|
|
12062
|
-
(name) => ctx.entityCollection.prepareCreate((
|
|
12063
|
-
|
|
12108
|
+
(name) => ctx.entityCollection.prepareCreate((record2) => {
|
|
12109
|
+
record2._setRaw("canonical_name", name);
|
|
12064
12110
|
const kind = kindByName.get(name);
|
|
12065
|
-
if (kind !== void 0)
|
|
12111
|
+
if (kind !== void 0) record2._setRaw("kind", kind);
|
|
12066
12112
|
})
|
|
12067
12113
|
);
|
|
12068
12114
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
12069
|
-
for (const
|
|
12070
|
-
for (const { record, kind } of kindBackfills) {
|
|
12071
|
-
out.set(
|
|
12115
|
+
for (const record2 of created) out.set(record2.canonicalName, entityToStored(record2));
|
|
12116
|
+
for (const { record: record2, kind } of kindBackfills) {
|
|
12117
|
+
out.set(record2.canonicalName, { ...entityToStored(record2), kind });
|
|
12072
12118
|
}
|
|
12073
12119
|
return { entities: out, operations: created, kindBackfills };
|
|
12074
12120
|
}
|
|
12075
12121
|
function prepareKindBackfills(backfills) {
|
|
12076
12122
|
return backfills.map(
|
|
12077
|
-
({ record, kind }) =>
|
|
12123
|
+
({ record: record2, kind }) => record2.prepareUpdate((r) => {
|
|
12078
12124
|
r._setRaw("kind", kind);
|
|
12079
12125
|
})
|
|
12080
12126
|
);
|
|
@@ -12105,10 +12151,10 @@ function displayNamesOf(entities) {
|
|
|
12105
12151
|
}
|
|
12106
12152
|
return out;
|
|
12107
12153
|
}
|
|
12108
|
-
function topicsEqual(
|
|
12109
|
-
if (
|
|
12154
|
+
function topicsEqual(stored2, computed) {
|
|
12155
|
+
if (stored2 === null || stored2.length !== computed.length) return false;
|
|
12110
12156
|
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
12111
|
-
const storedKeys =
|
|
12157
|
+
const storedKeys = stored2.map(key).sort();
|
|
12112
12158
|
const computedKeys = computed.map(key).sort();
|
|
12113
12159
|
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
12114
12160
|
}
|
|
@@ -12174,10 +12220,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
12174
12220
|
return;
|
|
12175
12221
|
}
|
|
12176
12222
|
const linkOps = toCreate.map(
|
|
12177
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
if (userId !== void 0)
|
|
12223
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
12224
|
+
record2._setRaw("memory_id", memoryId);
|
|
12225
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
12226
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
12181
12227
|
})
|
|
12182
12228
|
);
|
|
12183
12229
|
await ctx.database.batch(
|
|
@@ -12245,10 +12291,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
12245
12291
|
...entityOps,
|
|
12246
12292
|
...prepareKindBackfills(kindBackfills),
|
|
12247
12293
|
...toCreate.map(
|
|
12248
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
if (userId !== void 0)
|
|
12294
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
|
|
12295
|
+
record2._setRaw("memory_id", memoryId);
|
|
12296
|
+
record2._setRaw("entity_id", e.uniqueId);
|
|
12297
|
+
if (userId !== void 0) record2._setRaw("user_id", userId);
|
|
12252
12298
|
})
|
|
12253
12299
|
),
|
|
12254
12300
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
@@ -12366,13 +12412,54 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
|
|
|
12366
12412
|
}
|
|
12367
12413
|
}
|
|
12368
12414
|
const decryptedContent = await decryptField(memory.content, address);
|
|
12415
|
+
const decryptedKindValue = typeof memory.kindValue === "string" ? await decryptField(memory.kindValue, address) : memory.kindValue;
|
|
12369
12416
|
return {
|
|
12370
12417
|
...memory,
|
|
12371
|
-
content: decryptedContent
|
|
12418
|
+
content: decryptedContent,
|
|
12419
|
+
...decryptedKindValue !== void 0 && { kindValue: decryptedKindValue }
|
|
12372
12420
|
};
|
|
12373
12421
|
}
|
|
12374
12422
|
|
|
12375
12423
|
// src/lib/db/memoryVault/types.ts
|
|
12424
|
+
var MEMORY_KINDS = [
|
|
12425
|
+
"display_name",
|
|
12426
|
+
"birth_date",
|
|
12427
|
+
"bio",
|
|
12428
|
+
"occupation",
|
|
12429
|
+
"interest",
|
|
12430
|
+
"gender",
|
|
12431
|
+
"height_cm",
|
|
12432
|
+
"looking_for",
|
|
12433
|
+
"politics",
|
|
12434
|
+
"religion",
|
|
12435
|
+
"ethnicity",
|
|
12436
|
+
"smoking",
|
|
12437
|
+
"drinking",
|
|
12438
|
+
"exercise",
|
|
12439
|
+
"sexuality",
|
|
12440
|
+
"prompt"
|
|
12441
|
+
];
|
|
12442
|
+
var MEMORY_LEVELS = ["private", "matching", "profile"];
|
|
12443
|
+
var MemoryLevelError = class extends Error {
|
|
12444
|
+
constructor(message) {
|
|
12445
|
+
super(message);
|
|
12446
|
+
this.name = "MemoryLevelError";
|
|
12447
|
+
}
|
|
12448
|
+
};
|
|
12449
|
+
var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
|
|
12450
|
+
function levelFromScope(scope) {
|
|
12451
|
+
return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
|
|
12452
|
+
}
|
|
12453
|
+
function scopeForLevel(level) {
|
|
12454
|
+
return level === "private" ? "private" : "shared";
|
|
12455
|
+
}
|
|
12456
|
+
function resolveMemoryLevel(level, scope) {
|
|
12457
|
+
return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
|
|
12458
|
+
}
|
|
12459
|
+
function levelForScopeChange(current, nextScope) {
|
|
12460
|
+
const implied = levelFromScope(nextScope);
|
|
12461
|
+
return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
|
|
12462
|
+
}
|
|
12376
12463
|
function parseMedia(value) {
|
|
12377
12464
|
if (typeof value !== "string" || value === "") return null;
|
|
12378
12465
|
try {
|
|
@@ -12402,8 +12489,58 @@ function visibilityConditions(requested) {
|
|
|
12402
12489
|
if (excluded.length === 0) return [];
|
|
12403
12490
|
return [import_watermelondb20.Q.or(import_watermelondb20.Q.where("visibility", null), import_watermelondb20.Q.where("visibility", import_watermelondb20.Q.notIn(excluded)))];
|
|
12404
12491
|
}
|
|
12405
|
-
function
|
|
12406
|
-
return
|
|
12492
|
+
function isKinded(record2) {
|
|
12493
|
+
return record2.kind !== null && record2.kind !== void 0;
|
|
12494
|
+
}
|
|
12495
|
+
function assertValidKindLevel(kind, level) {
|
|
12496
|
+
const hasKind = kind !== null && kind !== void 0;
|
|
12497
|
+
if (hasKind && !MEMORY_KINDS.includes(kind)) {
|
|
12498
|
+
throw new MemoryLevelError(`Unknown memory kind: ${kind}`);
|
|
12499
|
+
}
|
|
12500
|
+
if (level !== void 0 && !MEMORY_LEVELS.includes(level)) {
|
|
12501
|
+
throw new MemoryLevelError(`Unknown memory level: ${level}`);
|
|
12502
|
+
}
|
|
12503
|
+
if (level === "profile" && !hasKind) {
|
|
12504
|
+
throw new MemoryLevelError("Only a memory with a kind can be at level 'profile'");
|
|
12505
|
+
}
|
|
12506
|
+
}
|
|
12507
|
+
function resolveCreateLevel(opts) {
|
|
12508
|
+
if (opts.level !== void 0) return { level: opts.level, scope: scopeForLevel(opts.level) };
|
|
12509
|
+
if (opts.scope !== void 0) return { level: levelFromScope(opts.scope), scope: opts.scope };
|
|
12510
|
+
return { level: "private", scope: "private" };
|
|
12511
|
+
}
|
|
12512
|
+
async function encryptKindValue(ctx, value) {
|
|
12513
|
+
if (typeof value !== "string" || !ctx.walletAddress || !ctx.signMessage) return value;
|
|
12514
|
+
return encryptVaultMemoryContent(
|
|
12515
|
+
value,
|
|
12516
|
+
ctx.walletAddress,
|
|
12517
|
+
ctx.signMessage,
|
|
12518
|
+
ctx.embeddedWalletSigner
|
|
12519
|
+
);
|
|
12520
|
+
}
|
|
12521
|
+
function levelConditions(requested) {
|
|
12522
|
+
if (!requested?.length) return [];
|
|
12523
|
+
const published = ["shared", "public"];
|
|
12524
|
+
const wantsMatching = requested.includes("matching");
|
|
12525
|
+
const wantsPrivate = requested.includes("private");
|
|
12526
|
+
const unresolved = import_watermelondb20.Q.or(import_watermelondb20.Q.where("level", null), import_watermelondb20.Q.where("level", import_watermelondb20.Q.notIn([...MEMORY_LEVELS])));
|
|
12527
|
+
const byLevel = import_watermelondb20.Q.where("level", import_watermelondb20.Q.oneOf([...requested]));
|
|
12528
|
+
if (wantsMatching && wantsPrivate) return [import_watermelondb20.Q.or(byLevel, unresolved)];
|
|
12529
|
+
if (wantsMatching) {
|
|
12530
|
+
return [import_watermelondb20.Q.or(byLevel, import_watermelondb20.Q.and(unresolved, import_watermelondb20.Q.where("scope", import_watermelondb20.Q.oneOf(published))))];
|
|
12531
|
+
}
|
|
12532
|
+
if (wantsPrivate) {
|
|
12533
|
+
return [
|
|
12534
|
+
import_watermelondb20.Q.or(
|
|
12535
|
+
byLevel,
|
|
12536
|
+
import_watermelondb20.Q.and(unresolved, import_watermelondb20.Q.or(import_watermelondb20.Q.where("scope", null), import_watermelondb20.Q.where("scope", import_watermelondb20.Q.notIn(published))))
|
|
12537
|
+
)
|
|
12538
|
+
];
|
|
12539
|
+
}
|
|
12540
|
+
return [byLevel];
|
|
12541
|
+
}
|
|
12542
|
+
function isOwnedByCtxUser(ctx, record2) {
|
|
12543
|
+
return ctx.userId === void 0 || record2.userId === ctx.userId;
|
|
12407
12544
|
}
|
|
12408
12545
|
function baseVaultConditions(ctx, options) {
|
|
12409
12546
|
return [
|
|
@@ -12445,6 +12582,9 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
12445
12582
|
uniqueId: memory.id,
|
|
12446
12583
|
content: memory.content,
|
|
12447
12584
|
scope: memory.scope,
|
|
12585
|
+
kind: memory.kind ?? null,
|
|
12586
|
+
kindValue: memory.kindValue ?? null,
|
|
12587
|
+
level: resolveMemoryLevel(memory.level, memory.scope),
|
|
12448
12588
|
folderId: memory.folderId ?? null,
|
|
12449
12589
|
userId: memory.userId ?? null,
|
|
12450
12590
|
embedding: memory.embedding ?? null,
|
|
@@ -12483,42 +12623,48 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
12483
12623
|
}
|
|
12484
12624
|
return raw;
|
|
12485
12625
|
}
|
|
12486
|
-
function populateNewVaultMemory(
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12626
|
+
function populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue) {
|
|
12627
|
+
const { level, scope } = resolveCreateLevel(opts);
|
|
12628
|
+
record2._setRaw("content", encryptedContent);
|
|
12629
|
+
record2._setRaw("scope", scope);
|
|
12630
|
+
record2._setRaw("level", level);
|
|
12631
|
+
record2._setRaw("kind", opts.kind ?? null);
|
|
12632
|
+
record2._setRaw("kind_value", encryptedKindValue ?? null);
|
|
12633
|
+
record2._setRaw("folder_id", opts.folderId ?? null);
|
|
12634
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
12635
|
+
record2._setRaw("is_deleted", false);
|
|
12492
12636
|
if (opts.embedding !== void 0) {
|
|
12493
|
-
|
|
12494
|
-
|
|
12637
|
+
record2._setRaw("embedding", opts.embedding);
|
|
12638
|
+
record2._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
12495
12639
|
}
|
|
12496
12640
|
if (opts.sourceChunkIds !== void 0) {
|
|
12497
|
-
|
|
12641
|
+
record2._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
12498
12642
|
}
|
|
12499
|
-
|
|
12500
|
-
|
|
12643
|
+
record2._setRaw("proof_count", opts.proofCount ?? 1);
|
|
12644
|
+
record2._setRaw("source", opts.source ?? "manual");
|
|
12501
12645
|
if (opts.eventTime) {
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12646
|
+
record2._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
12647
|
+
record2._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
12648
|
+
record2._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
12505
12649
|
}
|
|
12506
12650
|
if (opts.factType !== void 0) {
|
|
12507
|
-
|
|
12651
|
+
record2._setRaw("fact_type", opts.factType);
|
|
12508
12652
|
}
|
|
12509
12653
|
if (opts.trustTier !== void 0) {
|
|
12510
|
-
|
|
12654
|
+
record2._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
12511
12655
|
}
|
|
12512
|
-
|
|
12513
|
-
|
|
12656
|
+
record2._setRaw("visibility", opts.visibility ?? "private");
|
|
12657
|
+
record2._setRaw(
|
|
12514
12658
|
"published_at",
|
|
12515
12659
|
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
12516
12660
|
);
|
|
12517
12661
|
if (opts.geohash !== void 0) {
|
|
12518
|
-
|
|
12662
|
+
record2._setRaw("geohash", opts.geohash);
|
|
12519
12663
|
}
|
|
12520
12664
|
}
|
|
12521
12665
|
async function createVaultMemoryOp(ctx, opts) {
|
|
12666
|
+
assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
12667
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
12522
12668
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
12523
12669
|
opts.content,
|
|
12524
12670
|
ctx.walletAddress,
|
|
@@ -12529,13 +12675,15 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
12529
12675
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
12530
12676
|
throw new Error("Memory source is no longer eligible");
|
|
12531
12677
|
return ctx.vaultMemoryCollection.create(
|
|
12532
|
-
(
|
|
12678
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
12533
12679
|
);
|
|
12534
12680
|
});
|
|
12535
12681
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
12536
12682
|
}
|
|
12537
12683
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
12538
12684
|
if (!targetId) return { created: null, retired: false };
|
|
12685
|
+
assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
12686
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
12539
12687
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
12540
12688
|
opts.content,
|
|
12541
12689
|
ctx.walletAddress,
|
|
@@ -12552,9 +12700,10 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
12552
12700
|
} catch {
|
|
12553
12701
|
return;
|
|
12554
12702
|
}
|
|
12555
|
-
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target))
|
|
12703
|
+
if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
|
|
12704
|
+
return;
|
|
12556
12705
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
12557
|
-
(
|
|
12706
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
12558
12707
|
);
|
|
12559
12708
|
await target.update((r) => {
|
|
12560
12709
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -12618,6 +12767,10 @@ async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
|
|
|
12618
12767
|
}
|
|
12619
12768
|
async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
12620
12769
|
if (optionsArray.length === 0) return [];
|
|
12770
|
+
for (const opts of optionsArray) assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
|
|
12771
|
+
const encryptedKindValues = await Promise.all(
|
|
12772
|
+
optionsArray.map((opts) => encryptKindValue(ctx, opts.kindValue))
|
|
12773
|
+
);
|
|
12621
12774
|
const encryptedContents = await Promise.all(
|
|
12622
12775
|
optionsArray.map(async (opts) => {
|
|
12623
12776
|
if (ctx.walletAddress && ctx.signMessage) {
|
|
@@ -12636,7 +12789,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
12636
12789
|
throw new Error("Memory source is no longer eligible");
|
|
12637
12790
|
const prepared = optionsArray.map(
|
|
12638
12791
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
12639
|
-
(
|
|
12792
|
+
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
12640
12793
|
)
|
|
12641
12794
|
);
|
|
12642
12795
|
await ctx.database.batch(...prepared);
|
|
@@ -12644,16 +12797,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
12644
12797
|
});
|
|
12645
12798
|
return Promise.all(
|
|
12646
12799
|
created.map(
|
|
12647
|
-
(
|
|
12800
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
12648
12801
|
)
|
|
12649
12802
|
);
|
|
12650
12803
|
}
|
|
12651
12804
|
async function getVaultMemoryOp(ctx, id) {
|
|
12652
12805
|
try {
|
|
12653
|
-
const
|
|
12654
|
-
if (
|
|
12806
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
12807
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
12655
12808
|
return vaultMemoryToStored(
|
|
12656
|
-
|
|
12809
|
+
record2,
|
|
12657
12810
|
ctx.walletAddress,
|
|
12658
12811
|
ctx.signMessage,
|
|
12659
12812
|
ctx.embeddedWalletSigner
|
|
@@ -12679,6 +12832,9 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
12679
12832
|
uniqueId: raw.id,
|
|
12680
12833
|
content: raw.content ?? "",
|
|
12681
12834
|
scope: raw.scope ?? "",
|
|
12835
|
+
kind: raw.kind ?? null,
|
|
12836
|
+
kindValue: raw.kind_value ?? null,
|
|
12837
|
+
level: resolveMemoryLevel(raw.level, raw.scope),
|
|
12682
12838
|
folderId: raw.folder_id ?? null,
|
|
12683
12839
|
userId: raw.user_id ?? null,
|
|
12684
12840
|
embedding: raw.embedding ?? null,
|
|
@@ -12711,17 +12867,19 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
12711
12867
|
};
|
|
12712
12868
|
}
|
|
12713
12869
|
async function vaultMemoryRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner) {
|
|
12714
|
-
const
|
|
12870
|
+
const stored2 = vaultMemoryRawToStoredRaw(raw);
|
|
12715
12871
|
if (walletAddress) {
|
|
12716
|
-
return decryptVaultMemoryFields(
|
|
12872
|
+
return decryptVaultMemoryFields(stored2, walletAddress, signMessage, embeddedWalletSigner);
|
|
12717
12873
|
}
|
|
12718
|
-
return
|
|
12874
|
+
return stored2;
|
|
12719
12875
|
}
|
|
12720
12876
|
async function getAllVaultMemoriesOp(ctx, options) {
|
|
12721
12877
|
const conditions = [
|
|
12722
12878
|
...baseVaultConditions(ctx, options),
|
|
12723
12879
|
...options?.scopes?.length ? [import_watermelondb20.Q.where("scope", import_watermelondb20.Q.oneOf(options.scopes))] : [],
|
|
12724
12880
|
...visibilityConditions(options?.visibility),
|
|
12881
|
+
...levelConditions(options?.levels),
|
|
12882
|
+
...options?.kinds?.length ? [import_watermelondb20.Q.where("kind", import_watermelondb20.Q.oneOf(options.kinds))] : [],
|
|
12725
12883
|
...options?.folderId !== void 0 ? [import_watermelondb20.Q.where("folder_id", options.folderId)] : [],
|
|
12726
12884
|
...options?.factTypes?.length ? [import_watermelondb20.Q.where("fact_type", import_watermelondb20.Q.oneOf(options.factTypes))] : [],
|
|
12727
12885
|
import_watermelondb20.Q.sortBy(options?.since ? "updated_at" : "created_at", import_watermelondb20.Q.desc),
|
|
@@ -12867,13 +13025,13 @@ async function getVaultMemoriesByIdsOp(ctx, ids, options) {
|
|
|
12867
13025
|
async function getAllVaultMemoryContentsOp(ctx, options) {
|
|
12868
13026
|
const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, options)).unsafeFetchRaw();
|
|
12869
13027
|
return mapInBatches(results, async (raw) => {
|
|
12870
|
-
const
|
|
13028
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
12871
13029
|
raw,
|
|
12872
13030
|
ctx.walletAddress,
|
|
12873
13031
|
ctx.signMessage,
|
|
12874
13032
|
ctx.embeddedWalletSigner
|
|
12875
13033
|
);
|
|
12876
|
-
return
|
|
13034
|
+
return stored2.content;
|
|
12877
13035
|
});
|
|
12878
13036
|
}
|
|
12879
13037
|
async function countActiveVaultMemoriesOp(ctx) {
|
|
@@ -12888,6 +13046,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12888
13046
|
try {
|
|
12889
13047
|
const probe = await ctx.vaultMemoryCollection.find(id);
|
|
12890
13048
|
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
13049
|
+
if (opts.freeFormOnly && isKinded(probe)) return null;
|
|
13050
|
+
const levelAfter = (current) => {
|
|
13051
|
+
if (opts.level !== void 0) return opts.level;
|
|
13052
|
+
if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
|
|
13053
|
+
return levelForScopeChange(current, opts.scope);
|
|
13054
|
+
};
|
|
13055
|
+
assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
|
|
13056
|
+
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
12891
13057
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
12892
13058
|
opts.content,
|
|
12893
13059
|
ctx.walletAddress,
|
|
@@ -12895,30 +13061,43 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12895
13061
|
ctx.embeddedWalletSigner
|
|
12896
13062
|
) : opts.content;
|
|
12897
13063
|
let stale = false;
|
|
12898
|
-
const
|
|
12899
|
-
const originalUpdatedAt =
|
|
13064
|
+
const record2 = probe;
|
|
13065
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12900
13066
|
await ctx.database.write(async () => {
|
|
12901
13067
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
12902
13068
|
throw new Error("Memory source is no longer eligible");
|
|
12903
|
-
if (
|
|
13069
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
12904
13070
|
stale = true;
|
|
12905
13071
|
return;
|
|
12906
13072
|
}
|
|
13073
|
+
const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
|
|
13074
|
+
const nextLevel = levelAfter(record2);
|
|
13075
|
+
assertValidKindLevel(nextKind, nextLevel);
|
|
12907
13076
|
let observedSources = [];
|
|
12908
13077
|
let replayedObservation = false;
|
|
12909
13078
|
if (opts.observationSourceIds?.length) {
|
|
12910
13079
|
try {
|
|
12911
|
-
const parsed = JSON.parse(
|
|
13080
|
+
const parsed = JSON.parse(record2.sourceChunkIds ?? "[]");
|
|
12912
13081
|
if (Array.isArray(parsed))
|
|
12913
13082
|
observedSources = parsed.filter((id2) => typeof id2 === "string");
|
|
12914
13083
|
} catch {
|
|
12915
13084
|
}
|
|
12916
13085
|
replayedObservation = opts.observationSourceIds.every((id2) => observedSources.includes(id2));
|
|
12917
13086
|
}
|
|
12918
|
-
await
|
|
13087
|
+
await record2.update((r) => {
|
|
12919
13088
|
r._setRaw("content", encryptedContent);
|
|
12920
|
-
if (opts.
|
|
13089
|
+
if (opts.level !== void 0) {
|
|
13090
|
+
r._setRaw("level", nextLevel);
|
|
13091
|
+
r._setRaw("scope", scopeForLevel(nextLevel));
|
|
13092
|
+
} else if (opts.scope !== void 0) {
|
|
12921
13093
|
r._setRaw("scope", opts.scope);
|
|
13094
|
+
r._setRaw("level", nextLevel);
|
|
13095
|
+
}
|
|
13096
|
+
if (opts.kind !== void 0) {
|
|
13097
|
+
r._setRaw("kind", opts.kind);
|
|
13098
|
+
}
|
|
13099
|
+
if (encryptedKindValue !== void 0) {
|
|
13100
|
+
r._setRaw("kind_value", encryptedKindValue);
|
|
12922
13101
|
}
|
|
12923
13102
|
if (opts.folderId !== void 0) {
|
|
12924
13103
|
r._setRaw("folder_id", opts.folderId);
|
|
@@ -12972,12 +13151,13 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
12972
13151
|
});
|
|
12973
13152
|
if (stale) return null;
|
|
12974
13153
|
return vaultMemoryToStored(
|
|
12975
|
-
|
|
13154
|
+
record2,
|
|
12976
13155
|
ctx.walletAddress,
|
|
12977
13156
|
ctx.signMessage,
|
|
12978
13157
|
ctx.embeddedWalletSigner
|
|
12979
13158
|
);
|
|
12980
|
-
} catch {
|
|
13159
|
+
} catch (err) {
|
|
13160
|
+
if (err instanceof MemoryLevelError) throw err;
|
|
12981
13161
|
return null;
|
|
12982
13162
|
}
|
|
12983
13163
|
}
|
|
@@ -12986,21 +13166,21 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
12986
13166
|
if (!entityCtx) {
|
|
12987
13167
|
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
12988
13168
|
}
|
|
12989
|
-
let
|
|
13169
|
+
let record2;
|
|
12990
13170
|
try {
|
|
12991
|
-
|
|
13171
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
12992
13172
|
} catch {
|
|
12993
13173
|
return null;
|
|
12994
13174
|
}
|
|
12995
|
-
if (
|
|
13175
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
12996
13176
|
let stale = false;
|
|
12997
|
-
const originalUpdatedAt =
|
|
13177
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
12998
13178
|
await ctx.database.write(async (writer) => {
|
|
12999
|
-
if (
|
|
13179
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13000
13180
|
stale = true;
|
|
13001
13181
|
return;
|
|
13002
13182
|
}
|
|
13003
|
-
await
|
|
13183
|
+
await record2.update((r) => {
|
|
13004
13184
|
r._setRaw("topics_user_managed", true);
|
|
13005
13185
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
13006
13186
|
});
|
|
@@ -13024,25 +13204,25 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
13024
13204
|
);
|
|
13025
13205
|
});
|
|
13026
13206
|
if (stale) return null;
|
|
13027
|
-
return vaultMemoryToStored(
|
|
13207
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
13028
13208
|
}
|
|
13029
13209
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
13030
|
-
let
|
|
13210
|
+
let record2;
|
|
13031
13211
|
try {
|
|
13032
|
-
|
|
13212
|
+
record2 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
13033
13213
|
} catch {
|
|
13034
13214
|
return false;
|
|
13035
13215
|
}
|
|
13036
|
-
if (
|
|
13037
|
-
const originalUpdatedAt =
|
|
13216
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13217
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13038
13218
|
let cleared = false;
|
|
13039
13219
|
await ctx.database.write(async () => {
|
|
13040
|
-
if (options?.unlessTopicsRecorded && parseTopics(
|
|
13220
|
+
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
13041
13221
|
cleared = true;
|
|
13042
|
-
await
|
|
13222
|
+
await record2.update((r) => {
|
|
13043
13223
|
r._setRaw("topics_user_managed", false);
|
|
13044
13224
|
r._setRaw("topics_extracted_version", null);
|
|
13045
|
-
if (
|
|
13225
|
+
if (record2.topicsExtractedAt === null) {
|
|
13046
13226
|
r._setRaw("topics_extracted_at", originalUpdatedAt);
|
|
13047
13227
|
}
|
|
13048
13228
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -13051,22 +13231,22 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
13051
13231
|
return cleared;
|
|
13052
13232
|
}
|
|
13053
13233
|
async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
13054
|
-
let
|
|
13234
|
+
let record2;
|
|
13055
13235
|
try {
|
|
13056
|
-
|
|
13236
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13057
13237
|
} catch {
|
|
13058
13238
|
return null;
|
|
13059
13239
|
}
|
|
13060
|
-
if (
|
|
13240
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
13061
13241
|
let stale = false;
|
|
13062
13242
|
await ctx.database.write(async () => {
|
|
13063
|
-
if (
|
|
13243
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13064
13244
|
stale = true;
|
|
13065
13245
|
return;
|
|
13066
13246
|
}
|
|
13067
|
-
const currentUpdatedAt =
|
|
13068
|
-
const currentPublishedAt =
|
|
13069
|
-
await
|
|
13247
|
+
const currentUpdatedAt = record2.updatedAt.getTime();
|
|
13248
|
+
const currentPublishedAt = record2.publishedAt ?? null;
|
|
13249
|
+
await record2.update((r) => {
|
|
13070
13250
|
r._setRaw("visibility", opts.visibility);
|
|
13071
13251
|
if (opts.visibility === "private") {
|
|
13072
13252
|
r._setRaw("published_at", null);
|
|
@@ -13080,19 +13260,19 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
13080
13260
|
});
|
|
13081
13261
|
});
|
|
13082
13262
|
if (stale) return null;
|
|
13083
|
-
return vaultMemoryToStored(
|
|
13263
|
+
return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
13084
13264
|
}
|
|
13085
13265
|
async function deleteVaultMemoryOp(ctx, id) {
|
|
13086
13266
|
try {
|
|
13087
|
-
const
|
|
13088
|
-
if (
|
|
13267
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13268
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13089
13269
|
let stale = false;
|
|
13090
13270
|
await ctx.database.write(async () => {
|
|
13091
|
-
if (
|
|
13271
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13092
13272
|
stale = true;
|
|
13093
13273
|
return;
|
|
13094
13274
|
}
|
|
13095
|
-
await
|
|
13275
|
+
await record2.update((r) => {
|
|
13096
13276
|
r._setRaw("is_deleted", true);
|
|
13097
13277
|
});
|
|
13098
13278
|
});
|
|
@@ -13111,8 +13291,9 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
13111
13291
|
async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
13112
13292
|
if (id === supersededById) return false;
|
|
13113
13293
|
try {
|
|
13114
|
-
const
|
|
13115
|
-
if (
|
|
13294
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13295
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13296
|
+
if (isKinded(record2)) return false;
|
|
13116
13297
|
let successor;
|
|
13117
13298
|
try {
|
|
13118
13299
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -13126,7 +13307,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
13126
13307
|
await ctx.database.write(async () => {
|
|
13127
13308
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
13128
13309
|
throw new Error("Memory source is no longer eligible");
|
|
13129
|
-
if (
|
|
13310
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
13130
13311
|
stale = true;
|
|
13131
13312
|
return;
|
|
13132
13313
|
}
|
|
@@ -13134,7 +13315,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
13134
13315
|
stale = true;
|
|
13135
13316
|
return;
|
|
13136
13317
|
}
|
|
13137
|
-
await
|
|
13318
|
+
await record2.update((r) => {
|
|
13138
13319
|
r._setRaw("superseded_by", supersededById);
|
|
13139
13320
|
r._setRaw("superseded_at", Date.now());
|
|
13140
13321
|
});
|
|
@@ -13153,7 +13334,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
13153
13334
|
const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
|
|
13154
13335
|
return mapInBatches(
|
|
13155
13336
|
results,
|
|
13156
|
-
(
|
|
13337
|
+
(record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
13157
13338
|
);
|
|
13158
13339
|
}
|
|
13159
13340
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
@@ -13295,17 +13476,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
13295
13476
|
}
|
|
13296
13477
|
}
|
|
13297
13478
|
const eligible = records.filter(
|
|
13298
|
-
(
|
|
13479
|
+
(record2) => !record2.isDeleted && isOwnedByCtxUser(ctx, record2) && !record2.topicsUserManaged
|
|
13299
13480
|
);
|
|
13300
|
-
const prepared = eligible.map((
|
|
13301
|
-
const originalUpdatedAt =
|
|
13302
|
-
return
|
|
13481
|
+
const prepared = eligible.map((record2) => {
|
|
13482
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13483
|
+
return record2.prepareUpdate((r) => {
|
|
13303
13484
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
13304
13485
|
r._setRaw("topics_extracted_version", version);
|
|
13305
13486
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
13306
13487
|
});
|
|
13307
13488
|
});
|
|
13308
|
-
for (const
|
|
13489
|
+
for (const record2 of eligible) stamped.push(record2.id);
|
|
13309
13490
|
if (prepared.length > 0) await ctx.database.batch(...prepared);
|
|
13310
13491
|
});
|
|
13311
13492
|
}
|
|
@@ -13320,14 +13501,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
13320
13501
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
13321
13502
|
try {
|
|
13322
13503
|
await ctx.database.write(async (writer) => {
|
|
13323
|
-
let
|
|
13504
|
+
let record2;
|
|
13324
13505
|
try {
|
|
13325
|
-
|
|
13506
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13326
13507
|
} catch {
|
|
13327
13508
|
return;
|
|
13328
13509
|
}
|
|
13329
|
-
if (
|
|
13330
|
-
const topics = parseTopics(
|
|
13510
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
13511
|
+
const topics = parseTopics(record2.topics);
|
|
13331
13512
|
if (topics === null) return;
|
|
13332
13513
|
await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics));
|
|
13333
13514
|
relinked.push(id);
|
|
@@ -13352,20 +13533,20 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
13352
13533
|
await ctx.database.write(async () => {
|
|
13353
13534
|
const writes = [];
|
|
13354
13535
|
for (const id of chunkIds) {
|
|
13355
|
-
let
|
|
13536
|
+
let record2;
|
|
13356
13537
|
try {
|
|
13357
|
-
|
|
13538
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13358
13539
|
} catch {
|
|
13359
13540
|
continue;
|
|
13360
13541
|
}
|
|
13361
|
-
if (
|
|
13362
|
-
if (parseTopics(
|
|
13542
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) continue;
|
|
13543
|
+
if (parseTopics(record2.topics) !== null) continue;
|
|
13363
13544
|
const links = await entityCtx.memoryEntityCollection.query(import_watermelondb20.Q.where("memory_id", id)).unsafeFetchRaw();
|
|
13364
13545
|
const entityIds = links.map((l) => String(l.entity_id));
|
|
13365
13546
|
if (entityIds.length === 0) continue;
|
|
13366
13547
|
const entities = await entityCtx.entityCollection.query(import_watermelondb20.Q.where("id", import_watermelondb20.Q.oneOf(entityIds))).fetch();
|
|
13367
13548
|
if (entities.length === 0) continue;
|
|
13368
|
-
const source =
|
|
13549
|
+
const source = record2.topicsUserManaged ? "user" : "auto";
|
|
13369
13550
|
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
13370
13551
|
if (write) writes.push(write);
|
|
13371
13552
|
}
|
|
@@ -13383,7 +13564,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
13383
13564
|
if (records.length === 0) return 0;
|
|
13384
13565
|
await ctx.database.write(async () => {
|
|
13385
13566
|
const prepared = records.map(
|
|
13386
|
-
(
|
|
13567
|
+
(record2) => record2.prepareUpdate((r) => {
|
|
13387
13568
|
r._setRaw("is_deleted", true);
|
|
13388
13569
|
})
|
|
13389
13570
|
);
|
|
@@ -13413,7 +13594,10 @@ function assertVaultScopeForSweep(ctx) {
|
|
|
13413
13594
|
}
|
|
13414
13595
|
async function getDecayCandidatesRawOp(ctx) {
|
|
13415
13596
|
assertVaultScopeForSweep(ctx);
|
|
13416
|
-
const results = await ctx.vaultMemoryCollection.query(
|
|
13597
|
+
const results = await ctx.vaultMemoryCollection.query(
|
|
13598
|
+
...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true }),
|
|
13599
|
+
import_watermelondb20.Q.where("kind", null)
|
|
13600
|
+
).unsafeFetchRaw();
|
|
13417
13601
|
return results.map((raw) => ({
|
|
13418
13602
|
uniqueId: raw.id,
|
|
13419
13603
|
factType: raw.fact_type ?? null,
|
|
@@ -13428,20 +13612,20 @@ async function getDecayCandidatesRawOp(ctx) {
|
|
|
13428
13612
|
}
|
|
13429
13613
|
async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
13430
13614
|
try {
|
|
13431
|
-
const
|
|
13432
|
-
if (
|
|
13615
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13616
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13433
13617
|
let stale = false;
|
|
13434
13618
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
13435
13619
|
await ctx.database.write(async () => {
|
|
13436
|
-
if (
|
|
13620
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
13437
13621
|
stale = true;
|
|
13438
13622
|
return;
|
|
13439
13623
|
}
|
|
13440
|
-
if (opts?.expectedUpdatedAt !== void 0 &&
|
|
13624
|
+
if (opts?.expectedUpdatedAt !== void 0 && record2.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record2.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
|
|
13441
13625
|
stale = true;
|
|
13442
13626
|
return;
|
|
13443
13627
|
}
|
|
13444
|
-
await
|
|
13628
|
+
await record2.update((r) => {
|
|
13445
13629
|
r._setRaw("archived_at", archivedAtValue);
|
|
13446
13630
|
});
|
|
13447
13631
|
});
|
|
@@ -13452,15 +13636,15 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
13452
13636
|
}
|
|
13453
13637
|
async function restoreVaultMemoryOp(ctx, id) {
|
|
13454
13638
|
try {
|
|
13455
|
-
const
|
|
13456
|
-
if (
|
|
13639
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13640
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13457
13641
|
let stale = false;
|
|
13458
13642
|
await ctx.database.write(async () => {
|
|
13459
|
-
if (
|
|
13643
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
13460
13644
|
stale = true;
|
|
13461
13645
|
return;
|
|
13462
13646
|
}
|
|
13463
|
-
await
|
|
13647
|
+
await record2.update((r) => {
|
|
13464
13648
|
r._setRaw("archived_at", null);
|
|
13465
13649
|
});
|
|
13466
13650
|
});
|
|
@@ -13471,17 +13655,17 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
13471
13655
|
}
|
|
13472
13656
|
async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
13473
13657
|
try {
|
|
13474
|
-
const
|
|
13475
|
-
if (
|
|
13658
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13659
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13476
13660
|
const now = opts.now ?? Date.now();
|
|
13477
13661
|
let stale = false;
|
|
13478
13662
|
await ctx.database.write(async () => {
|
|
13479
|
-
const archivedAt =
|
|
13480
|
-
if (
|
|
13663
|
+
const archivedAt = record2.archivedAt;
|
|
13664
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
13481
13665
|
stale = true;
|
|
13482
13666
|
return;
|
|
13483
13667
|
}
|
|
13484
|
-
await
|
|
13668
|
+
await record2.update((r) => {
|
|
13485
13669
|
r._setRaw("is_deleted", true);
|
|
13486
13670
|
});
|
|
13487
13671
|
});
|
|
@@ -13499,14 +13683,14 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
13499
13683
|
}
|
|
13500
13684
|
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
13501
13685
|
try {
|
|
13502
|
-
const
|
|
13503
|
-
if (
|
|
13504
|
-
const readUpdatedAt =
|
|
13505
|
-
const readStoredContent =
|
|
13686
|
+
const record2 = await ctx.vaultMemoryCollection.find(id);
|
|
13687
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
13688
|
+
const readUpdatedAt = record2.updatedAt.getTime();
|
|
13689
|
+
const readStoredContent = record2._getRaw("content");
|
|
13506
13690
|
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
13507
13691
|
if (expected?.content !== void 0) {
|
|
13508
13692
|
const current = await vaultMemoryToStored(
|
|
13509
|
-
|
|
13693
|
+
record2,
|
|
13510
13694
|
ctx.walletAddress,
|
|
13511
13695
|
ctx.signMessage,
|
|
13512
13696
|
ctx.embeddedWalletSigner
|
|
@@ -13515,11 +13699,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
13515
13699
|
}
|
|
13516
13700
|
let written = false;
|
|
13517
13701
|
await ctx.database.write(async () => {
|
|
13518
|
-
if (
|
|
13519
|
-
const originalUpdatedAt =
|
|
13520
|
-
if (originalUpdatedAt !== readUpdatedAt ||
|
|
13702
|
+
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
13703
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13704
|
+
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
13521
13705
|
return;
|
|
13522
|
-
await
|
|
13706
|
+
await record2.update((r) => {
|
|
13523
13707
|
r._setRaw("embedding", embedding);
|
|
13524
13708
|
r._setRaw("embedding_model", embeddingModel);
|
|
13525
13709
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -13534,8 +13718,8 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
|
|
|
13534
13718
|
function normalizeForDedupe(content) {
|
|
13535
13719
|
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
13536
13720
|
}
|
|
13537
|
-
async function findQuarantinedDuplicateOp(ctx, content,
|
|
13538
|
-
const wanted = [...new Set(
|
|
13721
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds2, where) {
|
|
13722
|
+
const wanted = [...new Set(sourceIds2)].sort().join("\0");
|
|
13539
13723
|
const target = normalizeForDedupe(content);
|
|
13540
13724
|
const rows = await ctx.vaultMemoryCollection.query(
|
|
13541
13725
|
import_watermelondb20.Q.where("trust_tier", "quarantined"),
|
|
@@ -13554,13 +13738,13 @@ async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
|
13554
13738
|
if (!Array.isArray(ids)) continue;
|
|
13555
13739
|
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
13556
13740
|
if (key !== wanted) continue;
|
|
13557
|
-
const
|
|
13741
|
+
const stored2 = await vaultMemoryRawToStored(
|
|
13558
13742
|
raw,
|
|
13559
13743
|
ctx.walletAddress,
|
|
13560
13744
|
ctx.signMessage,
|
|
13561
13745
|
ctx.embeddedWalletSigner
|
|
13562
13746
|
);
|
|
13563
|
-
if (normalizeForDedupe(
|
|
13747
|
+
if (normalizeForDedupe(stored2.content) === target) return stored2.uniqueId;
|
|
13564
13748
|
}
|
|
13565
13749
|
return null;
|
|
13566
13750
|
}
|
|
@@ -13670,25 +13854,26 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
13670
13854
|
inserted = writable.length;
|
|
13671
13855
|
if (writable.length === 0) return;
|
|
13672
13856
|
const prepared = writable.map(
|
|
13673
|
-
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13857
|
+
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record2) => {
|
|
13858
|
+
record2._raw.id = row.memoryId;
|
|
13859
|
+
record2._setRaw("content", content);
|
|
13860
|
+
record2._setRaw("scope", "shared");
|
|
13861
|
+
record2._setRaw("level", "matching");
|
|
13862
|
+
record2._setRaw("folder_id", null);
|
|
13863
|
+
record2._setRaw("user_id", ctx.userId ?? null);
|
|
13864
|
+
record2._setRaw("is_deleted", false);
|
|
13865
|
+
record2._setRaw("proof_count", 1);
|
|
13866
|
+
record2._setRaw("source", SOURCE_PHOTO);
|
|
13867
|
+
record2._setRaw(
|
|
13683
13868
|
"media",
|
|
13684
13869
|
row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
|
|
13685
13870
|
);
|
|
13686
|
-
|
|
13687
|
-
|
|
13871
|
+
record2._setRaw("visibility", "public");
|
|
13872
|
+
record2._setRaw("published_at", now);
|
|
13688
13873
|
if (row.eventTime) {
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13874
|
+
record2._setRaw("event_time_start", row.eventTime.start ?? null);
|
|
13875
|
+
record2._setRaw("event_time_end", row.eventTime.end ?? null);
|
|
13876
|
+
record2._setRaw("event_time_kind", row.eventTime.kind ?? null);
|
|
13692
13877
|
}
|
|
13693
13878
|
})
|
|
13694
13879
|
);
|
|
@@ -14053,11 +14238,11 @@ function folderToStored(folder) {
|
|
|
14053
14238
|
}
|
|
14054
14239
|
async function createVaultFolderOp(ctx, opts) {
|
|
14055
14240
|
const created = await ctx.database.write(async () => {
|
|
14056
|
-
return ctx.vaultFolderCollection.create((
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14241
|
+
return ctx.vaultFolderCollection.create((record2) => {
|
|
14242
|
+
record2._setRaw("name", opts.name);
|
|
14243
|
+
record2._setRaw("scope", opts.scope ?? "private");
|
|
14244
|
+
record2._setRaw("is_system", opts.isSystem ?? false);
|
|
14245
|
+
record2._setRaw("is_deleted", false);
|
|
14061
14246
|
});
|
|
14062
14247
|
});
|
|
14063
14248
|
return folderToStored(created);
|
|
@@ -14068,14 +14253,14 @@ async function getAllVaultFoldersOp(ctx) {
|
|
|
14068
14253
|
}
|
|
14069
14254
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
14070
14255
|
try {
|
|
14071
|
-
const
|
|
14072
|
-
if (
|
|
14073
|
-
const scopeChanged = opts.scope !== void 0 && opts.scope !==
|
|
14256
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
14257
|
+
if (record2.isDeleted) return null;
|
|
14258
|
+
const scopeChanged = opts.scope !== void 0 && opts.scope !== record2.scope;
|
|
14074
14259
|
const updated = await ctx.database.write(async () => {
|
|
14075
14260
|
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.where("folder_id", id), import_watermelondb21.Q.where("is_deleted", false)).fetch() : [];
|
|
14076
14261
|
const updates = [];
|
|
14077
14262
|
updates.push(
|
|
14078
|
-
|
|
14263
|
+
record2.prepareUpdate((r) => {
|
|
14079
14264
|
if (opts.name !== void 0) r._setRaw("name", opts.name);
|
|
14080
14265
|
if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
|
|
14081
14266
|
})
|
|
@@ -14083,6 +14268,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
14083
14268
|
for (const memory of memories) {
|
|
14084
14269
|
updates.push(
|
|
14085
14270
|
memory.prepareUpdate((r) => {
|
|
14271
|
+
r._setRaw("level", levelForScopeChange(r, opts.scope));
|
|
14086
14272
|
r._setRaw("scope", opts.scope);
|
|
14087
14273
|
})
|
|
14088
14274
|
);
|
|
@@ -14097,17 +14283,18 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
14097
14283
|
}
|
|
14098
14284
|
async function deleteVaultFolderOp(ctx, id) {
|
|
14099
14285
|
try {
|
|
14100
|
-
const
|
|
14101
|
-
if (
|
|
14286
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
14287
|
+
if (record2.isDeleted) return false;
|
|
14102
14288
|
await ctx.database.write(async () => {
|
|
14103
14289
|
const memories = await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.where("folder_id", id), import_watermelondb21.Q.where("is_deleted", false)).fetch();
|
|
14104
14290
|
const preparedMemories = memories.map(
|
|
14105
14291
|
(memory) => memory.prepareUpdate((r) => {
|
|
14106
14292
|
r._setRaw("folder_id", null);
|
|
14293
|
+
r._setRaw("level", levelForScopeChange(r, "private"));
|
|
14107
14294
|
r._setRaw("scope", "private");
|
|
14108
14295
|
})
|
|
14109
14296
|
);
|
|
14110
|
-
const preparedFolder =
|
|
14297
|
+
const preparedFolder = record2.prepareUpdate((r) => {
|
|
14111
14298
|
r._setRaw("is_deleted", true);
|
|
14112
14299
|
});
|
|
14113
14300
|
await ctx.database.batch(...preparedMemories, preparedFolder);
|
|
@@ -14140,6 +14327,7 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
14140
14327
|
const prepared = memories.map(
|
|
14141
14328
|
(memory) => memory.prepareUpdate((r) => {
|
|
14142
14329
|
r._setRaw("folder_id", folderId);
|
|
14330
|
+
r._setRaw("level", levelForScopeChange(r, targetScope));
|
|
14143
14331
|
r._setRaw("scope", targetScope);
|
|
14144
14332
|
})
|
|
14145
14333
|
);
|
|
@@ -14153,11 +14341,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
14153
14341
|
}
|
|
14154
14342
|
async function updateVaultFolderContextOp(ctx, id, context) {
|
|
14155
14343
|
try {
|
|
14156
|
-
const
|
|
14157
|
-
if (
|
|
14344
|
+
const record2 = await ctx.vaultFolderCollection.find(id);
|
|
14345
|
+
if (record2.isDeleted) return null;
|
|
14158
14346
|
const updated = await ctx.database.write(async () => {
|
|
14159
14347
|
await ctx.database.batch(
|
|
14160
|
-
|
|
14348
|
+
record2.prepareUpdate((r) => {
|
|
14161
14349
|
r._setRaw("context", context);
|
|
14162
14350
|
})
|
|
14163
14351
|
);
|
|
@@ -16235,7 +16423,7 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
16235
16423
|
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
16236
16424
|
let subEmbeddings;
|
|
16237
16425
|
try {
|
|
16238
|
-
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
16426
|
+
subEmbeddings = prepared.facetEmbeddings ?? await generateEmbeddings(facetQueries, embeddingOptions);
|
|
16239
16427
|
} catch (err) {
|
|
16240
16428
|
getLogger().warn(
|
|
16241
16429
|
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
@@ -16421,6 +16609,35 @@ var DEFAULT_SCOPE = "private";
|
|
|
16421
16609
|
var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
|
|
16422
16610
|
var DEFAULT_CONSOLIDATE_TOP_K = 20;
|
|
16423
16611
|
async function retain(content, ctx, options = {}) {
|
|
16612
|
+
return retainWithPersistence(
|
|
16613
|
+
content,
|
|
16614
|
+
{
|
|
16615
|
+
embeddingOptions: ctx.embeddingOptions,
|
|
16616
|
+
vaultCache: ctx.vaultCache,
|
|
16617
|
+
persistence: {
|
|
16618
|
+
prepare: (query, searchOptions) => prepareVaultCandidates(
|
|
16619
|
+
query,
|
|
16620
|
+
ctx.vaultCtx,
|
|
16621
|
+
ctx.embeddingOptions,
|
|
16622
|
+
ctx.vaultCache,
|
|
16623
|
+
searchOptions
|
|
16624
|
+
),
|
|
16625
|
+
get: (id) => getVaultMemoryOp(ctx.vaultCtx, id),
|
|
16626
|
+
tombstones: (_embedding, _model, scope, folderId) => getAllVaultMemoriesOp(ctx.vaultCtx, {
|
|
16627
|
+
includeDeleted: true,
|
|
16628
|
+
scopes: [scope],
|
|
16629
|
+
...folderId !== void 0 && { folderId }
|
|
16630
|
+
}),
|
|
16631
|
+
create: (input) => createVaultMemoryOp(ctx.vaultCtx, input),
|
|
16632
|
+
update: (id, patch) => updateVaultMemoryOp(ctx.vaultCtx, id, patch),
|
|
16633
|
+
supersede: (id, successor) => supersedeVaultMemoryOp(ctx.vaultCtx, id, successor),
|
|
16634
|
+
createSuperseding: (input, target) => createSupersedingMemoryOp(ctx.vaultCtx, input, target)
|
|
16635
|
+
}
|
|
16636
|
+
},
|
|
16637
|
+
options
|
|
16638
|
+
);
|
|
16639
|
+
}
|
|
16640
|
+
async function retainWithPersistence(content, ctx, options = {}) {
|
|
16424
16641
|
const trimmed = content.trim();
|
|
16425
16642
|
if (trimmed.length === 0) {
|
|
16426
16643
|
throw new Error("retain: content cannot be empty");
|
|
@@ -16433,19 +16650,14 @@ async function retain(content, ctx, options = {}) {
|
|
|
16433
16650
|
let supersedeContent;
|
|
16434
16651
|
let prepared;
|
|
16435
16652
|
if (enableAutoMerge) {
|
|
16436
|
-
prepared = await
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
{
|
|
16442
|
-
|
|
16443
|
-
|
|
16444
|
-
scopes: [resolvedScope],
|
|
16445
|
-
includeArchived: true,
|
|
16446
|
-
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
16447
|
-
}
|
|
16448
|
-
);
|
|
16653
|
+
prepared = await ctx.persistence.prepare(trimmed, {
|
|
16654
|
+
limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
|
|
16655
|
+
useFusion: false,
|
|
16656
|
+
scopes: [resolvedScope],
|
|
16657
|
+
includeArchived: true,
|
|
16658
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
16659
|
+
});
|
|
16660
|
+
prepared = withoutKindedRows(prepared);
|
|
16449
16661
|
if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
|
|
16450
16662
|
throw new Error(
|
|
16451
16663
|
"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 +16688,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16476
16688
|
);
|
|
16477
16689
|
if (matches.length > 0) {
|
|
16478
16690
|
const targetId = matches[0].uniqueId;
|
|
16479
|
-
const existing = await
|
|
16691
|
+
const existing = await ctx.persistence.get(targetId);
|
|
16480
16692
|
if (existing && !existing.supersededBy) {
|
|
16481
16693
|
const mergedSourceIds = unionStrings(
|
|
16482
16694
|
existing.sourceChunkIds ?? [],
|
|
@@ -16485,8 +16697,9 @@ async function retain(content, ctx, options = {}) {
|
|
|
16485
16697
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
16486
16698
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
16487
16699
|
const resurrect = resurrectFields(existing);
|
|
16488
|
-
const updated = await
|
|
16700
|
+
const updated = await ctx.persistence.update(targetId, {
|
|
16489
16701
|
content: existing.content,
|
|
16702
|
+
freeFormOnly: true,
|
|
16490
16703
|
proofCountIncrement: 1,
|
|
16491
16704
|
observationSourceIds: options.sourceChunkIds,
|
|
16492
16705
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -16512,7 +16725,8 @@ async function retain(content, ctx, options = {}) {
|
|
|
16512
16725
|
}
|
|
16513
16726
|
const contentToWrite = supersedeContent ?? trimmed;
|
|
16514
16727
|
const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
|
|
16515
|
-
const
|
|
16728
|
+
const generatedEmbedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
|
|
16729
|
+
const embedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
16516
16730
|
const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
16517
16731
|
if (options.respectTombstones) {
|
|
16518
16732
|
const tombstone = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
|
|
@@ -16552,8 +16766,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16552
16766
|
};
|
|
16553
16767
|
if (supersedeTargetIds.length > 0) {
|
|
16554
16768
|
const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
|
|
16555
|
-
const { created: created2, retired } = await
|
|
16556
|
-
ctx.vaultCtx,
|
|
16769
|
+
const { created: created2, retired } = await ctx.persistence.createSuperseding(
|
|
16557
16770
|
createOpts,
|
|
16558
16771
|
primaryTargetId
|
|
16559
16772
|
);
|
|
@@ -16569,11 +16782,11 @@ async function retain(content, ctx, options = {}) {
|
|
|
16569
16782
|
for (const staleId of restTargetIds) {
|
|
16570
16783
|
let ok = false;
|
|
16571
16784
|
try {
|
|
16572
|
-
ok = await
|
|
16785
|
+
ok = await ctx.persistence.supersede(staleId, created2.uniqueId) === true;
|
|
16573
16786
|
} catch {
|
|
16574
16787
|
}
|
|
16575
16788
|
if (ok) continue;
|
|
16576
|
-
const stillLive = await
|
|
16789
|
+
const stillLive = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(staleId) : ctx.persistence.get(staleId)).catch(() => null);
|
|
16577
16790
|
if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
|
|
16578
16791
|
}
|
|
16579
16792
|
if (liveLeftovers.length > 0) {
|
|
@@ -16600,7 +16813,7 @@ async function retain(content, ctx, options = {}) {
|
|
|
16600
16813
|
`supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
|
|
16601
16814
|
);
|
|
16602
16815
|
}
|
|
16603
|
-
const created = await
|
|
16816
|
+
const created = await ctx.persistence.create(createOpts);
|
|
16604
16817
|
cacheRowVector(
|
|
16605
16818
|
ctx.vaultCache,
|
|
16606
16819
|
created.uniqueId,
|
|
@@ -16615,15 +16828,22 @@ async function retain(content, ctx, options = {}) {
|
|
|
16615
16828
|
...consolidationDecidedCreate && { consolidation: "create" }
|
|
16616
16829
|
};
|
|
16617
16830
|
}
|
|
16831
|
+
function withoutKindedRows(prepared) {
|
|
16832
|
+
const kinded = new Set(
|
|
16833
|
+
prepared.memories.filter((m) => m.kind !== null && m.kind !== void 0).map((m) => m.uniqueId)
|
|
16834
|
+
);
|
|
16835
|
+
if (kinded.size === 0) return prepared;
|
|
16836
|
+
return {
|
|
16837
|
+
...prepared,
|
|
16838
|
+
memories: prepared.memories.filter((m) => !kinded.has(m.uniqueId)),
|
|
16839
|
+
embeddedItems: prepared.embeddedItems.filter((item) => !kinded.has(item.id))
|
|
16840
|
+
};
|
|
16841
|
+
}
|
|
16618
16842
|
function unionStrings(a, b) {
|
|
16619
16843
|
return [.../* @__PURE__ */ new Set([...a, ...b])];
|
|
16620
16844
|
}
|
|
16621
16845
|
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
|
-
});
|
|
16846
|
+
const rows = await ctx.persistence.tombstones(embedding, embeddingModel, scope, opts.folderId);
|
|
16627
16847
|
let bestId = null;
|
|
16628
16848
|
let bestSim = opts.threshold;
|
|
16629
16849
|
for (const row of rows) {
|
|
@@ -16690,7 +16910,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16690
16910
|
if (requestedIds.length === 0) return null;
|
|
16691
16911
|
const valid = [];
|
|
16692
16912
|
for (const id of requestedIds) {
|
|
16693
|
-
const existing = await
|
|
16913
|
+
const existing = await ctx.persistence.get(id);
|
|
16694
16914
|
if (existing && !existing.supersededBy) valid.push(id);
|
|
16695
16915
|
}
|
|
16696
16916
|
if (valid.length === 0) {
|
|
@@ -16702,7 +16922,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16702
16922
|
return { supersede: valid, content: decision.content };
|
|
16703
16923
|
}
|
|
16704
16924
|
if (decision.action === "noop" && decision.targetId) {
|
|
16705
|
-
const existing = await
|
|
16925
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
16706
16926
|
if (!existing || existing.supersededBy) {
|
|
16707
16927
|
return abandonToRace(
|
|
16708
16928
|
options,
|
|
@@ -16716,8 +16936,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16716
16936
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
16717
16937
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
16718
16938
|
const resurrect = resurrectFields(existing);
|
|
16719
|
-
const updated = await
|
|
16939
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
16720
16940
|
content: existing.content,
|
|
16941
|
+
freeFormOnly: true,
|
|
16721
16942
|
proofCountIncrement: 1,
|
|
16722
16943
|
observationSourceIds: options.sourceChunkIds,
|
|
16723
16944
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -16744,7 +16965,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16744
16965
|
};
|
|
16745
16966
|
}
|
|
16746
16967
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
16747
|
-
const existing = await
|
|
16968
|
+
const existing = await ctx.persistence.get(decision.targetId);
|
|
16748
16969
|
if (!existing || existing.supersededBy) {
|
|
16749
16970
|
return abandonToRace(
|
|
16750
16971
|
options,
|
|
@@ -16755,13 +16976,15 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16755
16976
|
existing.sourceChunkIds ?? [],
|
|
16756
16977
|
options.sourceChunkIds ?? []
|
|
16757
16978
|
);
|
|
16758
|
-
const
|
|
16979
|
+
const generatedEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
|
|
16980
|
+
const newEmbedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
|
|
16759
16981
|
const consolidatedModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
16760
16982
|
const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
|
|
16761
16983
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
16762
16984
|
const resurrect = resurrectFields(existing);
|
|
16763
|
-
const updated = await
|
|
16985
|
+
const updated = await ctx.persistence.update(decision.targetId, {
|
|
16764
16986
|
content: decision.content,
|
|
16987
|
+
freeFormOnly: true,
|
|
16765
16988
|
proofCountIncrement: 1,
|
|
16766
16989
|
observationSourceIds: options.sourceChunkIds,
|
|
16767
16990
|
sourceChunkIds: mergedSourceIds,
|
|
@@ -16804,8 +17027,8 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
16804
17027
|
return null;
|
|
16805
17028
|
}
|
|
16806
17029
|
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
16807
|
-
const stillExists = await
|
|
16808
|
-
if (stillExists) {
|
|
17030
|
+
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
17031
|
+
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
|
|
16809
17032
|
throw new Error(`retain: merge into memory ${targetId} failed to persist`);
|
|
16810
17033
|
}
|
|
16811
17034
|
}
|
|
@@ -17321,9 +17544,9 @@ function createAutoExtractor(options) {
|
|
|
17321
17544
|
const persistCursor = (conversationId, messages, advancedToId, contiguous) => {
|
|
17322
17545
|
if (!cursorStore || conversationId === void 0 || !contiguous) return;
|
|
17323
17546
|
try {
|
|
17324
|
-
const
|
|
17325
|
-
if (
|
|
17326
|
-
const storedIdx = messages.findIndex((m) => m.id ===
|
|
17547
|
+
const stored2 = cursorStore.get(conversationId);
|
|
17548
|
+
if (stored2 && stored2 !== advancedToId) {
|
|
17549
|
+
const storedIdx = messages.findIndex((m) => m.id === stored2);
|
|
17327
17550
|
const newIdx = messages.findIndex((m) => m.id === advancedToId);
|
|
17328
17551
|
if (storedIdx !== -1 && newIdx !== -1 && storedIdx >= newIdx) return;
|
|
17329
17552
|
}
|
|
@@ -18303,7 +18526,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
18303
18526
|
if (graphLaneFailed) degraded.push("graph-lane-failed");
|
|
18304
18527
|
if (temporalLaneFailed) degraded.push("temporal-lane-failed");
|
|
18305
18528
|
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;
|
|
18529
|
+
const laneRan = types.includes("fact") && (!!ctx.factSource || !!ctx.vaultCtx && !!ctx.vaultCache) || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
|
|
18307
18530
|
const scores = admitted.map((m) => m.score);
|
|
18308
18531
|
const minScoreApplied = factResults.length > 0 ? factFloor : chunkResults.length > 0 ? chunkFloor : factFloor >= 0 ? factFloor : chunkFloor;
|
|
18309
18532
|
const diagnostics = {
|
|
@@ -18345,7 +18568,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
18345
18568
|
return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
|
|
18346
18569
|
}
|
|
18347
18570
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
18348
|
-
const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
|
|
18571
|
+
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
18349
18572
|
const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
|
|
18350
18573
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
18351
18574
|
const prepStart = nowMs2();
|
|
@@ -18375,7 +18598,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
18375
18598
|
safeLane(
|
|
18376
18599
|
"graph",
|
|
18377
18600
|
() => graphLaneFailed = true,
|
|
18378
|
-
() => buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
18601
|
+
() => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
|
|
18379
18602
|
...options.maxHops !== void 0 && { maxHops: options.maxHops },
|
|
18380
18603
|
...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
|
|
18381
18604
|
...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
|
|
@@ -18386,13 +18609,13 @@ async function recall(query, ctx, options = {}) {
|
|
|
18386
18609
|
wantsTemporal ? safeLane(
|
|
18387
18610
|
"temporal",
|
|
18388
18611
|
() => temporalLaneFailed = true,
|
|
18389
|
-
() => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
18612
|
+
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
18390
18613
|
) : Promise.resolve([])
|
|
18391
18614
|
]);
|
|
18392
18615
|
prepMs = nowMs2() - prepStart;
|
|
18393
18616
|
graphLaneCount = entityRanking.length;
|
|
18394
18617
|
temporalLaneCount = temporalRanking.length;
|
|
18395
|
-
if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
|
|
18618
|
+
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
18396
18619
|
const factStart = nowMs2();
|
|
18397
18620
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
18398
18621
|
factFloor = vaultMinScore;
|
|
@@ -18408,50 +18631,50 @@ async function recall(query, ctx, options = {}) {
|
|
|
18408
18631
|
rankedOnCosine: factRankedOnCosine,
|
|
18409
18632
|
decryptLast: factDecryptLast,
|
|
18410
18633
|
rowsDecrypted: factRowsDecrypted
|
|
18411
|
-
} = await searchVaultMemoriesWithSize(
|
|
18412
|
-
|
|
18634
|
+
} = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
|
|
18635
|
+
searchQuery,
|
|
18413
18636
|
ctx.vaultCtx,
|
|
18414
18637
|
ctx.embeddingOptions,
|
|
18415
18638
|
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
|
-
);
|
|
18639
|
+
searchOptions
|
|
18640
|
+
)))(query, {
|
|
18641
|
+
limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
|
|
18642
|
+
minSimilarity: vaultMinScore,
|
|
18643
|
+
useFusion: true,
|
|
18644
|
+
rerank: flags.rerank,
|
|
18645
|
+
...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
|
|
18646
|
+
...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
|
|
18647
|
+
...options.rerankLoadTimeoutMs !== void 0 && {
|
|
18648
|
+
rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
|
|
18649
|
+
},
|
|
18650
|
+
...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
|
|
18651
|
+
...options.recency && { recency: options.recency },
|
|
18652
|
+
...options.mmr !== void 0 && { mmr: options.mmr },
|
|
18653
|
+
...options.supersessionBoost !== void 0 && {
|
|
18654
|
+
supersessionBoost: options.supersessionBoost
|
|
18655
|
+
},
|
|
18656
|
+
...options.supersessionWindow !== void 0 && {
|
|
18657
|
+
supersessionWindow: options.supersessionWindow
|
|
18658
|
+
},
|
|
18659
|
+
...options.proofCountAlpha !== void 0 && {
|
|
18660
|
+
proofCountAlpha: options.proofCountAlpha
|
|
18661
|
+
},
|
|
18662
|
+
...options.bm25AdmissionDivisor !== void 0 && {
|
|
18663
|
+
bm25AdmissionDivisor: options.bm25AdmissionDivisor
|
|
18664
|
+
},
|
|
18665
|
+
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
18666
|
+
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
18667
|
+
...subQueries && { subQueries },
|
|
18668
|
+
...options.scopes && { scopes: options.scopes },
|
|
18669
|
+
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
18670
|
+
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
18671
|
+
...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
|
|
18672
|
+
...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
|
|
18673
|
+
...entityRanking.length > 0 && { entityRanking },
|
|
18674
|
+
...temporalRanking.length > 0 && { temporalRanking },
|
|
18675
|
+
...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
|
|
18676
|
+
queryEmbedTotalTimeoutMs
|
|
18677
|
+
});
|
|
18455
18678
|
factResults.push(
|
|
18456
18679
|
...dedupeBy(
|
|
18457
18680
|
results,
|
|
@@ -19264,26 +19487,26 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
|
19264
19487
|
};
|
|
19265
19488
|
const inputs = [];
|
|
19266
19489
|
for (const id of new Set(memoryIds)) {
|
|
19267
|
-
let
|
|
19490
|
+
let record2;
|
|
19268
19491
|
try {
|
|
19269
|
-
|
|
19492
|
+
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
19270
19493
|
} catch (err) {
|
|
19271
19494
|
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
19272
19495
|
skip(id, "not-found");
|
|
19273
19496
|
continue;
|
|
19274
19497
|
}
|
|
19275
|
-
if (
|
|
19498
|
+
if (record2.isDeleted || ctx.userId !== void 0 && record2.userId !== ctx.userId || record2.topicsUserManaged) {
|
|
19276
19499
|
skip(id, "excluded");
|
|
19277
19500
|
continue;
|
|
19278
19501
|
}
|
|
19279
19502
|
try {
|
|
19280
|
-
const
|
|
19281
|
-
|
|
19503
|
+
const stored2 = await vaultMemoryToStored(
|
|
19504
|
+
record2,
|
|
19282
19505
|
ctx.walletAddress,
|
|
19283
19506
|
ctx.signMessage,
|
|
19284
19507
|
ctx.embeddedWalletSigner
|
|
19285
19508
|
);
|
|
19286
|
-
inputs.push({ id, content:
|
|
19509
|
+
inputs.push({ id, content: stored2.content });
|
|
19287
19510
|
} catch (err) {
|
|
19288
19511
|
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
19289
19512
|
skip(id, "unreadable");
|
|
@@ -19468,6 +19691,781 @@ function createLocalMemoryStore(options) {
|
|
|
19468
19691
|
};
|
|
19469
19692
|
}
|
|
19470
19693
|
|
|
19694
|
+
// src/lib/memory/store/remotePersistence.ts
|
|
19695
|
+
var RemoteMemoryError = class extends Error {
|
|
19696
|
+
constructor(message, status, code) {
|
|
19697
|
+
super(message);
|
|
19698
|
+
this.status = status;
|
|
19699
|
+
this.code = code;
|
|
19700
|
+
this.name = "RemoteMemoryError";
|
|
19701
|
+
}
|
|
19702
|
+
};
|
|
19703
|
+
var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
|
|
19704
|
+
var memoryFields = {
|
|
19705
|
+
memory_id: true,
|
|
19706
|
+
content: true,
|
|
19707
|
+
scope: true,
|
|
19708
|
+
created_at: true,
|
|
19709
|
+
updated_at: true,
|
|
19710
|
+
is_deleted: true,
|
|
19711
|
+
embedding: true,
|
|
19712
|
+
embedding_model: true,
|
|
19713
|
+
kind: true,
|
|
19714
|
+
kind_value: true,
|
|
19715
|
+
level: true,
|
|
19716
|
+
folder_id: true,
|
|
19717
|
+
source_chunk_ids: true,
|
|
19718
|
+
proof_count: true,
|
|
19719
|
+
source: true,
|
|
19720
|
+
event_time_start: true,
|
|
19721
|
+
event_time_end: true,
|
|
19722
|
+
event_time_kind: true,
|
|
19723
|
+
topics_user_managed: true,
|
|
19724
|
+
topics: true,
|
|
19725
|
+
topics_updated_at: true,
|
|
19726
|
+
media: true,
|
|
19727
|
+
topics_extracted_at: true,
|
|
19728
|
+
topics_extracted_version: true,
|
|
19729
|
+
superseded_by: true,
|
|
19730
|
+
superseded_at: true,
|
|
19731
|
+
last_observed_at: true,
|
|
19732
|
+
fact_type: true,
|
|
19733
|
+
archived_at: true,
|
|
19734
|
+
trust_tier: true,
|
|
19735
|
+
visibility: true,
|
|
19736
|
+
twin_opt_in: true,
|
|
19737
|
+
published_at: true,
|
|
19738
|
+
geohash: true
|
|
19739
|
+
};
|
|
19740
|
+
var candidateListLimits = [
|
|
19741
|
+
["scopes", 20],
|
|
19742
|
+
["fact_types", 20],
|
|
19743
|
+
["memory_ids", 1e3],
|
|
19744
|
+
["force_ids", 100]
|
|
19745
|
+
];
|
|
19746
|
+
function record(value) {
|
|
19747
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19748
|
+
}
|
|
19749
|
+
function memoryRecord(value) {
|
|
19750
|
+
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))) {
|
|
19751
|
+
throw new Error("Invalid nearby private-memory response");
|
|
19752
|
+
}
|
|
19753
|
+
return value;
|
|
19754
|
+
}
|
|
19755
|
+
async function createRemoteMemoryPersistence(options) {
|
|
19756
|
+
const base = new URL(options.baseUrl);
|
|
19757
|
+
if (!/^https?:$/.test(base.protocol) || base.username || base.password || base.search || base.hash) {
|
|
19758
|
+
throw new Error(
|
|
19759
|
+
"baseUrl must be an HTTP(S) origin or base path without credentials, query or fragment"
|
|
19760
|
+
);
|
|
19761
|
+
}
|
|
19762
|
+
if (!options.keyId || options.keyId.length > 256)
|
|
19763
|
+
throw new Error("A canonical keyId is required");
|
|
19764
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
19765
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
19766
|
+
throw new Error("timeoutMs must be a positive number");
|
|
19767
|
+
const root = base.href.replace(/\/$/, "") + "/api/private-memories";
|
|
19768
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
19769
|
+
const request = async (path, init = {}, signal) => {
|
|
19770
|
+
const controller = new AbortController();
|
|
19771
|
+
let timedOut = false;
|
|
19772
|
+
const timer = setTimeout(() => {
|
|
19773
|
+
timedOut = true;
|
|
19774
|
+
controller.abort();
|
|
19775
|
+
}, timeoutMs);
|
|
19776
|
+
const forwardAbort = () => controller.abort(signal?.reason);
|
|
19777
|
+
if (signal?.aborted) forwardAbort();
|
|
19778
|
+
else signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
19779
|
+
let rejectAborted;
|
|
19780
|
+
const aborted = new Promise((_, reject) => {
|
|
19781
|
+
rejectAborted = () => reject(
|
|
19782
|
+
controller.signal.reason instanceof Error ? controller.signal.reason : new Error("Nearby request aborted")
|
|
19783
|
+
);
|
|
19784
|
+
if (controller.signal.aborted) rejectAborted();
|
|
19785
|
+
else controller.signal.addEventListener("abort", rejectAborted, { once: true });
|
|
19786
|
+
});
|
|
19787
|
+
aborted.catch(() => void 0);
|
|
19788
|
+
try {
|
|
19789
|
+
const token = await Promise.race([options.getToken(), aborted]);
|
|
19790
|
+
if (controller.signal.aborted) await aborted;
|
|
19791
|
+
if (!token) throw new RemoteMemoryError("Authentication required", 401);
|
|
19792
|
+
const response = await fetcher(root + path, {
|
|
19793
|
+
...init,
|
|
19794
|
+
headers: {
|
|
19795
|
+
Authorization: `Bearer ${token}`,
|
|
19796
|
+
...init.body ? { "Content-Type": "application/json" } : {}
|
|
19797
|
+
},
|
|
19798
|
+
redirect: "error",
|
|
19799
|
+
signal: controller.signal
|
|
19800
|
+
});
|
|
19801
|
+
if (!response.ok) {
|
|
19802
|
+
const body = await response.json().catch(() => null);
|
|
19803
|
+
throw new RemoteMemoryError(
|
|
19804
|
+
record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
19805
|
+
response.status,
|
|
19806
|
+
record(body) && typeof body.code === "string" ? body.code : void 0
|
|
19807
|
+
);
|
|
19808
|
+
}
|
|
19809
|
+
return await response.json();
|
|
19810
|
+
} catch (error) {
|
|
19811
|
+
if (timedOut) throw new RemoteMemoryError("Nearby request timed out", 408, "timeout");
|
|
19812
|
+
throw error;
|
|
19813
|
+
} finally {
|
|
19814
|
+
clearTimeout(timer);
|
|
19815
|
+
signal?.removeEventListener("abort", forwardAbort);
|
|
19816
|
+
if (rejectAborted) controller.signal.removeEventListener("abort", rejectAborted);
|
|
19817
|
+
}
|
|
19818
|
+
};
|
|
19819
|
+
const account = await request("/account", {}, options.signal);
|
|
19820
|
+
if (!record(account) || account.state !== "active") {
|
|
19821
|
+
throw new RemoteMemoryError(
|
|
19822
|
+
"Complete and verify migration before using remote memories",
|
|
19823
|
+
409,
|
|
19824
|
+
"memory_not_active"
|
|
19825
|
+
);
|
|
19826
|
+
}
|
|
19827
|
+
if (account.key_id !== options.keyId) {
|
|
19828
|
+
throw new RemoteMemoryError(
|
|
19829
|
+
"The canonical memory key does not match this account",
|
|
19830
|
+
409,
|
|
19831
|
+
"key_mismatch"
|
|
19832
|
+
);
|
|
19833
|
+
}
|
|
19834
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
19835
|
+
const decode = async (value) => {
|
|
19836
|
+
const item = memoryRecord(value);
|
|
19837
|
+
const decrypt = async (ciphertext) => {
|
|
19838
|
+
if (!ciphertextPattern.test(ciphertext))
|
|
19839
|
+
throw new Error("Nearby returned unencrypted memory content");
|
|
19840
|
+
const plaintext = await options.decrypt(ciphertext);
|
|
19841
|
+
if (plaintext === ciphertext) throw new Error("Memory decryption failed");
|
|
19842
|
+
return plaintext;
|
|
19843
|
+
};
|
|
19844
|
+
const decoded = {
|
|
19845
|
+
...item,
|
|
19846
|
+
memory: {
|
|
19847
|
+
...item.memory,
|
|
19848
|
+
content: await decrypt(item.memory.content),
|
|
19849
|
+
...item.memory.kind_value !== void 0 && {
|
|
19850
|
+
kind_value: await decrypt(item.memory.kind_value)
|
|
19851
|
+
}
|
|
19852
|
+
}
|
|
19853
|
+
};
|
|
19854
|
+
return remember(decoded, item);
|
|
19855
|
+
};
|
|
19856
|
+
const remember = (decoded, item) => {
|
|
19857
|
+
snapshots.set(decoded, {
|
|
19858
|
+
id: item.memory.memory_id,
|
|
19859
|
+
version: item.version,
|
|
19860
|
+
content: decoded.memory.content,
|
|
19861
|
+
kindValue: decoded.memory.kind_value,
|
|
19862
|
+
encryptedContent: item.memory.content,
|
|
19863
|
+
encryptedKindValue: item.memory.kind_value
|
|
19864
|
+
});
|
|
19865
|
+
return decoded;
|
|
19866
|
+
};
|
|
19867
|
+
const decodeAll = async (values) => {
|
|
19868
|
+
const records = values.map(memoryRecord);
|
|
19869
|
+
const settled = await Promise.allSettled(records.map(decode));
|
|
19870
|
+
const items = [];
|
|
19871
|
+
const failed = [];
|
|
19872
|
+
settled.forEach((result, i) => {
|
|
19873
|
+
if (result.status === "fulfilled") items.push(result.value);
|
|
19874
|
+
else
|
|
19875
|
+
failed.push({
|
|
19876
|
+
memory_id: records[i].memory.memory_id,
|
|
19877
|
+
version: records[i].version,
|
|
19878
|
+
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
19879
|
+
});
|
|
19880
|
+
});
|
|
19881
|
+
return { items, failed };
|
|
19882
|
+
};
|
|
19883
|
+
const decodeCommitted = async (value, write) => {
|
|
19884
|
+
const item = memoryRecord(value);
|
|
19885
|
+
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)
|
|
19886
|
+
return decode(item);
|
|
19887
|
+
return remember(
|
|
19888
|
+
{
|
|
19889
|
+
...item,
|
|
19890
|
+
memory: {
|
|
19891
|
+
...item.memory,
|
|
19892
|
+
content: write.content,
|
|
19893
|
+
...write.kindValue !== void 0 && { kind_value: write.kindValue }
|
|
19894
|
+
}
|
|
19895
|
+
},
|
|
19896
|
+
item
|
|
19897
|
+
);
|
|
19898
|
+
};
|
|
19899
|
+
const encryptField2 = async (plaintext) => {
|
|
19900
|
+
const ciphertext = await options.encrypt(plaintext);
|
|
19901
|
+
if (ciphertext === plaintext || !ciphertextPattern.test(ciphertext))
|
|
19902
|
+
throw new Error("Field encryption must return SDK ciphertext; refusing to upload plaintext");
|
|
19903
|
+
return ciphertext;
|
|
19904
|
+
};
|
|
19905
|
+
const memoryPath = (id) => {
|
|
19906
|
+
if (!id || id.length > 128) throw new Error("memory_id must be 1\u2013128 characters");
|
|
19907
|
+
return "/memories/" + encodeURIComponent(id);
|
|
19908
|
+
};
|
|
19909
|
+
const prepareWrite = async (memory, expectedVersion, signal) => {
|
|
19910
|
+
const unknown = Object.keys(memory).filter(
|
|
19911
|
+
(key) => !Object.prototype.hasOwnProperty.call(memoryFields, key)
|
|
19912
|
+
);
|
|
19913
|
+
if (unknown.length) {
|
|
19914
|
+
throw new RemoteMemoryError(
|
|
19915
|
+
`Unknown private-memory fields (${unknown.join(", ")}); refusing to forward them`,
|
|
19916
|
+
400,
|
|
19917
|
+
"unknown_field"
|
|
19918
|
+
);
|
|
19919
|
+
}
|
|
19920
|
+
memory = { ...memory, ...memory.embedding && { embedding: [...memory.embedding] } };
|
|
19921
|
+
const path = memoryPath(memory.memory_id);
|
|
19922
|
+
const snapshot = typeof expectedVersion === "number" ? void 0 : snapshots.get(expectedVersion);
|
|
19923
|
+
if (typeof expectedVersion !== "number" && (!snapshot || snapshot.id !== memory.memory_id || snapshot.version !== expectedVersion.version))
|
|
19924
|
+
throw new Error(
|
|
19925
|
+
"Expected snapshot must be an unmodified version from this persistence instance"
|
|
19926
|
+
);
|
|
19927
|
+
expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
|
|
19928
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
19929
|
+
throw new Error("expectedVersion must be a nonnegative integer");
|
|
19930
|
+
const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
|
|
19931
|
+
let existing;
|
|
19932
|
+
if (expectedVersion !== 0 && !snapshot) {
|
|
19933
|
+
try {
|
|
19934
|
+
existing = memoryRecord(await request(path, {}, signal));
|
|
19935
|
+
} catch (error) {
|
|
19936
|
+
if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
|
|
19937
|
+
throw error;
|
|
19938
|
+
}
|
|
19939
|
+
}
|
|
19940
|
+
if (existing && existing.version !== expectedVersion) throw conflict();
|
|
19941
|
+
const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
|
|
19942
|
+
const content = (snapshot?.content ?? decoded?.memory.content) === memory.content ? snapshot?.encryptedContent ?? existing.memory.content : await encryptField2(memory.content);
|
|
19943
|
+
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);
|
|
19944
|
+
return {
|
|
19945
|
+
body: {
|
|
19946
|
+
expected_version: expectedVersion,
|
|
19947
|
+
memory: { ...memory, content, ...kindValue !== void 0 && { kind_value: kindValue } }
|
|
19948
|
+
},
|
|
19949
|
+
content: memory.content,
|
|
19950
|
+
kindValue: memory.kind_value
|
|
19951
|
+
};
|
|
19952
|
+
};
|
|
19953
|
+
const fetchCandidates = async (embedding, candidateOptions, withCounts) => {
|
|
19954
|
+
const limit = candidateOptions.limit ?? 100;
|
|
19955
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
19956
|
+
throw new Error("Candidate limit must be 1\u2013100");
|
|
19957
|
+
for (const [key, max] of candidateListLimits) {
|
|
19958
|
+
const values = candidateOptions[key];
|
|
19959
|
+
if (values && values.length > max)
|
|
19960
|
+
throw new Error(`Candidate ${key} accepts at most ${max} entries (got ${values.length})`);
|
|
19961
|
+
}
|
|
19962
|
+
const result = await request(
|
|
19963
|
+
"/candidates",
|
|
19964
|
+
{
|
|
19965
|
+
method: "POST",
|
|
19966
|
+
body: JSON.stringify({
|
|
19967
|
+
embedding,
|
|
19968
|
+
limit,
|
|
19969
|
+
force_ids: candidateOptions.force_ids ?? [],
|
|
19970
|
+
...withCounts && { with_counts: true },
|
|
19971
|
+
...Object.fromEntries(
|
|
19972
|
+
[
|
|
19973
|
+
"scopes",
|
|
19974
|
+
"memory_ids",
|
|
19975
|
+
"embedding_model",
|
|
19976
|
+
"strict_model",
|
|
19977
|
+
"include_deleted",
|
|
19978
|
+
"deleted_only"
|
|
19979
|
+
].filter(
|
|
19980
|
+
(key) => candidateOptions[key] !== void 0
|
|
19981
|
+
).map((key) => [key, candidateOptions[key]])
|
|
19982
|
+
),
|
|
19983
|
+
...candidateOptions.fact_types !== void 0 && {
|
|
19984
|
+
fact_types: candidateOptions.fact_types
|
|
19985
|
+
},
|
|
19986
|
+
...candidateOptions.include_archived !== void 0 && {
|
|
19987
|
+
include_archived: candidateOptions.include_archived
|
|
19988
|
+
},
|
|
19989
|
+
...candidateOptions.include_quarantined !== void 0 && {
|
|
19990
|
+
include_quarantined: candidateOptions.include_quarantined
|
|
19991
|
+
},
|
|
19992
|
+
...candidateOptions.include_superseded !== void 0 && {
|
|
19993
|
+
include_superseded: candidateOptions.include_superseded
|
|
19994
|
+
}
|
|
19995
|
+
})
|
|
19996
|
+
},
|
|
19997
|
+
candidateOptions.signal
|
|
19998
|
+
);
|
|
19999
|
+
if (!record(result) || !Array.isArray(result.items))
|
|
20000
|
+
throw new Error("Invalid nearby candidate response");
|
|
20001
|
+
return result;
|
|
20002
|
+
};
|
|
20003
|
+
const candidateSet = async (embedding, candidateOptions = {}) => {
|
|
20004
|
+
const result = await fetchCandidates(embedding, candidateOptions, true);
|
|
20005
|
+
if (!Number.isSafeInteger(result.total_count) || result.total_count < 0 || !Number.isSafeInteger(result.unavailable_count) || result.unavailable_count < 0)
|
|
20006
|
+
throw new Error("Invalid nearby candidate response");
|
|
20007
|
+
return {
|
|
20008
|
+
...await decodeAll(result.items),
|
|
20009
|
+
total_count: result.total_count,
|
|
20010
|
+
unavailable_count: result.unavailable_count
|
|
20011
|
+
};
|
|
20012
|
+
};
|
|
20013
|
+
return {
|
|
20014
|
+
get: async (id, signal) => {
|
|
20015
|
+
try {
|
|
20016
|
+
return await decode(await request(memoryPath(id), {}, signal));
|
|
20017
|
+
} catch (error) {
|
|
20018
|
+
if (error instanceof RemoteMemoryError && error.status === 404) return null;
|
|
20019
|
+
throw error;
|
|
20020
|
+
}
|
|
20021
|
+
},
|
|
20022
|
+
list: async (listOptions = {}) => {
|
|
20023
|
+
const { signal, ...query } = listOptions;
|
|
20024
|
+
if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) {
|
|
20025
|
+
throw new Error("Page limit must be 1\u2013200");
|
|
20026
|
+
}
|
|
20027
|
+
const params = new URLSearchParams();
|
|
20028
|
+
for (const key of [
|
|
20029
|
+
"cursor",
|
|
20030
|
+
"limit",
|
|
20031
|
+
"include_deleted",
|
|
20032
|
+
"include_archived",
|
|
20033
|
+
"include_quarantined",
|
|
20034
|
+
"include_superseded",
|
|
20035
|
+
"include_embeddings"
|
|
20036
|
+
]) {
|
|
20037
|
+
if (query[key] !== void 0) params.set(key, String(query[key]));
|
|
20038
|
+
}
|
|
20039
|
+
const page = await request("/memories?" + params.toString(), {}, signal);
|
|
20040
|
+
if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
|
|
20041
|
+
throw new Error("Invalid nearby private-memory page");
|
|
20042
|
+
}
|
|
20043
|
+
return {
|
|
20044
|
+
...await decodeAll(page.items),
|
|
20045
|
+
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
|
|
20046
|
+
};
|
|
20047
|
+
},
|
|
20048
|
+
put: async (memory, expectedVersion, signal) => {
|
|
20049
|
+
const write = await prepareWrite(memory, expectedVersion, signal);
|
|
20050
|
+
return decodeCommitted(
|
|
20051
|
+
await request(
|
|
20052
|
+
memoryPath(write.body.memory.memory_id),
|
|
20053
|
+
{
|
|
20054
|
+
method: "PUT",
|
|
20055
|
+
body: JSON.stringify({ key_id: options.keyId, ...write.body })
|
|
20056
|
+
},
|
|
20057
|
+
signal
|
|
20058
|
+
),
|
|
20059
|
+
write
|
|
20060
|
+
);
|
|
20061
|
+
},
|
|
20062
|
+
putMany: async (writes, signal) => {
|
|
20063
|
+
if (writes.length < 1 || writes.length > 50 || new Set(writes.map((w) => w.memory.memory_id)).size !== writes.length)
|
|
20064
|
+
throw new Error("Batch must contain 1\u201350 distinct memory ids");
|
|
20065
|
+
const prepared = await Promise.all(
|
|
20066
|
+
writes.map((w) => prepareWrite(w.memory, w.expectedVersion, signal))
|
|
20067
|
+
);
|
|
20068
|
+
const result = await request(
|
|
20069
|
+
"/memories/batch",
|
|
20070
|
+
{
|
|
20071
|
+
method: "POST",
|
|
20072
|
+
body: JSON.stringify({ key_id: options.keyId, writes: prepared.map((w) => w.body) })
|
|
20073
|
+
},
|
|
20074
|
+
signal
|
|
20075
|
+
);
|
|
20076
|
+
if (!record(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
|
|
20077
|
+
throw new Error("Invalid nearby batch response");
|
|
20078
|
+
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
20079
|
+
},
|
|
20080
|
+
candidateSet,
|
|
20081
|
+
candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
|
|
20082
|
+
};
|
|
20083
|
+
}
|
|
20084
|
+
|
|
20085
|
+
// src/lib/memory/store/remotePipeline.ts
|
|
20086
|
+
var import_uuid4 = require("uuid");
|
|
20087
|
+
init_logger();
|
|
20088
|
+
function storedVector(vector) {
|
|
20089
|
+
if (!Array.isArray(vector) || vector.length !== 1536 && vector.length !== 4096 || vector.some((v) => !Number.isFinite(v)))
|
|
20090
|
+
throw new Error("Remote memories require a finite 1536/4096-dimensional vector");
|
|
20091
|
+
const out = vector.slice(0, 1536);
|
|
20092
|
+
const norm = Math.sqrt(out.reduce((sum, v) => sum + v * v, 0));
|
|
20093
|
+
if (!norm) throw new Error("Remote query/content vector has no direction after MRL truncation");
|
|
20094
|
+
return out.map((v) => v / norm);
|
|
20095
|
+
}
|
|
20096
|
+
function sourceIds(value) {
|
|
20097
|
+
if (!value) return [];
|
|
20098
|
+
try {
|
|
20099
|
+
const parsed = JSON.parse(value);
|
|
20100
|
+
return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
|
|
20101
|
+
} catch {
|
|
20102
|
+
return [];
|
|
20103
|
+
}
|
|
20104
|
+
}
|
|
20105
|
+
function isMemoryLevel(value) {
|
|
20106
|
+
return MEMORY_LEVELS.includes(value);
|
|
20107
|
+
}
|
|
20108
|
+
function stored(row) {
|
|
20109
|
+
return {
|
|
20110
|
+
uniqueId: row.memory_id,
|
|
20111
|
+
content: row.content,
|
|
20112
|
+
scope: row.scope,
|
|
20113
|
+
folderId: row.folder_id ?? null,
|
|
20114
|
+
userId: null,
|
|
20115
|
+
kind: row.kind ?? null,
|
|
20116
|
+
kindValue: row.kind_value ?? null,
|
|
20117
|
+
...isMemoryLevel(row.level) && { level: row.level },
|
|
20118
|
+
embedding: row.embedding ? JSON.stringify(row.embedding) : null,
|
|
20119
|
+
embeddingModel: row.embedding_model ?? null,
|
|
20120
|
+
sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
|
|
20121
|
+
proofCount: row.proof_count ?? null,
|
|
20122
|
+
source: row.source ?? null,
|
|
20123
|
+
media: parseMedia(row.media),
|
|
20124
|
+
eventTimeStart: row.event_time_start ?? null,
|
|
20125
|
+
eventTimeEnd: row.event_time_end ?? null,
|
|
20126
|
+
eventTimeKind: row.event_time_kind ?? null,
|
|
20127
|
+
topicsUserManaged: row.topics_user_managed ?? false,
|
|
20128
|
+
topics: parseTopics(row.topics),
|
|
20129
|
+
topicsUpdatedAt: row.topics_updated_at ?? null,
|
|
20130
|
+
topicsExtractedAt: row.topics_extracted_at ?? null,
|
|
20131
|
+
topicsExtractedVersion: row.topics_extracted_version ?? null,
|
|
20132
|
+
supersededBy: row.superseded_by ?? null,
|
|
20133
|
+
supersededAt: row.superseded_at ?? null,
|
|
20134
|
+
lastObservedAt: row.last_observed_at ?? null,
|
|
20135
|
+
factType: row.fact_type ?? null,
|
|
20136
|
+
archivedAt: row.archived_at ?? null,
|
|
20137
|
+
trustTier: row.trust_tier ?? null,
|
|
20138
|
+
visibility: row.visibility === "public" ? "public" : "private",
|
|
20139
|
+
twinOptIn: row.twin_opt_in ?? false,
|
|
20140
|
+
publishedAt: row.published_at ?? null,
|
|
20141
|
+
geohash: row.geohash ?? null,
|
|
20142
|
+
createdAt: new Date(row.created_at),
|
|
20143
|
+
updatedAt: new Date(row.updated_at),
|
|
20144
|
+
isDeleted: row.is_deleted
|
|
20145
|
+
};
|
|
20146
|
+
}
|
|
20147
|
+
function createRemoteMemoryPipeline(options) {
|
|
20148
|
+
const { persistence, embeddingOptions } = options;
|
|
20149
|
+
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
20150
|
+
const operation = (mode) => {
|
|
20151
|
+
const rejectUndecryptable = (failed) => {
|
|
20152
|
+
if (!failed.length) return;
|
|
20153
|
+
if (mode === "retain")
|
|
20154
|
+
throw new Error(
|
|
20155
|
+
`Remote memories could not decrypt ${failed.length} candidate row(s); refusing to retain until they are repaired`
|
|
20156
|
+
);
|
|
20157
|
+
getLogger().warn(
|
|
20158
|
+
`[memory/remote] Skipping ${failed.length} undecryptable candidate row(s)`,
|
|
20159
|
+
failed.map((failure) => failure.memory_id)
|
|
20160
|
+
);
|
|
20161
|
+
};
|
|
20162
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
20163
|
+
const remember = (items) => {
|
|
20164
|
+
items.forEach((item) => snapshots.set(item.memory.memory_id, item));
|
|
20165
|
+
return items.map((item) => stored(item.memory));
|
|
20166
|
+
};
|
|
20167
|
+
const get = async (id) => {
|
|
20168
|
+
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
20169
|
+
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
20170
|
+
snapshots.set(id, snapshot);
|
|
20171
|
+
return stored(snapshot.memory);
|
|
20172
|
+
};
|
|
20173
|
+
const prepare = async (query, search = {}) => {
|
|
20174
|
+
if (search.folderId !== void 0)
|
|
20175
|
+
throw new Error("Remote memories do not support folder filters");
|
|
20176
|
+
const facets = normalizeSubQueries(search.subQueries);
|
|
20177
|
+
const facetQueries = facets.length >= 2 ? facets : [];
|
|
20178
|
+
const start = Date.now();
|
|
20179
|
+
const budgetMs = search.queryEmbedTotalTimeoutMs ?? 8e3;
|
|
20180
|
+
const embed = (texts) => generateEmbeddings(texts, {
|
|
20181
|
+
...embeddingOptions,
|
|
20182
|
+
totalTimeoutMs: budgetMs
|
|
20183
|
+
});
|
|
20184
|
+
const embedFacets = async () => {
|
|
20185
|
+
if (!facetQueries.length) return [];
|
|
20186
|
+
try {
|
|
20187
|
+
const vectors2 = await embed(facetQueries);
|
|
20188
|
+
if (vectors2.length !== facetQueries.length)
|
|
20189
|
+
throw new Error("Incomplete facet embeddings");
|
|
20190
|
+
return vectors2.map(storedVector);
|
|
20191
|
+
} catch (error) {
|
|
20192
|
+
getLogger().warn(
|
|
20193
|
+
"[memory/remote] Facet embeddings unavailable; using primary query",
|
|
20194
|
+
error
|
|
20195
|
+
);
|
|
20196
|
+
return [];
|
|
20197
|
+
}
|
|
20198
|
+
};
|
|
20199
|
+
const [primary, facetEmbeddings] = await Promise.all([
|
|
20200
|
+
search.queryEmbedding ?? embed([query]).then((vectors2) => vectors2[0]),
|
|
20201
|
+
embedFacets()
|
|
20202
|
+
]);
|
|
20203
|
+
const queryEmbedding = storedVector(primary);
|
|
20204
|
+
const queryEmbedMs = Date.now() - start;
|
|
20205
|
+
const graph = search.entityRanking ?? [];
|
|
20206
|
+
const temporal = search.temporalRanking ?? [];
|
|
20207
|
+
const forced = /* @__PURE__ */ new Set();
|
|
20208
|
+
for (let i = 0; i < Math.max(graph.length, temporal.length) && forced.size < 100; i++) {
|
|
20209
|
+
if (graph[i] !== void 0) forced.add(graph[i]);
|
|
20210
|
+
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
20211
|
+
}
|
|
20212
|
+
const forceIds = [...forced];
|
|
20213
|
+
const windowOptions = (i, signal) => ({
|
|
20214
|
+
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
20215
|
+
force_ids: i === 0 ? forceIds : [],
|
|
20216
|
+
...search.scopes && { scopes: search.scopes },
|
|
20217
|
+
...search.factTypes && { fact_types: search.factTypes },
|
|
20218
|
+
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
20219
|
+
include_archived: search.includeArchived,
|
|
20220
|
+
embedding_model: model,
|
|
20221
|
+
...signal && { signal }
|
|
20222
|
+
});
|
|
20223
|
+
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
20224
|
+
let windows;
|
|
20225
|
+
if (mode === "retain") {
|
|
20226
|
+
windows = await Promise.all(
|
|
20227
|
+
vectors.map((embedding, i) => persistence.candidateSet(embedding, windowOptions(i)))
|
|
20228
|
+
);
|
|
20229
|
+
} else {
|
|
20230
|
+
const deadline = new AbortController();
|
|
20231
|
+
const timer = setTimeout(
|
|
20232
|
+
() => deadline.abort(
|
|
20233
|
+
new RemoteMemoryError("Remote recall exceeded its query budget", 408, "timeout")
|
|
20234
|
+
),
|
|
20235
|
+
Math.max(0, start + budgetMs - Date.now())
|
|
20236
|
+
);
|
|
20237
|
+
try {
|
|
20238
|
+
windows = await Promise.all(
|
|
20239
|
+
vectors.map(
|
|
20240
|
+
(embedding, i) => persistence.candidates(embedding, windowOptions(i, deadline.signal))
|
|
20241
|
+
)
|
|
20242
|
+
);
|
|
20243
|
+
} finally {
|
|
20244
|
+
clearTimeout(timer);
|
|
20245
|
+
}
|
|
20246
|
+
}
|
|
20247
|
+
rejectUndecryptable([
|
|
20248
|
+
...new Map(
|
|
20249
|
+
windows.flatMap((window2) => window2.failed).map((failure) => [failure.memory_id, failure])
|
|
20250
|
+
).values()
|
|
20251
|
+
]);
|
|
20252
|
+
const items = [
|
|
20253
|
+
...new Map(
|
|
20254
|
+
windows.flatMap((window2) => window2.items).map((item) => [item.memory.memory_id, item])
|
|
20255
|
+
).values()
|
|
20256
|
+
];
|
|
20257
|
+
const memories = remember(items);
|
|
20258
|
+
return {
|
|
20259
|
+
memories,
|
|
20260
|
+
embeddedItems: memories.map((memory) => ({
|
|
20261
|
+
id: memory.uniqueId,
|
|
20262
|
+
content: memory.content,
|
|
20263
|
+
embedding: JSON.parse(memory.embedding ?? "[]"),
|
|
20264
|
+
createdAt: memory.createdAt,
|
|
20265
|
+
updatedAt: memory.updatedAt,
|
|
20266
|
+
proofCount: memory.proofCount,
|
|
20267
|
+
lastObservedAt: memory.lastObservedAt,
|
|
20268
|
+
eventTimeStart: memory.eventTimeStart,
|
|
20269
|
+
eventTimeEnd: memory.eventTimeEnd,
|
|
20270
|
+
eventTimeKind: memory.eventTimeKind === "point" || memory.eventTimeKind === "range" || memory.eventTimeKind === "ongoing" ? memory.eventTimeKind : null,
|
|
20271
|
+
factType: memory.factType,
|
|
20272
|
+
sourceChunkIds: memory.sourceChunkIds
|
|
20273
|
+
})),
|
|
20274
|
+
queryEmbedding,
|
|
20275
|
+
facetEmbeddings,
|
|
20276
|
+
vaultSize: Math.max(windows[0].total_count ?? 0, items.length),
|
|
20277
|
+
embeddingFailure: windows.some((window2) => (window2.unavailable_count ?? 0) > 0),
|
|
20278
|
+
embeddingsUnavailable: (windows[0].total_count ?? items.length) > 0 && !memories.some((memory) => memory.embedding),
|
|
20279
|
+
decryptLast: true,
|
|
20280
|
+
rowsDecrypted: items.length,
|
|
20281
|
+
queryEmbedMs,
|
|
20282
|
+
rowsEmbedded: 0
|
|
20283
|
+
};
|
|
20284
|
+
};
|
|
20285
|
+
const createRow = (input) => {
|
|
20286
|
+
if (input.folderId !== void 0 && input.folderId !== null)
|
|
20287
|
+
throw new Error("Remote memories do not support folders");
|
|
20288
|
+
const now = Date.now();
|
|
20289
|
+
return {
|
|
20290
|
+
memory_id: (0, import_uuid4.v7)(),
|
|
20291
|
+
content: input.content,
|
|
20292
|
+
scope: input.scope ?? "private",
|
|
20293
|
+
created_at: now,
|
|
20294
|
+
updated_at: now,
|
|
20295
|
+
is_deleted: false,
|
|
20296
|
+
...input.embedding !== void 0 && {
|
|
20297
|
+
embedding: storedVector(JSON.parse(input.embedding)),
|
|
20298
|
+
embedding_model: input.embeddingModel
|
|
20299
|
+
},
|
|
20300
|
+
source_chunk_ids: JSON.stringify(input.sourceChunkIds ?? []),
|
|
20301
|
+
proof_count: input.proofCount ?? 1,
|
|
20302
|
+
source: input.source ?? "manual",
|
|
20303
|
+
...input.eventTime && {
|
|
20304
|
+
event_time_start: input.eventTime.start ?? void 0,
|
|
20305
|
+
event_time_end: input.eventTime.end ?? void 0,
|
|
20306
|
+
event_time_kind: input.eventTime.kind ?? void 0
|
|
20307
|
+
},
|
|
20308
|
+
fact_type: input.factType,
|
|
20309
|
+
trust_tier: normalizeTrustTier(input.trustTier) ?? void 0,
|
|
20310
|
+
geohash: input.geohash,
|
|
20311
|
+
visibility: "private",
|
|
20312
|
+
twin_opt_in: false
|
|
20313
|
+
};
|
|
20314
|
+
};
|
|
20315
|
+
const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
|
|
20316
|
+
const port = {
|
|
20317
|
+
prepare,
|
|
20318
|
+
get,
|
|
20319
|
+
getFresh: async (id) => {
|
|
20320
|
+
const current = await persistence.get(id);
|
|
20321
|
+
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
20322
|
+
},
|
|
20323
|
+
tombstones: async (embedding, embeddingModel, scope, folderId) => {
|
|
20324
|
+
if (folderId !== void 0) throw new Error("Remote memories do not support folders");
|
|
20325
|
+
const window2 = await persistence.candidateSet(storedVector(embedding), {
|
|
20326
|
+
limit: 1,
|
|
20327
|
+
scopes: [scope],
|
|
20328
|
+
embedding_model: embeddingModel,
|
|
20329
|
+
strict_model: true,
|
|
20330
|
+
include_deleted: true,
|
|
20331
|
+
deleted_only: true
|
|
20332
|
+
});
|
|
20333
|
+
rejectUndecryptable(window2.failed);
|
|
20334
|
+
return remember(window2.items);
|
|
20335
|
+
},
|
|
20336
|
+
create: (input) => write(createRow(input), 0),
|
|
20337
|
+
update: async (id, patch) => {
|
|
20338
|
+
const existing = await get(id);
|
|
20339
|
+
if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
20340
|
+
return null;
|
|
20341
|
+
const snapshot = snapshots.get(id);
|
|
20342
|
+
const memory = {
|
|
20343
|
+
...snapshot.memory,
|
|
20344
|
+
content: patch.content,
|
|
20345
|
+
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
|
|
20346
|
+
};
|
|
20347
|
+
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
20348
|
+
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
20349
|
+
delete memory.embedding;
|
|
20350
|
+
delete memory.embedding_model;
|
|
20351
|
+
}
|
|
20352
|
+
if (patch.embedding !== void 0) {
|
|
20353
|
+
memory.embedding = patch.embedding === null ? [] : storedVector(JSON.parse(patch.embedding));
|
|
20354
|
+
memory.embedding_model = patch.embeddingModel ?? void 0;
|
|
20355
|
+
}
|
|
20356
|
+
const observed = sourceIds(memory.source_chunk_ids);
|
|
20357
|
+
const replay = !!patch.observationSourceIds?.length && patch.observationSourceIds.every((id2) => observed.includes(id2));
|
|
20358
|
+
if (patch.sourceChunkIds !== void 0)
|
|
20359
|
+
memory.source_chunk_ids = JSON.stringify(
|
|
20360
|
+
patch.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observed, ...patch.sourceChunkIds])] : patch.sourceChunkIds
|
|
20361
|
+
);
|
|
20362
|
+
if (!replay) {
|
|
20363
|
+
if (patch.proofCountIncrement !== void 0)
|
|
20364
|
+
memory.proof_count = (memory.proof_count ?? 1) + patch.proofCountIncrement;
|
|
20365
|
+
else if (patch.proofCount !== void 0) memory.proof_count = patch.proofCount;
|
|
20366
|
+
if (patch.lastObservedAt !== void 0) memory.last_observed_at = patch.lastObservedAt;
|
|
20367
|
+
}
|
|
20368
|
+
if (patch.source !== void 0) memory.source = patch.source;
|
|
20369
|
+
if (patch.factType !== void 0) memory.fact_type = patch.factType;
|
|
20370
|
+
if (patch.trustTier !== void 0)
|
|
20371
|
+
memory.trust_tier = normalizeTrustTier(patch.trustTier) ?? void 0;
|
|
20372
|
+
if (patch.topicsUserManaged !== void 0)
|
|
20373
|
+
memory.topics_user_managed = patch.topicsUserManaged;
|
|
20374
|
+
if (patch.eventTime !== void 0) {
|
|
20375
|
+
memory.event_time_start = patch.eventTime.start ?? void 0;
|
|
20376
|
+
memory.event_time_end = patch.eventTime.end ?? void 0;
|
|
20377
|
+
memory.event_time_kind = patch.eventTime.kind ?? void 0;
|
|
20378
|
+
}
|
|
20379
|
+
if (patch.restore) memory.archived_at = void 0;
|
|
20380
|
+
return write(memory, snapshot);
|
|
20381
|
+
},
|
|
20382
|
+
supersede: async (id, successor) => {
|
|
20383
|
+
const [target, newer] = await Promise.all([get(id), get(successor)]);
|
|
20384
|
+
if (!target || !newer || id === successor) return false;
|
|
20385
|
+
const old = snapshots.get(id);
|
|
20386
|
+
const next = snapshots.get(successor);
|
|
20387
|
+
remember(
|
|
20388
|
+
await persistence.putMany([
|
|
20389
|
+
{
|
|
20390
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
20391
|
+
expectedVersion: old
|
|
20392
|
+
},
|
|
20393
|
+
{ memory: next.memory, expectedVersion: next }
|
|
20394
|
+
])
|
|
20395
|
+
);
|
|
20396
|
+
return true;
|
|
20397
|
+
},
|
|
20398
|
+
createSuperseding: async (input, targetId) => {
|
|
20399
|
+
const target = await get(targetId);
|
|
20400
|
+
if (!target) return { created: null, retired: false };
|
|
20401
|
+
const snapshot = snapshots.get(targetId);
|
|
20402
|
+
const successor = createRow(input);
|
|
20403
|
+
const rows = remember(
|
|
20404
|
+
await persistence.putMany([
|
|
20405
|
+
{ memory: successor, expectedVersion: 0 },
|
|
20406
|
+
{
|
|
20407
|
+
memory: {
|
|
20408
|
+
...snapshot.memory,
|
|
20409
|
+
superseded_by: successor.memory_id,
|
|
20410
|
+
superseded_at: Date.now()
|
|
20411
|
+
},
|
|
20412
|
+
expectedVersion: snapshot
|
|
20413
|
+
}
|
|
20414
|
+
])
|
|
20415
|
+
);
|
|
20416
|
+
return { created: rows[0], retired: true };
|
|
20417
|
+
}
|
|
20418
|
+
};
|
|
20419
|
+
return { prepare, port };
|
|
20420
|
+
};
|
|
20421
|
+
return {
|
|
20422
|
+
recall: async (query, recallOptions = {}) => {
|
|
20423
|
+
const { prepare } = operation("recall");
|
|
20424
|
+
return recall(
|
|
20425
|
+
query,
|
|
20426
|
+
{
|
|
20427
|
+
embeddingOptions,
|
|
20428
|
+
factSource: {
|
|
20429
|
+
graphRanking: options.graphRanking,
|
|
20430
|
+
temporalRanking: options.temporalRanking,
|
|
20431
|
+
search: async (text12, searchOptions) => {
|
|
20432
|
+
const prepared = await prepare(text12, searchOptions);
|
|
20433
|
+
const ranked = await rankPreparedVaultCandidates(
|
|
20434
|
+
text12,
|
|
20435
|
+
prepared,
|
|
20436
|
+
embeddingOptions,
|
|
20437
|
+
searchOptions
|
|
20438
|
+
);
|
|
20439
|
+
return {
|
|
20440
|
+
...ranked,
|
|
20441
|
+
rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
|
|
20442
|
+
decryptLast: true,
|
|
20443
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
20444
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
20445
|
+
rowsEmbedded: 0
|
|
20446
|
+
};
|
|
20447
|
+
}
|
|
20448
|
+
}
|
|
20449
|
+
},
|
|
20450
|
+
{ ...recallOptions, types: ["fact"] }
|
|
20451
|
+
);
|
|
20452
|
+
},
|
|
20453
|
+
retain: async (content, retainOptions) => {
|
|
20454
|
+
const { port } = operation("retain");
|
|
20455
|
+
return retainWithPersistence(
|
|
20456
|
+
content,
|
|
20457
|
+
{
|
|
20458
|
+
persistence: port,
|
|
20459
|
+
embeddingOptions,
|
|
20460
|
+
vaultCache: /* @__PURE__ */ new Map(),
|
|
20461
|
+
normalizeEmbedding: storedVector
|
|
20462
|
+
},
|
|
20463
|
+
retainOptions
|
|
20464
|
+
);
|
|
20465
|
+
}
|
|
20466
|
+
};
|
|
20467
|
+
}
|
|
20468
|
+
|
|
19471
20469
|
// src/lib/memory/synthesizeProfile.ts
|
|
19472
20470
|
init_internalFlowMarker();
|
|
19473
20471
|
init_logger();
|
|
@@ -22893,7 +23891,7 @@ function useChat(options) {
|
|
|
22893
23891
|
|
|
22894
23892
|
// src/expo/useChatStorage.ts
|
|
22895
23893
|
var import_react5 = require("react");
|
|
22896
|
-
var
|
|
23894
|
+
var import_uuid6 = require("uuid");
|
|
22897
23895
|
init_clientConfig();
|
|
22898
23896
|
|
|
22899
23897
|
// src/lib/chat/assembleMessages.ts
|
|
@@ -23556,9 +24554,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
|
|
|
23556
24554
|
}
|
|
23557
24555
|
|
|
23558
24556
|
// src/lib/db/media/types.ts
|
|
23559
|
-
var
|
|
24557
|
+
var import_uuid5 = require("uuid");
|
|
23560
24558
|
function generateMediaId() {
|
|
23561
|
-
return `media_${(0,
|
|
24559
|
+
return `media_${(0, import_uuid5.v7)()}`;
|
|
23562
24560
|
}
|
|
23563
24561
|
|
|
23564
24562
|
// src/lib/db/media/operations.ts
|
|
@@ -23769,10 +24767,10 @@ function extractImageModelFromToolEvents(toolCallEvents) {
|
|
|
23769
24767
|
}
|
|
23770
24768
|
return void 0;
|
|
23771
24769
|
}
|
|
23772
|
-
function storedToLlmapiMessage(
|
|
23773
|
-
const content = [{ type: "text", text:
|
|
23774
|
-
if (
|
|
23775
|
-
for (const file of
|
|
24770
|
+
function storedToLlmapiMessage(stored2) {
|
|
24771
|
+
const content = [{ type: "text", text: stored2.content }];
|
|
24772
|
+
if (stored2.role !== "assistant" && stored2.files?.length) {
|
|
24773
|
+
for (const file of stored2.files) {
|
|
23776
24774
|
if (isSendableImageURL(file.url)) {
|
|
23777
24775
|
content.push({
|
|
23778
24776
|
type: "image_url",
|
|
@@ -23782,11 +24780,11 @@ function storedToLlmapiMessage(stored) {
|
|
|
23782
24780
|
}
|
|
23783
24781
|
}
|
|
23784
24782
|
const messages = [];
|
|
23785
|
-
if (
|
|
24783
|
+
if (stored2.role === "assistant" && stored2.toolCallEvents?.length) {
|
|
23786
24784
|
messages.push({
|
|
23787
|
-
role:
|
|
24785
|
+
role: stored2.role,
|
|
23788
24786
|
content: void 0,
|
|
23789
|
-
tool_calls:
|
|
24787
|
+
tool_calls: stored2.toolCallEvents.map((event) => ({
|
|
23790
24788
|
id: event.id,
|
|
23791
24789
|
type: "function",
|
|
23792
24790
|
function: {
|
|
@@ -23795,7 +24793,7 @@ function storedToLlmapiMessage(stored) {
|
|
|
23795
24793
|
}
|
|
23796
24794
|
}))
|
|
23797
24795
|
});
|
|
23798
|
-
for (const event of
|
|
24796
|
+
for (const event of stored2.toolCallEvents) {
|
|
23799
24797
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
23800
24798
|
messages.push({
|
|
23801
24799
|
role: "tool",
|
|
@@ -23804,14 +24802,14 @@ function storedToLlmapiMessage(stored) {
|
|
|
23804
24802
|
});
|
|
23805
24803
|
}
|
|
23806
24804
|
}
|
|
23807
|
-
const postToolText =
|
|
24805
|
+
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
24806
|
messages.push({
|
|
23809
|
-
role:
|
|
24807
|
+
role: stored2.role,
|
|
23810
24808
|
content: [{ type: "text", text: postToolText }]
|
|
23811
24809
|
});
|
|
23812
24810
|
} else {
|
|
23813
24811
|
messages.push({
|
|
23814
|
-
role:
|
|
24812
|
+
role: stored2.role,
|
|
23815
24813
|
content
|
|
23816
24814
|
});
|
|
23817
24815
|
}
|
|
@@ -24518,7 +25516,7 @@ function useChatStorage(options) {
|
|
|
24518
25516
|
};
|
|
24519
25517
|
};
|
|
24520
25518
|
pendingResumeRef.current = null;
|
|
24521
|
-
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0,
|
|
25519
|
+
const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0, import_uuid6.v7)()}` : void 0);
|
|
24522
25520
|
const embedToolText = (text12, mask, masked, token) => {
|
|
24523
25521
|
const opts = {
|
|
24524
25522
|
getToken: token,
|
|
@@ -25036,7 +26034,7 @@ function useChatStorage(options) {
|
|
|
25036
26034
|
const detachedResult = result;
|
|
25037
26035
|
if (detachedResult.detached) {
|
|
25038
26036
|
recordToolSetTurn(database, convId, matchedToolSets);
|
|
25039
|
-
const rowId = effectiveAssistantUniqueId ?? `msg_${(0,
|
|
26037
|
+
const rowId = effectiveAssistantUniqueId ?? `msg_${(0, import_uuid6.v7)()}`;
|
|
25040
26038
|
pendingResumeRef.current = {
|
|
25041
26039
|
handle: detachedResult.resume ?? null,
|
|
25042
26040
|
convId,
|
|
@@ -25546,6 +26544,9 @@ function useChatStorage(options) {
|
|
|
25546
26544
|
LoggerProvider,
|
|
25547
26545
|
MAX_HOPS,
|
|
25548
26546
|
MEDIUM_TTL_MS,
|
|
26547
|
+
MEMORY_KINDS,
|
|
26548
|
+
MEMORY_LEVELS,
|
|
26549
|
+
MemoryLevelError,
|
|
25549
26550
|
NEVER_TTL_MS,
|
|
25550
26551
|
NODE_BUDGET,
|
|
25551
26552
|
NOTION_OAUTH_CONFIG,
|
|
@@ -25556,6 +26557,7 @@ function useChatStorage(options) {
|
|
|
25556
26557
|
QueueManager,
|
|
25557
26558
|
RECALL_MAX_LIMIT,
|
|
25558
26559
|
RECALL_TOOL_NAME,
|
|
26560
|
+
RemoteMemoryError,
|
|
25559
26561
|
RerankerUnavailableError,
|
|
25560
26562
|
SDK_SCHEMA_VERSION,
|
|
25561
26563
|
SHORT_TTL_MS,
|
|
@@ -25619,6 +26621,8 @@ function useChatStorage(options) {
|
|
|
25619
26621
|
createNotionTools,
|
|
25620
26622
|
createPlatformCursorStore,
|
|
25621
26623
|
createRecallTool,
|
|
26624
|
+
createRemoteMemoryPersistence,
|
|
26625
|
+
createRemoteMemoryPipeline,
|
|
25622
26626
|
createStockPricePreProcessor,
|
|
25623
26627
|
createStreamingDeAnonymizer,
|
|
25624
26628
|
createVaultEmbeddingCache,
|