@anuma/sdk 6.31.4 → 6.33.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.
@@ -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,
@@ -13241,6 +13242,51 @@ async function updateVaultMemoryOp(ctx, id, opts) {
13241
13242
  return null;
13242
13243
  }
13243
13244
  }
13245
+ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
13246
+ const entityCtx = ctx.entityCtx;
13247
+ if (!entityCtx) {
13248
+ throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
13249
+ }
13250
+ let record;
13251
+ try {
13252
+ record = await ctx.vaultMemoryCollection.find(memoryId);
13253
+ } catch {
13254
+ return null;
13255
+ }
13256
+ if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
13257
+ let stale = false;
13258
+ const originalUpdatedAt = record.updatedAt.getTime();
13259
+ await ctx.database.write(async (writer) => {
13260
+ if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
13261
+ stale = true;
13262
+ return;
13263
+ }
13264
+ await record.update((r) => {
13265
+ r._setRaw("topics_user_managed", true);
13266
+ r._setRaw("updated_at", originalUpdatedAt);
13267
+ });
13268
+ const linked = entities.length > 0 ? await writer.callWriter(
13269
+ () => linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" })
13270
+ ) : [];
13271
+ const keep = new Set(linked.map((e) => e.uniqueId));
13272
+ const existing = await entityCtx.memoryEntityCollection.query(import_watermelondb10.Q.where("memory_id", memoryId)).fetch();
13273
+ const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
13274
+ if (staleLinks.length === 0 && entities.length > 0) return;
13275
+ const topicsWrite = await resolveMemoryTopicsWrite(
13276
+ entityCtx,
13277
+ memoryId,
13278
+ linked,
13279
+ entities,
13280
+ "user"
13281
+ );
13282
+ await ctx.database.batch(
13283
+ ...staleLinks.map((l) => l.prepareDestroyPermanently()),
13284
+ ...topicsWrite ? [prepareMemoryTopicsUpdate(topicsWrite)] : []
13285
+ );
13286
+ });
13287
+ if (stale) return null;
13288
+ return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13289
+ }
13244
13290
  async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
13245
13291
  let record;
