@anuma/sdk 6.32.0 → 6.33.1
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 +456 -249
- package/dist/expo/index.d.mts +434 -170
- package/dist/expo/index.d.ts +434 -170
- package/dist/expo/index.mjs +415 -210
- package/dist/memory/context.d.mts +1 -0
- package/dist/memory/context.d.ts +1 -0
- package/dist/react/index.cjs +465 -303
- package/dist/react/index.d.mts +425 -170
- package/dist/react/index.d.ts +425 -170
- package/dist/react/index.mjs +418 -258
- package/dist/server/index.cjs +423 -216
- package/dist/server/index.d.mts +433 -171
- package/dist/server/index.d.ts +433 -171
- package/dist/server/index.mjs +418 -213
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -1530,6 +1530,7 @@ __export(index_exports, {
|
|
|
1530
1530
|
createDurableAutoExtractor: () => createDurableAutoExtractor,
|
|
1531
1531
|
createLlmDecayClassifier: () => createLlmDecayClassifier,
|
|
1532
1532
|
createLlmNeighborRefiner: () => createLlmNeighborRefiner,
|
|
1533
|
+
createLocalMemoryStore: () => createLocalMemoryStore,
|
|
1533
1534
|
createMemoryEngineTool: () => createMemoryEngineTool,
|
|
1534
1535
|
createMemoryVaultSearchTool: () => createMemoryVaultSearchTool,
|
|
1535
1536
|
createMemoryVaultTool: () => createMemoryVaultTool,
|
|
@@ -9150,7 +9151,13 @@ async function runToolLoop(options) {
|
|
|
9150
9151
|
);
|
|
9151
9152
|
const extra = results.flatMap((r) => Array.isArray(r) ? r : []);
|
|
9152
9153
|
if (extra.length > 0) {
|
|
9153
|
-
|
|
9154
|
+
let userIndex = messages.length - 1;
|
|
9155
|
+
while (userIndex > 0 && messages[userIndex].role !== "user") userIndex--;
|
|
9156
|
+
messages = [
|
|
9157
|
+
...messages.slice(0, userIndex),
|
|
9158
|
+
...await redactBatch(extra),
|
|
9159
|
+
...messages.slice(userIndex)
|
|
9160
|
+
];
|
|
9154
9161
|
}
|
|
9155
9162
|
}
|
|
9156
9163
|
} catch (err) {
|
|
@@ -13241,6 +13248,51 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
13241
13248
|
return null;
|
|
13242
13249
|
}
|
|
13243
13250
|
}
|
|
13251
|
+
async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
13252
|
+
const entityCtx = ctx.entityCtx;
|
|
13253
|
+
if (!entityCtx) {
|
|
13254
|
+
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
13255
|
+
}
|
|
13256
|
+
let record;
|
|
13257
|
+
try {
|
|
13258
|
+
record = await ctx.vaultMemoryCollection.find(memoryId);
|
|
13259
|
+
} catch {
|
|
13260
|
+
return null;
|
|
13261
|
+
}
|
|
13262
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
|
|
13263
|
+
let stale = false;
|
|
13264
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
13265
|
+
await ctx.database.write(async (writer) => {
|
|
13266
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
13267
|
+
stale = true;
|
|
13268
|
+
return;
|
|
13269
|
+
}
|
|
13270
|
+
await record.update((r) => {
|
|
13271
|
+
r._setRaw("topics_user_managed", true);
|
|
13272
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
13273
|
+
});
|
|
13274
|
+
const linked = entities.length > 0 ? await writer.callWriter(
|
|
13275
|
+
() => linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" })
|
|
13276
|
+
) : [];
|
|
13277
|
+
const keep = new Set(linked.map((e) => e.uniqueId));
|
|
13278
|
+
const existing = await entityCtx.memoryEntityCollection.query(import_watermelondb10.Q.where("memory_id", memoryId)).fetch();
|
|
13279
|
+
const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
|
|
13280
|
+
if (staleLinks.length === 0 && entities.length > 0) return;
|
|
13281
|
+
const topicsWrite = await resolveMemoryTopicsWrite(
|
|
13282
|
+
entityCtx,
|
|
13283
|
+
memoryId,
|
|
13284
|
+
linked,
|
|
13285
|
+
entities,
|
|
13286
|
+
"user"
|
|
13287
|
+
);
|
|
13288
|
+
await ctx.database.batch(
|
|
13289
|
+
...staleLinks.map((l) => l.prepareDestroyPermanently()),
|
|
13290
|
+
...topicsWrite ? [prepareMemoryTopicsUpdate(topicsWrite)] : []
|
|
13291
|
+
);
|
|
13292
|
+
});
|
|
13293
|
+
if (stale) return null;
|
|
13294
|
+
return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
13295
|
+
}
|
|
13244
13296
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
13245
13297
|
let record;
|
|
13246
13298
|
try {
|
|
@@ -15817,7 +15869,10 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
|
|
|
15817
15869
|
if (memoryId) cacheRowVector(cache, memoryId, Float32Array.from(embedding), updatedAt, content);
|
|
15818
15870
|
if (vaultCtx && memoryId) {
|
|
15819
15871
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
15820
|
-
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel
|
|
15872
|
+
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel, {
|
|
15873
|
+
content,
|
|
15874
|
+
...updatedAt !== void 0 && { updatedAt: updatedAt.getTime() }
|
|
15875
|
+
}).catch(
|
|
15821
15876
|
// Silently swallow – SDK must not use console.*; embedding will be retried on next search
|
|
15822
15877
|
() => {
|
|
15823
15878
|
}
|
|
@@ -19356,6 +19411,353 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
19356
19411
|
};
|
|
19357
19412
|
}
|
|
19358
19413
|
|
|
19414
|
+
// src/lib/memory/store/local.ts
|
|
19415
|
+
var import_watermelondb12 = require("@nozbe/watermelondb");
|
|
19416
|
+
init_logger();
|
|
19417
|
+
|
|
19418
|
+
// src/lib/memory/topicExtract.ts
|
|
19419
|
+
init_logger();
|
|
19420
|
+
init_redactor();
|
|
19421
|
+
init_portalLlm();
|
|
19422
|
+
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
19423
|
+
var MAX_CHARS_PER_MEMORY = 300;
|
|
19424
|
+
var MAX_VOCABULARY_NAMES = 100;
|
|
19425
|
+
var MAX_COMPLETION_TOKENS = 8192;
|
|
19426
|
+
var SYSTEM_PROMPT6 = `You assign topics to saved memories for a personal memory system.
|
|
19427
|
+
|
|
19428
|
+
Each memory is a short statement about the user. For each memory, list the NAMED entities it mentions \u2014 these become the memory's topics, used to connect related memories in a knowledge graph.
|
|
19429
|
+
|
|
19430
|
+
Include only NAMED entities, skip generic/common nouns. A topic must identify a specific thing the user could recognize by name; if it would be equally true of thousands of unrelated memories, leave it out:
|
|
19431
|
+
- SKIP bare generic nouns even when the memory capitalizes them or a calendar entry is titled that way \u2014 "Home", "Work", "Meeting", "Lunch", "Birthday", "Appointment", "Trip", "Today", "Friday", "March" are NOT topics.
|
|
19432
|
+
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
19433
|
+
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
19434
|
+
${ENTITY_KIND_GUIDELINES}
|
|
19435
|
+
|
|
19436
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
19437
|
+
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
19438
|
+
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
19439
|
+
No prose.`;
|
|
19440
|
+
async function extractEntitiesForMemories(memories, options) {
|
|
19441
|
+
const out = /* @__PURE__ */ new Map();
|
|
19442
|
+
if (memories.length === 0) return out;
|
|
19443
|
+
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
19444
|
+
const vocabulary = [];
|
|
19445
|
+
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
19446
|
+
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
19447
|
+
}
|
|
19448
|
+
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
19449
|
+
When a memory refers to one of these, reuse the EXACT existing name (same spelling, casing, spacing and punctuation) instead of a variant \u2014 if "Foo.ai" is listed, never emit "Foo ai" or "Foo AI", and if "Jane Roe" is listed, emit that rather than a bare "Jane".
|
|
19450
|
+
|
|
19451
|
+
` : "";
|
|
19452
|
+
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
19453
|
+
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
19454
|
+
const rows = [];
|
|
19455
|
+
for (const m of batch) {
|
|
19456
|
+
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
19457
|
+
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
19458
|
+
}
|
|
19459
|
+
const listing = rows.join("\n");
|
|
19460
|
+
const parsed = await callPortalJsonCompletion({
|
|
19461
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
19462
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
19463
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
19464
|
+
taskType: "memory_topic",
|
|
19465
|
+
...options.endpointOverride !== void 0 && {
|
|
19466
|
+
endpointOverride: options.endpointOverride
|
|
19467
|
+
},
|
|
19468
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
19469
|
+
systemPrompt: SYSTEM_PROMPT6,
|
|
19470
|
+
userMessage: `${vocabularyNote}Memories:
|
|
19471
|
+
${listing}
|
|
19472
|
+
|
|
19473
|
+
List each memory's named entities.`,
|
|
19474
|
+
tag: "memory/topics",
|
|
19475
|
+
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
19476
|
+
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
19477
|
+
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
19478
|
+
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
19479
|
+
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
19480
|
+
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
19481
|
+
});
|
|
19482
|
+
if (parsed === null) {
|
|
19483
|
+
getLogger().warn(
|
|
19484
|
+
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
19485
|
+
);
|
|
19486
|
+
continue;
|
|
19487
|
+
}
|
|
19488
|
+
const validIds = new Set(batch.map((m) => m.id));
|
|
19489
|
+
const byId = parseTopicResponse(parsed, validIds);
|
|
19490
|
+
if (byId === null) {
|
|
19491
|
+
getLogger().warn(
|
|
19492
|
+
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
19493
|
+
);
|
|
19494
|
+
continue;
|
|
19495
|
+
}
|
|
19496
|
+
for (const m of batch) {
|
|
19497
|
+
const entities = byId.get(m.id);
|
|
19498
|
+
if (entities === void 0) {
|
|
19499
|
+
continue;
|
|
19500
|
+
}
|
|
19501
|
+
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
19502
|
+
}
|
|
19503
|
+
}
|
|
19504
|
+
return out;
|
|
19505
|
+
}
|
|
19506
|
+
function restoreEntities(entities, redactor) {
|
|
19507
|
+
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
19508
|
+
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
19509
|
+
);
|
|
19510
|
+
}
|
|
19511
|
+
function parseTopicResponse(parsed, validIds) {
|
|
19512
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
19513
|
+
const list = parsed.memories;
|
|
19514
|
+
if (!Array.isArray(list)) return null;
|
|
19515
|
+
const out = /* @__PURE__ */ new Map();
|
|
19516
|
+
for (const raw of list) {
|
|
19517
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
19518
|
+
const obj = raw;
|
|
19519
|
+
if (typeof obj.id !== "string") continue;
|
|
19520
|
+
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
19521
|
+
if (!validIds.has(id) || out.has(id)) continue;
|
|
19522
|
+
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
19523
|
+
out.set(id, entities);
|
|
19524
|
+
}
|
|
19525
|
+
return out;
|
|
19526
|
+
}
|
|
19527
|
+
var DEGRADED_TOPIC_SKIP = {
|
|
19528
|
+
excluded: false,
|
|
19529
|
+
"link-declined": false,
|
|
19530
|
+
"stamp-declined": false,
|
|
19531
|
+
"llm-unanswered": true,
|
|
19532
|
+
unreadable: true,
|
|
19533
|
+
"not-found": true,
|
|
19534
|
+
"link-failed": true
|
|
19535
|
+
};
|
|
19536
|
+
function isDegradedTopicSkip(reason) {
|
|
19537
|
+
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
19538
|
+
}
|
|
19539
|
+
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
19540
|
+
const entityCtx = ctx.entityCtx;
|
|
19541
|
+
if (!entityCtx) {
|
|
19542
|
+
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
19543
|
+
}
|
|
19544
|
+
const log = getLogger();
|
|
19545
|
+
const extractedAt = options.now ?? Date.now();
|
|
19546
|
+
const skippedIds = [];
|
|
19547
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
19548
|
+
const skip = (id, reason) => {
|
|
19549
|
+
if (skippedReasons.has(id)) return;
|
|
19550
|
+
skippedIds.push(id);
|
|
19551
|
+
skippedReasons.set(id, reason);
|
|
19552
|
+
};
|
|
19553
|
+
const inputs = [];
|
|
19554
|
+
for (const id of new Set(memoryIds)) {
|
|
19555
|
+
let record;
|
|
19556
|
+
try {
|
|
19557
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
19558
|
+
} catch (err) {
|
|
19559
|
+
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
19560
|
+
skip(id, "not-found");
|
|
19561
|
+
continue;
|
|
19562
|
+
}
|
|
19563
|
+
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
19564
|
+
skip(id, "excluded");
|
|
19565
|
+
continue;
|
|
19566
|
+
}
|
|
19567
|
+
try {
|
|
19568
|
+
const stored = await vaultMemoryToStored(
|
|
19569
|
+
record,
|
|
19570
|
+
ctx.walletAddress,
|
|
19571
|
+
ctx.signMessage,
|
|
19572
|
+
ctx.embeddedWalletSigner
|
|
19573
|
+
);
|
|
19574
|
+
inputs.push({ id, content: stored.content });
|
|
19575
|
+
} catch (err) {
|
|
19576
|
+
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
19577
|
+
skip(id, "unreadable");
|
|
19578
|
+
}
|
|
19579
|
+
}
|
|
19580
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
19581
|
+
const toStamp = [];
|
|
19582
|
+
for (const input of inputs) {
|
|
19583
|
+
const entities = entitiesByMemory.get(input.id);
|
|
19584
|
+
if (entities === void 0) {
|
|
19585
|
+
skip(input.id, "llm-unanswered");
|
|
19586
|
+
continue;
|
|
19587
|
+
}
|
|
19588
|
+
try {
|
|
19589
|
+
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
19590
|
+
if (linked === null) {
|
|
19591
|
+
skip(input.id, "link-declined");
|
|
19592
|
+
entitiesByMemory.delete(input.id);
|
|
19593
|
+
continue;
|
|
19594
|
+
}
|
|
19595
|
+
} catch (err) {
|
|
19596
|
+
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
19597
|
+
skip(input.id, "link-failed");
|
|
19598
|
+
entitiesByMemory.delete(input.id);
|
|
19599
|
+
continue;
|
|
19600
|
+
}
|
|
19601
|
+
toStamp.push(input.id);
|
|
19602
|
+
}
|
|
19603
|
+
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
19604
|
+
const stampedSet = new Set(stampedIds);
|
|
19605
|
+
for (const id of toStamp) {
|
|
19606
|
+
if (!stampedSet.has(id)) {
|
|
19607
|
+
skip(id, "stamp-declined");
|
|
19608
|
+
entitiesByMemory.delete(id);
|
|
19609
|
+
}
|
|
19610
|
+
}
|
|
19611
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
19612
|
+
}
|
|
19613
|
+
|
|
19614
|
+
// src/lib/memory/store/local.ts
|
|
19615
|
+
function createLocalMemoryStore(options) {
|
|
19616
|
+
const { database, userId } = options;
|
|
19617
|
+
const entityCtx = {
|
|
19618
|
+
database,
|
|
19619
|
+
entityCollection: database.get("entity"),
|
|
19620
|
+
memoryEntityCollection: database.get("memory_entity"),
|
|
19621
|
+
...userId !== void 0 && { userId },
|
|
19622
|
+
...options.allowUnscopedRows !== void 0 && {
|
|
19623
|
+
allowUnscopedRows: options.allowUnscopedRows
|
|
19624
|
+
}
|
|
19625
|
+
};
|
|
19626
|
+
const vaultCtx = {
|
|
19627
|
+
database,
|
|
19628
|
+
vaultMemoryCollection: database.get("memory_vault"),
|
|
19629
|
+
walletAddress: options.walletAddress,
|
|
19630
|
+
signMessage: options.signMessage,
|
|
19631
|
+
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
19632
|
+
...userId !== void 0 && { userId },
|
|
19633
|
+
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
19634
|
+
// Deletes cascade to memory_entity, so the graph lane never serves a
|
|
19635
|
+
// deleted memory's id.
|
|
19636
|
+
entityCtx
|
|
19637
|
+
};
|
|
19638
|
+
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
19639
|
+
const ownedBy = userId !== void 0 ? [import_watermelondb12.Q.where("user_id", userId)] : [];
|
|
19640
|
+
const watchedColumns = [
|
|
19641
|
+
"content",
|
|
19642
|
+
"scope",
|
|
19643
|
+
"updated_at",
|
|
19644
|
+
"fact_type",
|
|
19645
|
+
"event_time_start",
|
|
19646
|
+
"event_time_end",
|
|
19647
|
+
"event_time_kind",
|
|
19648
|
+
"archived_at",
|
|
19649
|
+
"trust_tier",
|
|
19650
|
+
"superseded_by",
|
|
19651
|
+
"visibility",
|
|
19652
|
+
"published_at",
|
|
19653
|
+
"geohash",
|
|
19654
|
+
"topics",
|
|
19655
|
+
"topics_user_managed",
|
|
19656
|
+
"media",
|
|
19657
|
+
"source"
|
|
19658
|
+
];
|
|
19659
|
+
const embedInBackground = (memory) => {
|
|
19660
|
+
eagerEmbedContent(
|
|
19661
|
+
memory.content,
|
|
19662
|
+
options.embeddingOptions,
|
|
19663
|
+
vaultCache,
|
|
19664
|
+
vaultCtx,
|
|
19665
|
+
memory.uniqueId,
|
|
19666
|
+
memory.updatedAt
|
|
19667
|
+
).catch((err) => {
|
|
19668
|
+
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
19669
|
+
});
|
|
19670
|
+
};
|
|
19671
|
+
return {
|
|
19672
|
+
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
19673
|
+
get: (id) => getVaultMemoryOp(vaultCtx, id),
|
|
19674
|
+
listArchived: async () => {
|
|
19675
|
+
const ids = await vaultCtx.vaultMemoryCollection.query(import_watermelondb12.Q.where("is_deleted", false), import_watermelondb12.Q.where("archived_at", import_watermelondb12.Q.notEq(null)), ...ownedBy).fetchIds();
|
|
19676
|
+
if (ids.length === 0) return [];
|
|
19677
|
+
const rows = await getAllVaultMemoriesOp(vaultCtx, { memoryIds: ids, includeArchived: true });
|
|
19678
|
+
return rows.sort((a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0));
|
|
19679
|
+
},
|
|
19680
|
+
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
19681
|
+
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
19682
|
+
create: async (input) => {
|
|
19683
|
+
const created = await createVaultMemoryOp(vaultCtx, input);
|
|
19684
|
+
if (input.embedding === void 0) embedInBackground(created);
|
|
19685
|
+
return created;
|
|
19686
|
+
},
|
|
19687
|
+
createMany: async (inputs) => {
|
|
19688
|
+
const created = await createVaultMemoriesBatchOp(vaultCtx, inputs);
|
|
19689
|
+
created.forEach((memory, i) => {
|
|
19690
|
+
if (inputs[i].embedding === void 0) embedInBackground(memory);
|
|
19691
|
+
});
|
|
19692
|
+
return created;
|
|
19693
|
+
},
|
|
19694
|
+
update: async (id, patch) => {
|
|
19695
|
+
const reembed = patch.embedding === void 0;
|
|
19696
|
+
const updated = await updateVaultMemoryOp(
|
|
19697
|
+
vaultCtx,
|
|
19698
|
+
id,
|
|
19699
|
+
reembed ? { ...patch, embedding: null } : patch
|
|
19700
|
+
);
|
|
19701
|
+
if (!updated) return null;
|
|
19702
|
+
vaultCache.delete(id);
|
|
19703
|
+
if (reembed) embedInBackground(updated);
|
|
19704
|
+
return updated;
|
|
19705
|
+
},
|
|
19706
|
+
delete: async (id) => {
|
|
19707
|
+
const deleted = await deleteVaultMemoryOp(vaultCtx, id);
|
|
19708
|
+
if (deleted) vaultCache.delete(id);
|
|
19709
|
+
return deleted;
|
|
19710
|
+
},
|
|
19711
|
+
supersede: (id, supersededById) => supersedeVaultMemoryOp(vaultCtx, id, supersededById),
|
|
19712
|
+
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
19713
|
+
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
19714
|
+
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
19715
|
+
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
19716
|
+
const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb12.Q.where("id", memoryId), import_watermelondb12.Q.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
19717
|
+
return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
|
|
19718
|
+
}),
|
|
19719
|
+
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
19720
|
+
recall: (query, recallOptions) => recall(
|
|
19721
|
+
query,
|
|
19722
|
+
{ vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
19723
|
+
{ ...recallOptions, types: ["fact"] }
|
|
19724
|
+
),
|
|
19725
|
+
retain: (content, retainOptions) => retain(
|
|
19726
|
+
content,
|
|
19727
|
+
{ vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
19728
|
+
retainOptions
|
|
19729
|
+
),
|
|
19730
|
+
subscribe: (onChange, subscribeOptions) => {
|
|
19731
|
+
const afterFirst = () => {
|
|
19732
|
+
let first = true;
|
|
19733
|
+
return () => {
|
|
19734
|
+
if (first) first = false;
|
|
19735
|
+
else onChange();
|
|
19736
|
+
};
|
|
19737
|
+
};
|
|
19738
|
+
const memories = subscribeOptions?.includeDeleted ? vaultCtx.vaultMemoryCollection.query(...ownedBy).observe() : vaultCtx.vaultMemoryCollection.query(import_watermelondb12.Q.where("is_deleted", false), ...ownedBy).observeWithColumns(
|
|
19739
|
+
subscribeOptions?.embeddings ? [...watchedColumns, "embedding", "embedding_model"] : watchedColumns
|
|
19740
|
+
);
|
|
19741
|
+
const subscriptions = [memories.subscribe(afterFirst())];
|
|
19742
|
+
if (subscribeOptions?.topics) {
|
|
19743
|
+
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [import_watermelondb12.Q.or(import_watermelondb12.Q.where("user_id", userId), import_watermelondb12.Q.where("user_id", null))] : [import_watermelondb12.Q.where("user_id", userId)];
|
|
19744
|
+
subscriptions.push(
|
|
19745
|
+
entityCtx.memoryEntityCollection.query(...linksOwnedBy).observe().subscribe(afterFirst())
|
|
19746
|
+
);
|
|
19747
|
+
}
|
|
19748
|
+
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
19749
|
+
},
|
|
19750
|
+
maintenance: {
|
|
19751
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
19752
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
19753
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
19754
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
19755
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
19756
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
19757
|
+
}
|
|
19758
|
+
};
|
|
19759
|
+
}
|
|
19760
|
+
|
|
19359
19761
|
// src/lib/memory/synthesizeProfile.ts
|
|
19360
19762
|
init_internalFlowMarker();
|
|
19361
19763
|
init_logger();
|
|
@@ -19885,202 +20287,6 @@ function normalizeInterests(values) {
|
|
|
19885
20287
|
return out.length > 0 ? out : void 0;
|
|
19886
20288
|
}
|
|
19887
20289
|
|
|
19888
|
-
// src/lib/memory/topicExtract.ts
|
|
19889
|
-
init_logger();
|
|
19890
|
-
init_redactor();
|
|
19891
|
-
init_portalLlm();
|
|
19892
|
-
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
19893
|
-
var MAX_CHARS_PER_MEMORY = 300;
|
|
19894
|
-
var MAX_VOCABULARY_NAMES = 100;
|
|
19895
|
-
var MAX_COMPLETION_TOKENS = 8192;
|
|
19896
|
-
var SYSTEM_PROMPT6 = `You assign topics to saved memories for a personal memory system.
|
|
19897
|
-
|
|
19898
|
-
Each memory is a short statement about the user. For each memory, list the NAMED entities it mentions \u2014 these become the memory's topics, used to connect related memories in a knowledge graph.
|
|
19899
|
-
|
|
19900
|
-
Include only NAMED entities, skip generic/common nouns. A topic must identify a specific thing the user could recognize by name; if it would be equally true of thousands of unrelated memories, leave it out:
|
|
19901
|
-
- SKIP bare generic nouns even when the memory capitalizes them or a calendar entry is titled that way \u2014 "Home", "Work", "Meeting", "Lunch", "Birthday", "Appointment", "Trip", "Today", "Friday", "March" are NOT topics.
|
|
19902
|
-
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
19903
|
-
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
19904
|
-
${ENTITY_KIND_GUIDELINES}
|
|
19905
|
-
|
|
19906
|
-
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
19907
|
-
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
19908
|
-
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
19909
|
-
No prose.`;
|
|
19910
|
-
async function extractEntitiesForMemories(memories, options) {
|
|
19911
|
-
const out = /* @__PURE__ */ new Map();
|
|
19912
|
-
if (memories.length === 0) return out;
|
|
19913
|
-
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
19914
|
-
const vocabulary = [];
|
|
19915
|
-
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
19916
|
-
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
19917
|
-
}
|
|
19918
|
-
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
19919
|
-
When a memory refers to one of these, reuse the EXACT existing name (same spelling, casing, spacing and punctuation) instead of a variant \u2014 if "Foo.ai" is listed, never emit "Foo ai" or "Foo AI", and if "Jane Roe" is listed, emit that rather than a bare "Jane".
|
|
19920
|
-
|
|
19921
|
-
` : "";
|
|
19922
|
-
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
19923
|
-
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
19924
|
-
const rows = [];
|
|
19925
|
-
for (const m of batch) {
|
|
19926
|
-
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
19927
|
-
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
19928
|
-
}
|
|
19929
|
-
const listing = rows.join("\n");
|
|
19930
|
-
const parsed = await callPortalJsonCompletion({
|
|
19931
|
-
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
19932
|
-
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
19933
|
-
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
19934
|
-
taskType: "memory_topic",
|
|
19935
|
-
...options.endpointOverride !== void 0 && {
|
|
19936
|
-
endpointOverride: options.endpointOverride
|
|
19937
|
-
},
|
|
19938
|
-
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
19939
|
-
systemPrompt: SYSTEM_PROMPT6,
|
|
19940
|
-
userMessage: `${vocabularyNote}Memories:
|
|
19941
|
-
${listing}
|
|
19942
|
-
|
|
19943
|
-
List each memory's named entities.`,
|
|
19944
|
-
tag: "memory/topics",
|
|
19945
|
-
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
19946
|
-
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
19947
|
-
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
19948
|
-
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
19949
|
-
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
19950
|
-
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
19951
|
-
});
|
|
19952
|
-
if (parsed === null) {
|
|
19953
|
-
getLogger().warn(
|
|
19954
|
-
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
19955
|
-
);
|
|
19956
|
-
continue;
|
|
19957
|
-
}
|
|
19958
|
-
const validIds = new Set(batch.map((m) => m.id));
|
|
19959
|
-
const byId = parseTopicResponse(parsed, validIds);
|
|
19960
|
-
if (byId === null) {
|
|
19961
|
-
getLogger().warn(
|
|
19962
|
-
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
19963
|
-
);
|
|
19964
|
-
continue;
|
|
19965
|
-
}
|
|
19966
|
-
for (const m of batch) {
|
|
19967
|
-
const entities = byId.get(m.id);
|
|
19968
|
-
if (entities === void 0) {
|
|
19969
|
-
continue;
|
|
19970
|
-
}
|
|
19971
|
-
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
19972
|
-
}
|
|
19973
|
-
}
|
|
19974
|
-
return out;
|
|
19975
|
-
}
|
|
19976
|
-
function restoreEntities(entities, redactor) {
|
|
19977
|
-
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
19978
|
-
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
19979
|
-
);
|
|
19980
|
-
}
|
|
19981
|
-
function parseTopicResponse(parsed, validIds) {
|
|
19982
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
19983
|
-
const list = parsed.memories;
|
|
19984
|
-
if (!Array.isArray(list)) return null;
|
|
19985
|
-
const out = /* @__PURE__ */ new Map();
|
|
19986
|
-
for (const raw of list) {
|
|
19987
|
-
if (typeof raw !== "object" || raw === null) continue;
|
|
19988
|
-
const obj = raw;
|
|
19989
|
-
if (typeof obj.id !== "string") continue;
|
|
19990
|
-
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
19991
|
-
if (!validIds.has(id) || out.has(id)) continue;
|
|
19992
|
-
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
19993
|
-
out.set(id, entities);
|
|
19994
|
-
}
|
|
19995
|
-
return out;
|
|
19996
|
-
}
|
|
19997
|
-
var DEGRADED_TOPIC_SKIP = {
|
|
19998
|
-
excluded: false,
|
|
19999
|
-
"link-declined": false,
|
|
20000
|
-
"stamp-declined": false,
|
|
20001
|
-
"llm-unanswered": true,
|
|
20002
|
-
unreadable: true,
|
|
20003
|
-
"not-found": true,
|
|
20004
|
-
"link-failed": true
|
|
20005
|
-
};
|
|
20006
|
-
function isDegradedTopicSkip(reason) {
|
|
20007
|
-
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
20008
|
-
}
|
|
20009
|
-
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
20010
|
-
const entityCtx = ctx.entityCtx;
|
|
20011
|
-
if (!entityCtx) {
|
|
20012
|
-
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
20013
|
-
}
|
|
20014
|
-
const log = getLogger();
|
|
20015
|
-
const extractedAt = options.now ?? Date.now();
|
|
20016
|
-
const skippedIds = [];
|
|
20017
|
-
const skippedReasons = /* @__PURE__ */ new Map();
|
|
20018
|
-
const skip = (id, reason) => {
|
|
20019
|
-
if (skippedReasons.has(id)) return;
|
|
20020
|
-
skippedIds.push(id);
|
|
20021
|
-
skippedReasons.set(id, reason);
|
|
20022
|
-
};
|
|
20023
|
-
const inputs = [];
|
|
20024
|
-
for (const id of new Set(memoryIds)) {
|
|
20025
|
-
let record;
|
|
20026
|
-
try {
|
|
20027
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
20028
|
-
} catch (err) {
|
|
20029
|
-
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
20030
|
-
skip(id, "not-found");
|
|
20031
|
-
continue;
|
|
20032
|
-
}
|
|
20033
|
-
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
20034
|
-
skip(id, "excluded");
|
|
20035
|
-
continue;
|
|
20036
|
-
}
|
|
20037
|
-
try {
|
|
20038
|
-
const stored = await vaultMemoryToStored(
|
|
20039
|
-
record,
|
|
20040
|
-
ctx.walletAddress,
|
|
20041
|
-
ctx.signMessage,
|
|
20042
|
-
ctx.embeddedWalletSigner
|
|
20043
|
-
);
|
|
20044
|
-
inputs.push({ id, content: stored.content });
|
|
20045
|
-
} catch (err) {
|
|
20046
|
-
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
20047
|
-
skip(id, "unreadable");
|
|
20048
|
-
}
|
|
20049
|
-
}
|
|
20050
|
-
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
20051
|
-
const toStamp = [];
|
|
20052
|
-
for (const input of inputs) {
|
|
20053
|
-
const entities = entitiesByMemory.get(input.id);
|
|
20054
|
-
if (entities === void 0) {
|
|
20055
|
-
skip(input.id, "llm-unanswered");
|
|
20056
|
-
continue;
|
|
20057
|
-
}
|
|
20058
|
-
try {
|
|
20059
|
-
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
20060
|
-
if (linked === null) {
|
|
20061
|
-
skip(input.id, "link-declined");
|
|
20062
|
-
entitiesByMemory.delete(input.id);
|
|
20063
|
-
continue;
|
|
20064
|
-
}
|
|
20065
|
-
} catch (err) {
|
|
20066
|
-
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
20067
|
-
skip(input.id, "link-failed");
|
|
20068
|
-
entitiesByMemory.delete(input.id);
|
|
20069
|
-
continue;
|
|
20070
|
-
}
|
|
20071
|
-
toStamp.push(input.id);
|
|
20072
|
-
}
|
|
20073
|
-
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
20074
|
-
const stampedSet = new Set(stampedIds);
|
|
20075
|
-
for (const id of toStamp) {
|
|
20076
|
-
if (!stampedSet.has(id)) {
|
|
20077
|
-
skip(id, "stamp-declined");
|
|
20078
|
-
entitiesByMemory.delete(id);
|
|
20079
|
-
}
|
|
20080
|
-
}
|
|
20081
|
-
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
20082
|
-
}
|
|
20083
|
-
|
|
20084
20290
|
// src/lib/memory/verifySupport.ts
|
|
20085
20291
|
init_logger();
|
|
20086
20292
|
init_redactor();
|
|
@@ -20474,7 +20680,7 @@ async function assembleMemoryContext(options) {
|
|
|
20474
20680
|
}
|
|
20475
20681
|
|
|
20476
20682
|
// src/lib/memory/durableExtraction.ts
|
|
20477
|
-
var
|
|
20683
|
+
var import_watermelondb13 = require("@nozbe/watermelondb");
|
|
20478
20684
|
var MAX_JOBS_PER_PASS = 3;
|
|
20479
20685
|
var MAX_ATTEMPTS = 3;
|
|
20480
20686
|
var MAX_FAILED_SESSIONS = 3;
|
|
@@ -20621,7 +20827,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20621
20827
|
...options.retainCtx,
|
|
20622
20828
|
vaultCtx: {
|
|
20623
20829
|
...vault,
|
|
20624
|
-
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(
|
|
20830
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("id", import_watermelondb13.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
20625
20831
|
}
|
|
20626
20832
|
},
|
|
20627
20833
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -20763,7 +20969,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20763
20969
|
let scheduleAfterSuccess = false;
|
|
20764
20970
|
try {
|
|
20765
20971
|
await writes;
|
|
20766
|
-
const pending = await jobs.query(
|
|
20972
|
+
const pending = await jobs.query(import_watermelondb13.Q.where("owner_key", owner), import_watermelondb13.Q.where("message_ids", import_watermelondb13.Q.notEq("[]"))).fetch();
|
|
20767
20973
|
storeFailures = 0;
|
|
20768
20974
|
let processed = 0;
|
|
20769
20975
|
for (const job of pending) {
|
|
@@ -20779,7 +20985,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20779
20985
|
let ids = [];
|
|
20780
20986
|
let loaded = [];
|
|
20781
20987
|
try {
|
|
20782
|
-
const conversations = await storage.conversationsCollection.query(
|
|
20988
|
+
const conversations = await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount();
|
|
20783
20989
|
if (!conversations) {
|
|
20784
20990
|
await database.write(() => job.destroyPermanently());
|
|
20785
20991
|
continue;
|
|
@@ -20896,12 +21102,12 @@ function createDurableAutoExtractor(options) {
|
|
|
20896
21102
|
const scope = currentScope();
|
|
20897
21103
|
writes = writes.then(
|
|
20898
21104
|
() => database.write(async () => {
|
|
20899
|
-
const existing = await jobs.query(
|
|
21105
|
+
const existing = await jobs.query(import_watermelondb13.Q.where("owner_key", owner), import_watermelondb13.Q.where("conversation_id", conversationId)).fetch();
|
|
20900
21106
|
const job = existing.find(
|
|
20901
21107
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
20902
21108
|
);
|
|
20903
21109
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
20904
|
-
const rows = await storage.messagesCollection.query(
|
|
21110
|
+
const rows = await storage.messagesCollection.query(import_watermelondb13.Q.where("id", import_watermelondb13.Q.oneOf(ids))).fetch();
|
|
20905
21111
|
const sequences = /* @__PURE__ */ new Map();
|
|
20906
21112
|
for (const row of rows) {
|
|
20907
21113
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -23594,13 +23800,13 @@ init_patterns();
|
|
|
23594
23800
|
init_redactor();
|
|
23595
23801
|
|
|
23596
23802
|
// src/lib/db/schema.ts
|
|
23597
|
-
var
|
|
23803
|
+
var import_watermelondb22 = require("@nozbe/watermelondb");
|
|
23598
23804
|
var import_migrations2 = require("@nozbe/watermelondb/Schema/migrations");
|
|
23599
23805
|
|
|
23600
23806
|
// src/lib/db/appFiles/models.ts
|
|
23601
|
-
var
|
|
23807
|
+
var import_watermelondb14 = require("@nozbe/watermelondb");
|
|
23602
23808
|
var import_decorators4 = require("@nozbe/watermelondb/decorators");
|
|
23603
|
-
var AppFile = class extends
|
|
23809
|
+
var AppFile = class extends import_watermelondb14.Model {
|
|
23604
23810
|
};
|
|
23605
23811
|
AppFile.table = "app_files";
|
|
23606
23812
|
AppFile.associations = {};
|
|
@@ -23622,9 +23828,9 @@ __decorateClass([
|
|
|
23622
23828
|
], AppFile.prototype, "updatedAt", 2);
|
|
23623
23829
|
|
|
23624
23830
|
// src/lib/db/conversationMemory/models.ts
|
|
23625
|
-
var
|
|
23831
|
+
var import_watermelondb15 = require("@nozbe/watermelondb");
|
|
23626
23832
|
var import_decorators5 = require("@nozbe/watermelondb/decorators");
|
|
23627
|
-
var ConversationMemory = class extends
|
|
23833
|
+
var ConversationMemory = class extends import_watermelondb15.Model {
|
|
23628
23834
|
};
|
|
23629
23835
|
ConversationMemory.table = "conversation_memory";
|
|
23630
23836
|
ConversationMemory.associations = {};
|
|
@@ -23643,9 +23849,9 @@ __decorateClass([
|
|
|
23643
23849
|
], ConversationMemory.prototype, "createdAt", 2);
|
|
23644
23850
|
|
|
23645
23851
|
// src/lib/db/entities/models.ts
|
|
23646
|
-
var
|
|
23852
|
+
var import_watermelondb16 = require("@nozbe/watermelondb");
|
|
23647
23853
|
var import_decorators6 = require("@nozbe/watermelondb/decorators");
|
|
23648
|
-
var Entity = class extends
|
|
23854
|
+
var Entity = class extends import_watermelondb16.Model {
|
|
23649
23855
|
};
|
|
23650
23856
|
Entity.table = "entity";
|
|
23651
23857
|
__decorateClass([
|
|
@@ -23661,7 +23867,7 @@ __decorateClass([
|
|
|
23661
23867
|
__decorateClass([
|
|
23662
23868
|
(0, import_decorators6.date)("updated_at")
|
|
23663
23869
|
], Entity.prototype, "updatedAt", 2);
|
|
23664
|
-
var MemoryEntity = class extends
|
|
23870
|
+
var MemoryEntity = class extends import_watermelondb16.Model {
|
|
23665
23871
|
};
|
|
23666
23872
|
MemoryEntity.table = "memory_entity";
|
|
23667
23873
|
__decorateClass([
|
|
@@ -23679,9 +23885,9 @@ __decorateClass([
|
|
|
23679
23885
|
], MemoryEntity.prototype, "createdAt", 2);
|
|
23680
23886
|
|
|
23681
23887
|
// src/lib/db/project/models.ts
|
|
23682
|
-
var
|
|
23888
|
+
var import_watermelondb17 = require("@nozbe/watermelondb");
|
|
23683
23889
|
var import_decorators7 = require("@nozbe/watermelondb/decorators");
|
|
23684
|
-
var Project = class extends
|
|
23890
|
+
var Project = class extends import_watermelondb17.Model {
|
|
23685
23891
|
};
|
|
23686
23892
|
Project.table = "projects";
|
|
23687
23893
|
Project.associations = {
|
|
@@ -23704,10 +23910,10 @@ __decorateClass([
|
|
|
23704
23910
|
], Project.prototype, "isDeleted", 2);
|
|
23705
23911
|
|
|
23706
23912
|
// src/lib/db/savedTools/models.ts
|
|
23707
|
-
var
|
|
23913
|
+
var import_watermelondb18 = require("@nozbe/watermelondb");
|
|
23708
23914
|
var import_decorators8 = require("@nozbe/watermelondb/decorators");
|
|
23709
23915
|
var sanitizeParameters = (raw) => raw ?? {};
|
|
23710
|
-
var SavedTool = class extends
|
|
23916
|
+
var SavedTool = class extends import_watermelondb18.Model {
|
|
23711
23917
|
};
|
|
23712
23918
|
SavedTool.table = "saved_tools";
|
|
23713
23919
|
SavedTool.associations = {};
|
|
@@ -23741,9 +23947,9 @@ __decorateClass([
|
|
|
23741
23947
|
], SavedTool.prototype, "isDeleted", 2);
|
|
23742
23948
|
|
|
23743
23949
|
// src/lib/db/settings/models.ts
|
|
23744
|
-
var
|
|
23950
|
+
var import_watermelondb19 = require("@nozbe/watermelondb");
|
|
23745
23951
|
var import_decorators9 = require("@nozbe/watermelondb/decorators");
|
|
23746
|
-
var ModelPreference = class extends
|
|
23952
|
+
var ModelPreference = class extends import_watermelondb19.Model {
|
|
23747
23953
|
};
|
|
23748
23954
|
ModelPreference.table = "modelPreferences";
|
|
23749
23955
|
__decorateClass([
|
|
@@ -23754,9 +23960,9 @@ __decorateClass([
|
|
|
23754
23960
|
], ModelPreference.prototype, "models", 2);
|
|
23755
23961
|
|
|
23756
23962
|
// src/lib/db/userPreferences/models.ts
|
|
23757
|
-
var
|
|
23963
|
+
var import_watermelondb20 = require("@nozbe/watermelondb");
|
|
23758
23964
|
var import_decorators10 = require("@nozbe/watermelondb/decorators");
|
|
23759
|
-
var UserPreference = class extends
|
|
23965
|
+
var UserPreference = class extends import_watermelondb20.Model {
|
|
23760
23966
|
};
|
|
23761
23967
|
UserPreference.table = "userPreferences";
|
|
23762
23968
|
__decorateClass([
|
|
@@ -23785,9 +23991,9 @@ __decorateClass([
|
|
|
23785
23991
|
], UserPreference.prototype, "updatedAt", 2);
|
|
23786
23992
|
|
|
23787
23993
|
// src/lib/db/vaultFolders/models.ts
|
|
23788
|
-
var
|
|
23994
|
+
var import_watermelondb21 = require("@nozbe/watermelondb");
|
|
23789
23995
|
var import_decorators11 = require("@nozbe/watermelondb/decorators");
|
|
23790
|
-
var VaultFolder = class extends
|
|
23996
|
+
var VaultFolder = class extends import_watermelondb21.Model {
|
|
23791
23997
|
};
|
|
23792
23998
|
VaultFolder.table = "vault_folders";
|
|
23793
23999
|
__decorateClass([
|
|
@@ -23815,10 +24021,10 @@ __decorateClass([
|
|
|
23815
24021
|
|
|
23816
24022
|
// src/lib/db/schema.ts
|
|
23817
24023
|
var SDK_SCHEMA_VERSION = 47;
|
|
23818
|
-
var sdkSchema = (0,
|
|
24024
|
+
var sdkSchema = (0, import_watermelondb22.appSchema)({
|
|
23819
24025
|
version: SDK_SCHEMA_VERSION,
|
|
23820
24026
|
tables: [
|
|
23821
|
-
(0,
|
|
24027
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23822
24028
|
name: "memory_extraction_jobs",
|
|
23823
24029
|
columns: [
|
|
23824
24030
|
{ name: "owner_key", type: "string", isIndexed: true },
|
|
@@ -23838,7 +24044,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
23838
24044
|
]
|
|
23839
24045
|
}),
|
|
23840
24046
|
// Chat storage tables
|
|
23841
|
-
(0,
|
|
24047
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23842
24048
|
name: "history",
|
|
23843
24049
|
columns: [
|
|
23844
24050
|
{ name: "message_id", type: "number" },
|
|
@@ -23877,7 +24083,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
23877
24083
|
// MessageOrigin — provenance, NOT encrypted (see v44)
|
|
23878
24084
|
]
|
|
23879
24085
|
}),
|
|
23880
|
-
(0,
|
|
24086
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23881
24087
|
name: "conversations",
|
|
23882
24088
|
columns: [
|
|
23883
24089
|
{ name: "conversation_id", type: "string", isIndexed: true },
|
|
@@ -23899,7 +24105,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
23899
24105
|
]
|
|
23900
24106
|
}),
|
|
23901
24107
|
// Project storage table
|
|
23902
|
-
(0,
|
|
24108
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23903
24109
|
name: "projects",
|
|
23904
24110
|
columns: [
|
|
23905
24111
|
{ name: "project_id", type: "string", isIndexed: true },
|
|
@@ -23910,7 +24116,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
23910
24116
|
]
|
|
23911
24117
|
}),
|
|
23912
24118
|
// Settings storage tables (deprecated - use userPreferences)
|
|
23913
|
-
(0,
|
|
24119
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23914
24120
|
name: "modelPreferences",
|
|
23915
24121
|
columns: [
|
|
23916
24122
|
{ name: "wallet_address", type: "string", isIndexed: true },
|
|
@@ -23918,7 +24124,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
23918
24124
|
]
|
|
23919
24125
|
}),
|
|
23920
24126
|
// Unified user preferences storage
|
|
23921
|
-
(0,
|
|
24127
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23922
24128
|
name: "userPreferences",
|
|
23923
24129
|
columns: [
|
|
23924
24130
|
// Identity
|
|
@@ -23937,7 +24143,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
23937
24143
|
]
|
|
23938
24144
|
}),
|
|
23939
24145
|
// Memory vault storage
|
|
23940
|
-
(0,
|
|
24146
|
+
(0, import_watermelondb22.tableSchema)({
|
|
23941
24147
|
name: "memory_vault",
|
|
23942
24148
|
columns: [
|
|
23943
24149
|
{ name: "content", type: "string" },
|
|
@@ -24065,7 +24271,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24065
24271
|
]
|
|
24066
24272
|
}),
|
|
24067
24273
|
// Entity table — canonical names extracted from auto-extraction (W5).
|
|
24068
|
-
(0,
|
|
24274
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24069
24275
|
name: "entity",
|
|
24070
24276
|
columns: [
|
|
24071
24277
|
{ name: "canonical_name", type: "string", isIndexed: true },
|
|
@@ -24075,7 +24281,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24075
24281
|
]
|
|
24076
24282
|
}),
|
|
24077
24283
|
// Many-to-many join: which memories reference which entities.
|
|
24078
|
-
(0,
|
|
24284
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24079
24285
|
name: "memory_entity",
|
|
24080
24286
|
columns: [
|
|
24081
24287
|
{ name: "memory_id", type: "string", isIndexed: true },
|
|
@@ -24085,7 +24291,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24085
24291
|
]
|
|
24086
24292
|
}),
|
|
24087
24293
|
// Vault folder organization
|
|
24088
|
-
(0,
|
|
24294
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24089
24295
|
name: "vault_folders",
|
|
24090
24296
|
columns: [
|
|
24091
24297
|
{ name: "name", type: "string" },
|
|
@@ -24098,7 +24304,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24098
24304
|
]
|
|
24099
24305
|
}),
|
|
24100
24306
|
// Conversation summary cache for progressive history summarization
|
|
24101
|
-
(0,
|
|
24307
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24102
24308
|
name: "conversation_summaries",
|
|
24103
24309
|
columns: [
|
|
24104
24310
|
{ name: "conversation_id", type: "string", isIndexed: true },
|
|
@@ -24111,7 +24317,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24111
24317
|
]
|
|
24112
24318
|
}),
|
|
24113
24319
|
// Media library storage (images, videos, audio, documents)
|
|
24114
|
-
(0,
|
|
24320
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24115
24321
|
name: "media",
|
|
24116
24322
|
columns: [
|
|
24117
24323
|
// Identity
|
|
@@ -24147,7 +24353,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24147
24353
|
]
|
|
24148
24354
|
}),
|
|
24149
24355
|
// ── App files ─────────────────────────────────────────────────────────
|
|
24150
|
-
(0,
|
|
24356
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24151
24357
|
name: "app_files",
|
|
24152
24358
|
columns: [
|
|
24153
24359
|
{ name: "conversation_id", type: "string", isIndexed: true },
|
|
@@ -24158,7 +24364,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24158
24364
|
]
|
|
24159
24365
|
}),
|
|
24160
24366
|
// ── Saved tools ──────────────────────────────────────────────────────
|
|
24161
|
-
(0,
|
|
24367
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24162
24368
|
name: "saved_tools",
|
|
24163
24369
|
columns: [
|
|
24164
24370
|
{ name: "name", type: "string" },
|
|
@@ -24174,7 +24380,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
24174
24380
|
]
|
|
24175
24381
|
}),
|
|
24176
24382
|
// ── Conversation memories (panel persistence) ────────────────────────
|
|
24177
|
-
(0,
|
|
24383
|
+
(0, import_watermelondb22.tableSchema)({
|
|
24178
24384
|
name: "conversation_memory",
|
|
24179
24385
|
columns: [
|
|
24180
24386
|
{ name: "conversation_id", type: "string", isIndexed: true },
|
|
@@ -24896,7 +25102,7 @@ var sdkModelClasses = [
|
|
|
24896
25102
|
];
|
|
24897
25103
|
|
|
24898
25104
|
// src/lib/db/manager.ts
|
|
24899
|
-
var
|
|
25105
|
+
var import_watermelondb23 = require("@nozbe/watermelondb");
|
|
24900
25106
|
var DESTRUCTIVE_MIGRATION_VERSION = 8;
|
|
24901
25107
|
var webPlatformStorage = {
|
|
24902
25108
|
getItem: (key) => localStorage.getItem(key),
|
|
@@ -24977,7 +25183,7 @@ var DatabaseManager = class {
|
|
|
24977
25183
|
walletAddress
|
|
24978
25184
|
});
|
|
24979
25185
|
const adapter = this.createAdapter(dbName, sdkSchema, sdkMigrations);
|
|
24980
|
-
const database = new
|
|
25186
|
+
const database = new import_watermelondb23.Database({
|
|
24981
25187
|
adapter,
|
|
24982
25188
|
modelClasses: sdkModelClasses
|
|
24983
25189
|
});
|
|
@@ -25056,7 +25262,7 @@ var DatabaseManager = class {
|
|
|
25056
25262
|
};
|
|
25057
25263
|
|
|
25058
25264
|
// src/lib/db/conversationMemory/operations.ts
|
|
25059
|
-
var
|
|
25265
|
+
var import_watermelondb24 = require("@nozbe/watermelondb");
|
|
25060
25266
|
var MAX_PER_CONVERSATION = 200;
|
|
25061
25267
|
function conversationMemoryToStored(row) {
|
|
25062
25268
|
return {
|
|
@@ -25071,7 +25277,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
25071
25277
|
if (!conversationId || items.length === 0) return;
|
|
25072
25278
|
const now = Date.now();
|
|
25073
25279
|
await ctx.database.write(async () => {
|
|
25074
|
-
const existing = await ctx.conversationMemoryCollection.query(
|
|
25280
|
+
const existing = await ctx.conversationMemoryCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.sortBy("created_at", import_watermelondb24.Q.asc)).fetch();
|
|
25075
25281
|
const seen = new Set(existing.map((r) => r.memoryId));
|
|
25076
25282
|
const batchSeen = /* @__PURE__ */ new Set();
|
|
25077
25283
|
const deduped = [];
|
|
@@ -25106,20 +25312,20 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
25106
25312
|
}
|
|
25107
25313
|
async function getConversationMemoriesOp(ctx, conversationId) {
|
|
25108
25314
|
if (!conversationId) return [];
|
|
25109
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
25315
|
+
const rows = await ctx.conversationMemoryCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.sortBy("created_at", import_watermelondb24.Q.asc)).fetch();
|
|
25110
25316
|
return rows.map(conversationMemoryToStored);
|
|
25111
25317
|
}
|
|
25112
25318
|
async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
25113
25319
|
if (!conversationId) return;
|
|
25114
25320
|
await ctx.database.write(async () => {
|
|
25115
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
25321
|
+
const rows = await ctx.conversationMemoryCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId)).fetch();
|
|
25116
25322
|
if (rows.length === 0) return;
|
|
25117
25323
|
await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
|
|
25118
25324
|
});
|
|
25119
25325
|
}
|
|
25120
25326
|
|
|
25121
25327
|
// src/lib/db/vaultFolders/operations.ts
|
|
25122
|
-
var
|
|
25328
|
+
var import_watermelondb25 = require("@nozbe/watermelondb");
|
|
25123
25329
|
function folderToStored(folder) {
|
|
25124
25330
|
return {
|
|
25125
25331
|
uniqueId: folder.id,
|
|
@@ -25144,7 +25350,7 @@ async function createVaultFolderOp(ctx, opts) {
|
|
|
25144
25350
|
return folderToStored(created);
|
|
25145
25351
|
}
|
|
25146
25352
|
async function getAllVaultFoldersOp(ctx) {
|
|
25147
|
-
const results = await ctx.vaultFolderCollection.query(
|
|
25353
|
+
const results = await ctx.vaultFolderCollection.query(import_watermelondb25.Q.where("is_deleted", false), import_watermelondb25.Q.sortBy("created_at", import_watermelondb25.Q.desc)).fetch();
|
|
25148
25354
|
return results.map(folderToStored);
|
|
25149
25355
|
}
|
|
25150
25356
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
@@ -25153,7 +25359,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
25153
25359
|
if (record.isDeleted) return null;
|
|
25154
25360
|
const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
|
|
25155
25361
|
const updated = await ctx.database.write(async () => {
|
|
25156
|
-
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(
|
|
25362
|
+
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb25.Q.where("folder_id", id), import_watermelondb25.Q.where("is_deleted", false)).fetch() : [];
|
|
25157
25363
|
const updates = [];
|
|
25158
25364
|
updates.push(
|
|
25159
25365
|
record.prepareUpdate((r) => {
|
|
@@ -25181,7 +25387,7 @@ async function deleteVaultFolderOp(ctx, id) {
|
|
|
25181
25387
|
const record = await ctx.vaultFolderCollection.find(id);
|
|
25182
25388
|
if (record.isDeleted) return false;
|
|
25183
25389
|
await ctx.database.write(async () => {
|
|
25184
|
-
const memories = await ctx.vaultMemoryCollection.query(
|
|
25390
|
+
const memories = await ctx.vaultMemoryCollection.query(import_watermelondb25.Q.where("folder_id", id), import_watermelondb25.Q.where("is_deleted", false)).fetch();
|
|
25185
25391
|
const preparedMemories = memories.map(
|
|
25186
25392
|
(memory) => memory.prepareUpdate((r) => {
|
|
25187
25393
|
r._setRaw("folder_id", null);
|
|
@@ -25250,7 +25456,7 @@ async function updateVaultFolderContextOp(ctx, id, context) {
|
|
|
25250
25456
|
}
|
|
25251
25457
|
}
|
|
25252
25458
|
async function getVaultFolderMemoryCountOp(ctx, folderId) {
|
|
25253
|
-
return await ctx.vaultMemoryCollection.query(
|
|
25459
|
+
return await ctx.vaultMemoryCollection.query(import_watermelondb25.Q.where("folder_id", folderId), import_watermelondb25.Q.where("is_deleted", false)).fetchCount();
|
|
25254
25460
|
}
|
|
25255
25461
|
|
|
25256
25462
|
// src/lib/db/vaultFolders/defaults.ts
|
|
@@ -26288,6 +26494,7 @@ function createNotionProxyTools(callMcp) {
|
|
|
26288
26494
|
createDurableAutoExtractor,
|
|
26289
26495
|
createLlmDecayClassifier,
|
|
26290
26496
|
createLlmNeighborRefiner,
|
|
26497
|
+
createLocalMemoryStore,
|
|
26291
26498
|
createMemoryEngineTool,
|
|
26292
26499
|
createMemoryVaultSearchTool,
|
|
26293
26500
|
createMemoryVaultTool,
|