13246
13292
  try {
@@ -15817,7 +15863,10 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
15817
15863
  if (memoryId) cacheRowVector(cache, memoryId, Float32Array.from(embedding), updatedAt, content);
15818
15864
  if (vaultCtx && memoryId) {
15819
15865
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
15820
- updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel).catch(
15866
+ updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel, {
15867
+ content,
15868
+ ...updatedAt !== void 0 && { updatedAt: updatedAt.getTime() }
15869
+ }).catch(
15821
15870
  // Silently swallow – SDK must not use console.*; embedding will be retried on next search
15822
15871
  () => {
15823
15872
  }
@@ -19356,6 +19405,353 @@ function parseAnswer(body, base, parseSchema) {
19356
19405
  };
19357
19406
  }
19358
19407
 
19408
+ // src/lib/memory/store/local.ts
19409
+ var import_watermelondb12 = require("@nozbe/watermelondb");
19410
+ init_logger();
19411
+
19412
+ // src/lib/memory/topicExtract.ts
19413
+ init_logger();
19414
+ init_redactor();
19415
+ init_portalLlm();
19416
+ var TOPIC_EXTRACTION_BATCH_SIZE = 10;
19417
+ var MAX_CHARS_PER_MEMORY = 300;
19418
+ var MAX_VOCABULARY_NAMES = 100;
19419
+ var MAX_COMPLETION_TOKENS = 8192;
19420
+ var SYSTEM_PROMPT6 = `You assign topics to saved memories for a personal memory system.
19421
+
19422
+ 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.
19423
+
19424
+ 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:
19425
+ - 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.
19426
+ - KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
19427
+ - Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
19428
+ ${ENTITY_KIND_GUIDELINES}
19429
+
19430
+ Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
19431
+ - exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
19432
+ - "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
19433
+ No prose.`;
19434
+ async function extractEntitiesForMemories(memories, options) {
19435
+ const out = /* @__PURE__ */ new Map();
19436
+ if (memories.length === 0) return out;
19437
+ const redactor = resolvePiiRedactor(options.piiRedaction);
19438
+ const vocabulary = [];
19439
+ for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
19440
+ vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
19441
+ }
19442
+ const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
19443
+ 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".
19444
+
19445
+ ` : "";
19446
+ for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
19447
+ const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
19448
+ const rows = [];
19449
+ for (const m of batch) {
19450
+ const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
19451
+ rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
19452
+ }
19453
+ const listing = rows.join("\n");
19454
+ const parsed = await callPortalJsonCompletion({
19455
+ ...options.apiKey !== void 0 && { apiKey: options.apiKey },
19456
+ ...options.getToken !== void 0 && { getToken: options.getToken },
19457
+ ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
19458
+ taskType: "memory_topic",
19459
+ ...options.endpointOverride !== void 0 && {
19460
+ endpointOverride: options.endpointOverride
19461
+ },
19462
+ model: options.model ?? DEFAULT_EXTRACTION_MODEL,
19463
+ systemPrompt: SYSTEM_PROMPT6,
19464
+ userMessage: `${vocabularyNote}Memories:
19465
+ ${listing}
19466
+
19467
+ List each memory's named entities.`,
19468
+ tag: "memory/topics",
19469
+ extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
19470
+ ...options.fetchFn && { fetchFn: options.fetchFn },
19471
+ ...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
19472
+ ...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
19473
+ ...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
19474
+ ...options.backoffMs && { backoffMs: options.backoffMs }
19475
+ });
19476
+ if (parsed === null) {
19477
+ getLogger().warn(
19478
+ `[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
19479
+ );
19480
+ continue;
19481
+ }
19482
+ const validIds = new Set(batch.map((m) => m.id));
19483
+ const byId = parseTopicResponse(parsed, validIds);
19484
+ if (byId === null) {
19485
+ getLogger().warn(
19486
+ `[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
19487
+ );
19488
+ continue;
19489
+ }
19490
+ for (const m of batch) {
19491
+ const entities = byId.get(m.id);
19492
+ if (entities === void 0) {
19493
+ continue;
19494
+ }
19495
+ out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
19496
+ }
19497
+ }
19498
+ return out;
19499
+ }
19500
+ function restoreEntities(entities, redactor) {
19501
+ return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
19502
+ (e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
19503
+ );
19504
+ }
19505
+ function parseTopicResponse(parsed, validIds) {
19506
+ if (typeof parsed !== "object" || parsed === null) return null;
19507
+ const list = parsed.memories;
19508
+ if (!Array.isArray(list)) return null;
19509
+ const out = /* @__PURE__ */ new Map();
19510
+ for (const raw of list) {
19511
+ if (typeof raw !== "object" || raw === null) continue;
19512
+ const obj = raw;
19513
+ if (typeof obj.id !== "string") continue;
19514
+ const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
19515
+ if (!validIds.has(id) || out.has(id)) continue;
19516
+ const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
19517
+ out.set(id, entities);
19518
+ }
19519
+ return out;
19520
+ }
19521
+ var DEGRADED_TOPIC_SKIP = {
19522
+ excluded: false,
19523
+ "link-declined": false,
19524
+ "stamp-declined": false,
19525
+ "llm-unanswered": true,
19526
+ unreadable: true,
19527
+ "not-found": true,
19528
+ "link-failed": true
19529
+ };
19530
+ function isDegradedTopicSkip(reason) {
19531
+ return DEGRADED_TOPIC_SKIP[reason] === true;
19532
+ }
19533
+ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
19534
+ const entityCtx = ctx.entityCtx;
19535
+ if (!entityCtx) {
19536
+ throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
19537
+ }
19538
+ const log = getLogger();
19539
+ const extractedAt = options.now ?? Date.now();
19540
+ const skippedIds = [];
19541
+ const skippedReasons = /* @__PURE__ */ new Map();
19542
+ const skip = (id, reason) => {
19543
+ if (skippedReasons.has(id)) return;
19544
+ skippedIds.push(id);
19545
+ skippedReasons.set(id, reason);
19546
+ };
19547
+ const inputs = [];
19548
+ for (const id of new Set(memoryIds)) {
19549
+ let record;
19550
+ try {
19551
+ record = await ctx.vaultMemoryCollection.find(id);
19552
+ } catch (err) {
19553
+ log.warn("[memory/topics] vault lookup failed for extraction", err);
19554
+ skip(id, "not-found");
19555
+ continue;
19556
+ }
19557
+ if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
19558
+ skip(id, "excluded");
19559
+ continue;
19560
+ }
19561
+ try {
19562
+ const stored = await vaultMemoryToStored(
19563
+ record,
19564
+ ctx.walletAddress,
19565
+ ctx.signMessage,
19566
+ ctx.embeddedWalletSigner
19567
+ );
19568
+ inputs.push({ id, content: stored.content });
19569
+ } catch (err) {
19570
+ log.warn("[memory/topics] failed to load memory for extraction", err);
19571
+ skip(id, "unreadable");
19572
+ }
19573
+ }
19574
+ const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
19575
+ const toStamp = [];
19576
+ for (const input of inputs) {
19577
+ const entities = entitiesByMemory.get(input.id);
19578
+ if (entities === void 0) {
19579
+ skip(input.id, "llm-unanswered");
19580
+ continue;
19581
+ }
19582
+ try {
19583
+ const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
19584
+ if (linked === null) {
19585
+ skip(input.id, "link-declined");
19586
+ entitiesByMemory.delete(input.id);
19587
+ continue;
19588
+ }
19589
+ } catch (err) {
19590
+ log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
19591
+ skip(input.id, "link-failed");
19592
+ entitiesByMemory.delete(input.id);
19593
+ continue;
19594
+ }
19595
+ toStamp.push(input.id);
19596
+ }
19597
+ const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
19598
+ const stampedSet = new Set(stampedIds);
19599
+ for (const id of toStamp) {
19600
+ if (!stampedSet.has(id)) {
19601
+ skip(id, "stamp-declined");
19602
+ entitiesByMemory.delete(id);
19603
+ }
19604
+ }
19605
+ return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
19606
+ }
19607
+
19608
+ // src/lib/memory/store/local.ts
19609
+ function createLocalMemoryStore(options) {
19610
+ const { database, userId } = options;
19611
+ const entityCtx = {
19612
+ database,
19613
+ entityCollection: database.get("entity"),
19614
+ memoryEntityCollection: database.get("memory_entity"),
19615
+ ...userId !== void 0 && { userId },
19616
+ ...options.allowUnscopedRows !== void 0 && {
19617
+ allowUnscopedRows: options.allowUnscopedRows
19618
+ }
19619
+ };
19620
+ const vaultCtx = {
19621
+ database,
19622
+ vaultMemoryCollection: database.get("memory_vault"),
19623
+ walletAddress: options.walletAddress,
19624
+ signMessage: options.signMessage,
19625
+ embeddedWalletSigner: options.embeddedWalletSigner,
19626
+ ...userId !== void 0 && { userId },
19627
+ ...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
19628
+ // Deletes cascade to memory_entity, so the graph lane never serves a
19629
+ // deleted memory's id.
19630
+ entityCtx
19631
+ };
19632
+ const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
19633
+ const ownedBy = userId !== void 0 ? [import_watermelondb12.Q.where("user_id", userId)] : [];
19634
+ const watchedColumns = [
19635
+ "content",
19636
+ "scope",
19637
+ "updated_at",
19638
+ "fact_type",
19639
+ "event_time_start",
19640
+ "event_time_end",
19641
+ "event_time_kind",
19642
+ "archived_at",
19643
+ "trust_tier",
19644
+ "superseded_by",
19645
+ "visibility",
19646
+ "published_at",
19647
+ "geohash",
19648
+ "topics",
19649
+ "topics_user_managed",
19650
+ "media",
19651
+ "source"
19652
+ ];
19653
+ const embedInBackground = (memory) => {
19654
+ eagerEmbedContent(
19655
+ memory.content,
19656
+ options.embeddingOptions,
19657
+ vaultCache,
19658
+ vaultCtx,
19659
+ memory.uniqueId,
19660
+ memory.updatedAt
19661
+ ).catch((err) => {
19662
+ getLogger().warn("[memory/store] Failed to embed memory:", err);
19663
+ });
19664
+ };
19665
+ return {
19666
+ list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
19667
+ get: (id) => getVaultMemoryOp(vaultCtx, id),
19668
+ listArchived: async () => {
19669
+ 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();
19670
+ if (ids.length === 0) return [];
19671
+ const rows = await getAllVaultMemoriesOp(vaultCtx, { memoryIds: ids, includeArchived: true });
19672
+ return rows.sort((a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0));
19673
+ },
19674
+ memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
19675
+ topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
19676
+ create: async (input) => {
19677
+ const created = await createVaultMemoryOp(vaultCtx, input);
19678
+ if (input.embedding === void 0) embedInBackground(created);
19679
+ return created;
19680
+ },
19681
+ createMany: async (inputs) => {
19682
+ const created = await createVaultMemoriesBatchOp(vaultCtx, inputs);
19683
+ created.forEach((memory, i) => {
19684
+ if (inputs[i].embedding === void 0) embedInBackground(memory);
19685
+ });
19686
+ return created;
19687
+ },
19688
+ update: async (id, patch) => {
19689
+ const reembed = patch.embedding === void 0;
19690
+ const updated = await updateVaultMemoryOp(
19691
+ vaultCtx,
19692
+ id,
19693
+ reembed ? { ...patch, embedding: null } : patch
19694
+ );
19695
+ if (!updated) return null;
19696
+ vaultCache.delete(id);
19697
+ if (reembed) embedInBackground(updated);
19698
+ return updated;
19699
+ },
19700
+ delete: async (id) => {
19701
+ const deleted = await deleteVaultMemoryOp(vaultCtx, id);
19702
+ if (deleted) vaultCache.delete(id);
19703
+ return deleted;
19704
+ },
19705
+ supersede: (id, supersededById) => supersedeVaultMemoryOp(vaultCtx, id, supersededById),
19706
+ archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
19707
+ restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
19708
+ setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
19709
+ addTopics: (memoryId, topics) => database.write(async (writer) => {
19710
+ const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb12.Q.where("id", memoryId), import_watermelondb12.Q.where("is_deleted", false), ...ownedBy).fetchCount();
19711
+ return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
19712
+ }),
19713
+ setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
19714
+ recall: (query, recallOptions) => recall(
19715
+ query,
19716
+ { vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions, vaultCache },
19717
+ { ...recallOptions, types: ["fact"] }
19718
+ ),
19719
+ retain: (content, retainOptions) => retain(
19720
+ content,
19721
+ { vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
19722
+ retainOptions
19723
+ ),
19724
+ subscribe: (onChange, subscribeOptions) => {
19725
+ const afterFirst = () => {
19726
+ let first = true;
19727
+ return () => {
19728
+ if (first) first = false;
19729
+ else onChange();
19730
+ };
19731
+ };
19732
+ const memories = subscribeOptions?.includeDeleted ? vaultCtx.vaultMemoryCollection.query(...ownedBy).observe() : vaultCtx.vaultMemoryCollection.query(import_watermelondb12.Q.where("is_deleted", false), ...ownedBy).observeWithColumns(
19733
+ subscribeOptions?.embeddings ? [...watchedColumns, "embedding", "embedding_model"] : watchedColumns
19734
+ );
19735
+ const subscriptions = [memories.subscribe(afterFirst())];
19736
+ if (subscribeOptions?.topics) {
19737
+ 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)];
19738
+ subscriptions.push(
19739
+ entityCtx.memoryEntityCollection.query(...linksOwnedBy).observe().subscribe(afterFirst())
19740
+ );
19741
+ }
19742
+ return () => subscriptions.forEach((s) => s.unsubscribe());
19743
+ },
19744
+ maintenance: {
19745
+ createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
19746
+ getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
19747
+ extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
19748
+ stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
19749
+ relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
19750
+ backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
19751
+ }
19752
+ };
19753
+ }
19754
+
19359
19755
  // src/lib/memory/synthesizeProfile.ts
19360
19756
  init_internalFlowMarker();
19361
19757
  init_logger();
@@ -19885,202 +20281,6 @@ function normalizeInterests(values) {
19885
20281
  return out.length > 0 ? out : void 0;
19886
20282
  }
19887
20283
 
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
20284
  // src/lib/memory/verifySupport.ts
20085
20285
  init_logger();
20086
20286
  init_redactor();
@@ -20474,7 +20674,7 @@ async function assembleMemoryContext(options) {
20474
20674
  }
20475
20675
 
20476
20676
  // src/lib/memory/durableExtraction.ts
20477
- var import_watermelondb12 = require("@nozbe/watermelondb");
20677
+ var import_watermelondb13 = require("@nozbe/watermelondb");
20478
20678
  var MAX_JOBS_PER_PASS = 3;
20479
20679
  var MAX_ATTEMPTS = 3;
20480
20680
  var MAX_FAILED_SESSIONS = 3;
@@ -20621,7 +20821,7 @@ function createDurableAutoExtractor(options) {
20621
20821
  ...options.retainCtx,
20622
20822
  vaultCtx: {
20623
20823
  ...vault,
20624
- canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("id", import_watermelondb12.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
20824
+ 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
20825
  }
20626
20826
  },
20627
20827
  // The model follows the job's scope, not the mode alive at drain time.
@@ -20763,7 +20963,7 @@ function createDurableAutoExtractor(options) {
20763
20963
  let scheduleAfterSuccess = false;
20764
20964
  try {
20765
20965
  await writes;
20766
- const pending = await jobs.query(import_watermelondb12.Q.where("owner_key", owner), import_watermelondb12.Q.where("message_ids", import_watermelondb12.Q.notEq("[]"))).fetch();
20966
+ const pending = await jobs.query(import_watermelondb13.Q.where("owner_key", owner), import_watermelondb13.Q.where("message_ids", import_watermelondb13.Q.notEq("[]"))).fetch();
20767
20967
  storeFailures = 0;
20768
20968
  let processed = 0;
20769
20969
  for (const job of pending) {
@@ -20779,7 +20979,7 @@ function createDurableAutoExtractor(options) {
20779
20979
  let ids = [];
20780
20980
  let loaded = [];
20781
20981
  try {
20782
- const conversations = await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount();
20982
+ const conversations = await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount();
20783
20983
  if (!conversations) {
20784
20984
  await database.write(() => job.destroyPermanently());
20785
20985
  continue;
@@ -20896,12 +21096,12 @@ function createDurableAutoExtractor(options) {
20896
21096
  const scope = currentScope();
20897
21097
  writes = writes.then(
20898
21098
  () => database.write(async () => {
20899
- const existing = await jobs.query(import_watermelondb12.Q.where("owner_key", owner), import_watermelondb12.Q.where("conversation_id", conversationId)).fetch();
21099
+ const existing = await jobs.query(import_watermelondb13.Q.where("owner_key", owner), import_watermelondb13.Q.where("conversation_id", conversationId)).fetch();
20900
21100
  const job = existing.find(
20901
21101
  (candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
20902
21102
  );
20903
21103
  const positions = new Map(ids.map((id, index) => [id, index]));
20904
- const rows = await storage.messagesCollection.query(import_watermelondb12.Q.where("id", import_watermelondb12.Q.oneOf(ids))).fetch();
21104
+ const rows = await storage.messagesCollection.query(import_watermelondb13.Q.where("id", import_watermelondb13.Q.oneOf(ids))).fetch();
20905
21105
  const sequences = /* @__PURE__ */ new Map();
20906
21106
  for (const row of rows) {
20907
21107
  const sequence = Number(row._getRaw("message_id"));
@@ -23594,13 +23794,13 @@ init_patterns();
23594
23794
  init_redactor();
23595
23795
 
23596
23796
  // src/lib/db/schema.ts
23597
- var import_watermelondb21 = require("@nozbe/watermelondb");
23797
+ var import_watermelondb22 = require("@nozbe/watermelondb");
23598
23798
  var import_migrations2 = require("@nozbe/watermelondb/Schema/migrations");
23599
23799
 
23600
23800
  // src/lib/db/appFiles/models.ts
23601
- var import_watermelondb13 = require("@nozbe/watermelondb");
23801
+ var import_watermelondb14 = require("@nozbe/watermelondb");
23602
23802
  var import_decorators4 = require("@nozbe/watermelondb/decorators");
23603
- var AppFile = class extends import_watermelondb13.Model {
23803
+ var AppFile = class extends import_watermelondb14.Model {
23604
23804
  };
23605
23805
  AppFile.table = "app_files";
23606
23806
  AppFile.associations = {};
@@ -23622,9 +23822,9 @@ __decorateClass([
23622
23822
  ], AppFile.prototype, "updatedAt", 2);
23623
23823
 
23624
23824
  // src/lib/db/conversationMemory/models.ts
23625
- var import_watermelondb14 = require("@nozbe/watermelondb");
23825
+ var import_watermelondb15 = require("@nozbe/watermelondb");
23626
23826
  var import_decorators5 = require("@nozbe/watermelondb/decorators");
23627
- var ConversationMemory = class extends import_watermelondb14.Model {
23827
+ var ConversationMemory = class extends import_watermelondb15.Model {
23628
23828
  };
23629
23829
  ConversationMemory.table = "conversation_memory";
23630
23830
  ConversationMemory.associations = {};
@@ -23643,9 +23843,9 @@ __decorateClass([
23643
23843
  ], ConversationMemory.prototype, "createdAt", 2);
23644
23844
 
23645
23845
  // src/lib/db/entities/models.ts
23646
- var import_watermelondb15 = require("@nozbe/watermelondb");
23846
+ var import_watermelondb16 = require("@nozbe/watermelondb");
23647
23847
  var import_decorators6 = require("@nozbe/watermelondb/decorators");
23648
- var Entity = class extends import_watermelondb15.Model {
23848
+ var Entity = class extends import_watermelondb16.Model {
23649
23849
  };
23650
23850
  Entity.table = "entity";
23651
23851
  __decorateClass([
@@ -23661,7 +23861,7 @@ __decorateClass([
23661
23861
  __decorateClass([
23662
23862
  (0, import_decorators6.date)("updated_at")
23663
23863
  ], Entity.prototype, "updatedAt", 2);
23664
- var MemoryEntity = class extends import_watermelondb15.Model {
23864
+ var MemoryEntity = class extends import_watermelondb16.Model {
23665
23865
  };
23666
23866
  MemoryEntity.table = "memory_entity";
23667
23867
  __decorateClass([
@@ -23679,9 +23879,9 @@ __decorateClass([
23679
23879
  ], MemoryEntity.prototype, "createdAt", 2);
23680
23880
 
23681
23881
  // src/lib/db/project/models.ts
23682
- var import_watermelondb16 = require("@nozbe/watermelondb");
23882
+ var import_watermelondb17 = require("@nozbe/watermelondb");
23683
23883
  var import_decorators7 = require("@nozbe/watermelondb/decorators");
23684
- var Project = class extends import_watermelondb16.Model {
23884
+ var Project = class extends import_watermelondb17.Model {
23685
23885
  };
23686
23886
  Project.table = "projects";
23687
23887
  Project.associations = {
@@ -23704,10 +23904,10 @@ __decorateClass([
23704
23904
  ], Project.prototype, "isDeleted", 2);
23705
23905
 
23706
23906
  // src/lib/db/savedTools/models.ts
23707
- var import_watermelondb17 = require("@nozbe/watermelondb");
23907
+ var import_watermelondb18 = require("@nozbe/watermelondb");
23708
23908
  var import_decorators8 = require("@nozbe/watermelondb/decorators");
23709
23909
  var sanitizeParameters = (raw) => raw ?? {};
23710
- var SavedTool = class extends import_watermelondb17.Model {
23910
+ var SavedTool = class extends import_watermelondb18.Model {
23711
23911
  };
23712
23912
  SavedTool.table = "saved_tools";
23713
23913
  SavedTool.associations = {};
@@ -23741,9 +23941,9 @@ __decorateClass([
23741
23941
  ], SavedTool.prototype, "isDeleted", 2);
23742
23942
 
23743
23943
  // src/lib/db/settings/models.ts
23744
- var import_watermelondb18 = require("@nozbe/watermelondb");
23944
+ var import_watermelondb19 = require("@nozbe/watermelondb");
23745
23945
  var import_decorators9 = require("@nozbe/watermelondb/decorators");
23746
- var ModelPreference = class extends import_watermelondb18.Model {
23946
+ var ModelPreference = class extends import_watermelondb19.Model {
23747
23947
  };
23748
23948
  ModelPreference.table = "modelPreferences";
23749
23949
  __decorateClass([
@@ -23754,9 +23954,9 @@ __decorateClass([
23754
23954
  ], ModelPreference.prototype, "models", 2);
23755
23955
 
23756
23956
  // src/lib/db/userPreferences/models.ts
23757
- var import_watermelondb19 = require("@nozbe/watermelondb");
23957
+ var import_watermelondb20 = require("@nozbe/watermelondb");
23758
23958
  var import_decorators10 = require("@nozbe/watermelondb/decorators");
23759
- var UserPreference = class extends import_watermelondb19.Model {
23959
+ var UserPreference = class extends import_watermelondb20.Model {
23760
23960
  };
23761
23961
  UserPreference.table = "userPreferences";
23762
23962
  __decorateClass([
@@ -23785,9 +23985,9 @@ __decorateClass([
23785
23985
  ], UserPreference.prototype, "updatedAt", 2);
23786
23986
 
23787
23987
  // src/lib/db/vaultFolders/models.ts
23788
- var import_watermelondb20 = require("@nozbe/watermelondb");
23988
+ var import_watermelondb21 = require("@nozbe/watermelondb");
23789
23989
  var import_decorators11 = require("@nozbe/watermelondb/decorators");
23790
- var VaultFolder = class extends import_watermelondb20.Model {
23990
+ var VaultFolder = class extends import_watermelondb21.Model {
23791
23991
  };
23792
23992
  VaultFolder.table = "vault_folders";
23793
23993
  __decorateClass([
@@ -23815,10 +24015,10 @@ __decorateClass([
23815
24015
 
23816
24016
  // src/lib/db/schema.ts
23817
24017
  var SDK_SCHEMA_VERSION = 47;
23818
- var sdkSchema = (0, import_watermelondb21.appSchema)({
24018
+ var sdkSchema = (0, import_watermelondb22.appSchema)({
23819
24019
  version: SDK_SCHEMA_VERSION,
23820
24020
  tables: [
23821
- (0, import_watermelondb21.tableSchema)({
24021
+ (0, import_watermelondb22.tableSchema)({
23822
24022
  name: "memory_extraction_jobs",
23823
24023
  columns: [
23824
24024
  { name: "owner_key", type: "string", isIndexed: true },
@@ -23838,7 +24038,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
23838
24038
  ]
23839
24039
  }),
23840
24040
  // Chat storage tables
23841
- (0, import_watermelondb21.tableSchema)({
24041
+ (0, import_watermelondb22.tableSchema)({
23842
24042
  name: "history",
23843
24043
  columns: [
23844
24044
  { name: "message_id", type: "number" },
@@ -23877,7 +24077,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
23877
24077
  // MessageOrigin — provenance, NOT encrypted (see v44)
23878
24078
  ]
23879
24079
  }),
23880
- (0, import_watermelondb21.tableSchema)({
24080
+ (0, import_watermelondb22.tableSchema)({
23881
24081
  name: "conversations",
23882
24082
  columns: [
23883
24083
  { name: "conversation_id", type: "string", isIndexed: true },
@@ -23899,7 +24099,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
23899
24099
  ]
23900
24100
  }),
23901
24101
  // Project storage table
23902
- (0, import_watermelondb21.tableSchema)({
24102
+ (0, import_watermelondb22.tableSchema)({
23903
24103
  name: "projects",
23904
24104
  columns: [
23905
24105
  { name: "project_id", type: "string", isIndexed: true },
@@ -23910,7 +24110,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
23910
24110
  ]
23911
24111
  }),
23912
24112
  // Settings storage tables (deprecated - use userPreferences)
23913
- (0, import_watermelondb21.tableSchema)({
24113
+ (0, import_watermelondb22.tableSchema)({
23914
24114
  name: "modelPreferences",
23915
24115
  columns: [
23916
24116
  { name: "wallet_address", type: "string", isIndexed: true },
@@ -23918,7 +24118,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
23918
24118
  ]
23919
24119
  }),
23920
24120
  // Unified user preferences storage
23921
- (0, import_watermelondb21.tableSchema)({
24121
+ (0, import_watermelondb22.tableSchema)({
23922
24122
  name: "userPreferences",
23923
24123
  columns: [
23924
24124
  // Identity
@@ -23937,7 +24137,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
23937
24137
  ]
23938
24138
  }),
23939
24139
  // Memory vault storage
23940
- (0, import_watermelondb21.tableSchema)({
24140
+ (0, import_watermelondb22.tableSchema)({
23941
24141
  name: "memory_vault",
23942
24142
  columns: [
23943
24143
  { name: "content", type: "string" },
@@ -24065,7 +24265,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24065
24265
  ]
24066
24266
  }),
24067
24267
  // Entity table — canonical names extracted from auto-extraction (W5).
24068
- (0, import_watermelondb21.tableSchema)({
24268
+ (0, import_watermelondb22.tableSchema)({
24069
24269
  name: "entity",
24070
24270
  columns: [
24071
24271
  { name: "canonical_name", type: "string", isIndexed: true },
@@ -24075,7 +24275,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24075
24275
  ]
24076
24276
  }),
24077
24277
  // Many-to-many join: which memories reference which entities.
24078
- (0, import_watermelondb21.tableSchema)({
24278
+ (0, import_watermelondb22.tableSchema)({
24079
24279
  name: "memory_entity",
24080
24280
  columns: [
24081
24281
  { name: "memory_id", type: "string", isIndexed: true },
@@ -24085,7 +24285,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24085
24285
  ]
24086
24286
  }),
24087
24287
  // Vault folder organization
24088
- (0, import_watermelondb21.tableSchema)({
24288
+ (0, import_watermelondb22.tableSchema)({
24089
24289
  name: "vault_folders",
24090
24290
  columns: [
24091
24291
  { name: "name", type: "string" },
@@ -24098,7 +24298,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24098
24298
  ]
24099
24299
  }),
24100
24300
  // Conversation summary cache for progressive history summarization
24101
- (0, import_watermelondb21.tableSchema)({
24301
+ (0, import_watermelondb22.tableSchema)({
24102
24302
  name: "conversation_summaries",
24103
24303
  columns: [
24104
24304
  { name: "conversation_id", type: "string", isIndexed: true },
@@ -24111,7 +24311,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24111
24311
  ]
24112
24312
  }),
24113
24313
  // Media library storage (images, videos, audio, documents)
24114
- (0, import_watermelondb21.tableSchema)({
24314
+ (0, import_watermelondb22.tableSchema)({
24115
24315
  name: "media",
24116
24316
  columns: [
24117
24317
  // Identity
@@ -24147,7 +24347,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24147
24347
  ]
24148
24348
  }),
24149
24349
  // ── App files ─────────────────────────────────────────────────────────
24150
- (0, import_watermelondb21.tableSchema)({
24350
+ (0, import_watermelondb22.tableSchema)({
24151
24351
  name: "app_files",
24152
24352
  columns: [
24153
24353
  { name: "conversation_id", type: "string", isIndexed: true },
@@ -24158,7 +24358,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24158
24358
  ]
24159
24359
  }),
24160
24360
  // ── Saved tools ──────────────────────────────────────────────────────
24161
- (0, import_watermelondb21.tableSchema)({
24361
+ (0, import_watermelondb22.tableSchema)({
24162
24362
  name: "saved_tools",
24163
24363
  columns: [
24164
24364
  { name: "name", type: "string" },
@@ -24174,7 +24374,7 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
24174
24374
  ]
24175
24375
  }),
24176
24376
  // ── Conversation memories (panel persistence) ────────────────────────
24177
- (0, import_watermelondb21.tableSchema)({
24377
+ (0, import_watermelondb22.tableSchema)({
24178
24378
  name: "conversation_memory",
24179
24379
  columns: [
24180
24380
  { name: "conversation_id", type: "string", isIndexed: true },
@@ -24896,7 +25096,7 @@ var sdkModelClasses = [
24896
25096
  ];
24897
25097
 
24898
25098
  // src/lib/db/manager.ts
24899
- var import_watermelondb22 = require("@nozbe/watermelondb");
25099
+ var import_watermelondb23 = require("@nozbe/watermelondb");
24900
25100
  var DESTRUCTIVE_MIGRATION_VERSION = 8;
24901
25101
  var webPlatformStorage = {
24902
25102
  getItem: (key) => localStorage.getItem(key),
@@ -24977,7 +25177,7 @@ var DatabaseManager = class {
24977
25177
  walletAddress
24978
25178
  });
24979
25179
  const adapter = this.createAdapter(dbName, sdkSchema, sdkMigrations);
24980
- const database = new import_watermelondb22.Database({
25180
+ const database = new import_watermelondb23.Database({
24981
25181
  adapter,
24982
25182
  modelClasses: sdkModelClasses
24983
25183
  });
@@ -25056,7 +25256,7 @@ var DatabaseManager = class {
25056
25256
  };
25057
25257
 
25058
25258
  // src/lib/db/conversationMemory/operations.ts
25059
- var import_watermelondb23 = require("@nozbe/watermelondb");
25259
+ var import_watermelondb24 = require("@nozbe/watermelondb");
25060
25260
  var MAX_PER_CONVERSATION = 200;
25061
25261
  function conversationMemoryToStored(row) {
25062
25262
  return {
@@ -25071,7 +25271,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
25071
25271
  if (!conversationId || items.length === 0) return;
25072
25272
  const now = Date.now();
25073
25273
  await ctx.database.write(async () => {
25074
- const existing = await ctx.conversationMemoryCollection.query(import_watermelondb23.Q.where("conversation_id", conversationId), import_watermelondb23.Q.sortBy("created_at", import_watermelondb23.Q.asc)).fetch();
25274
+ 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
25275
  const seen = new Set(existing.map((r) => r.memoryId));
25076
25276
  const batchSeen = /* @__PURE__ */ new Set();
25077
25277
  const deduped = [];
@@ -25106,20 +25306,20 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
25106
25306
  }
25107
25307
  async function getConversationMemoriesOp(ctx, conversationId) {
25108
25308
  if (!conversationId) return [];
25109
- const rows = await ctx.conversationMemoryCollection.query(import_watermelondb23.Q.where("conversation_id", conversationId), import_watermelondb23.Q.sortBy("created_at", import_watermelondb23.Q.asc)).fetch();
25309
+ 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
25310
  return rows.map(conversationMemoryToStored);
25111
25311
  }
25112
25312
  async function clearConversationMemoriesOp(ctx, conversationId) {
25113
25313
  if (!conversationId) return;
25114
25314
  await ctx.database.write(async () => {
25115
- const rows = await ctx.conversationMemoryCollection.query(import_watermelondb23.Q.where("conversation_id", conversationId)).fetch();
25315
+ const rows = await ctx.conversationMemoryCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId)).fetch();
25116
25316
  if (rows.length === 0) return;
25117
25317
  await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
25118
25318
  });
25119
25319
  }
25120
25320
 
25121
25321
  // src/lib/db/vaultFolders/operations.ts
25122
- var import_watermelondb24 = require("@nozbe/watermelondb");
25322
+ var import_watermelondb25 = require("@nozbe/watermelondb");
25123
25323
  function folderToStored(folder) {
25124
25324
  return {
25125
25325
  uniqueId: folder.id,
@@ -25144,7 +25344,7 @@ async function createVaultFolderOp(ctx, opts) {
25144
25344
  return folderToStored(created);
25145
25345
  }
25146
25346
  async function getAllVaultFoldersOp(ctx) {
25147
- const results = await ctx.vaultFolderCollection.query(import_watermelondb24.Q.where("is_deleted", false), import_watermelondb24.Q.sortBy("created_at", import_watermelondb24.Q.desc)).fetch();
25347
+ 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
25348
  return results.map(folderToStored);
25149
25349
  }
25150
25350
  async function updateVaultFolderOp(ctx, id, opts) {
@@ -25153,7 +25353,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
25153
25353
  if (record.isDeleted) return null;
25154
25354
  const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
25155
25355
  const updated = await ctx.database.write(async () => {
25156
- const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb24.Q.where("folder_id", id), import_watermelondb24.Q.where("is_deleted", false)).fetch() : [];
25356
+ const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb25.Q.where("folder_id", id), import_watermelondb25.Q.where("is_deleted", false)).fetch() : [];
25157
25357
  const updates = [];
25158
25358
  updates.push(
25159
25359
  record.prepareUpdate((r) => {
@@ -25181,7 +25381,7 @@ async function deleteVaultFolderOp(ctx, id) {
25181
25381
  const record = await ctx.vaultFolderCollection.find(id);
25182
25382
  if (record.isDeleted) return false;
25183
25383
  await ctx.database.write(async () => {
25184
- const memories = await ctx.vaultMemoryCollection.query(import_watermelondb24.Q.where("folder_id", id), import_watermelondb24.Q.where("is_deleted", false)).fetch();
25384
+ const memories = await ctx.vaultMemoryCollection.query(import_watermelondb25.Q.where("folder_id", id), import_watermelondb25.Q.where("is_deleted", false)).fetch();
25185
25385
  const preparedMemories = memories.map(
25186
25386
  (memory) => memory.prepareUpdate((r) => {
25187
25387
  r._setRaw("folder_id", null);
@@ -25250,7 +25450,7 @@ async function updateVaultFolderContextOp(ctx, id, context) {
25250
25450
  }
25251
25451
  }
25252
25452
  async function getVaultFolderMemoryCountOp(ctx, folderId) {
25253
- return await ctx.vaultMemoryCollection.query(import_watermelondb24.Q.where("folder_id", folderId), import_watermelondb24.Q.where("is_deleted", false)).fetchCount();
25453
+ return await ctx.vaultMemoryCollection.query(import_watermelondb25.Q.where("folder_id", folderId), import_watermelondb25.Q.where("is_deleted", false)).fetchCount();
25254
25454
  }
25255
25455
 
25256
25456
  // src/lib/db/vaultFolders/defaults.ts
@@ -26288,6 +26488,7 @@ function createNotionProxyTools(callMcp) {
26288
26488
  createDurableAutoExtractor,
26289
26489
  createLlmDecayClassifier,
26290
26490
  createLlmNeighborRefiner,
26491
+ createLocalMemoryStore,
26291
26492
  createMemoryEngineTool,
26292
26493
  createMemoryVaultSearchTool,
26293
26494
  createMemoryVaultTool,