@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.
@@ -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
- messages = [...messages, ...await redactBatch(extra)];
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).catch(
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 import_watermelondb12 = require("@nozbe/watermelondb");
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(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
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(import_watermelondb12.Q.where("owner_key", owner), import_watermelondb12.Q.where("message_ids", import_watermelondb12.Q.notEq("[]"))).fetch();
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(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount();
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(import_watermelondb12.Q.where("owner_key", owner), import_watermelondb12.Q.where("conversation_id", conversationId)).fetch();
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(import_watermelondb12.Q.where("id", import_watermelondb12.Q.oneOf(ids))).fetch();
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 import_watermelondb21 = require("@nozbe/watermelondb");
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 import_watermelondb13 = require("@nozbe/watermelondb");
23807
+ var import_watermelondb14 = require("@nozbe/watermelondb");
23602
23808
  var import_decorators4 = require("@nozbe/watermelondb/decorators");
23603
- var AppFile = class extends import_watermelondb13.Model {
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 import_watermelondb14 = require("@nozbe/watermelondb");
23831
+ var import_watermelondb15 = require("@nozbe/watermelondb");
23626
23832
  var import_decorators5 = require("@nozbe/watermelondb/decorators");
23627
- var ConversationMemory = class extends import_watermelondb14.Model {
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 import_watermelondb15 = require("@nozbe/watermelondb");
23852
+ var import_watermelondb16 = require("@nozbe/watermelondb");
23647
23853
  var import_decorators6 = require("@nozbe/watermelondb/decorators");
23648
- var Entity = class extends import_watermelondb15.Model {
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 import_watermelondb15.Model {
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 import_watermelondb16 = require("@nozbe/watermelondb");
23888
+ var import_watermelondb17 = require("@nozbe/watermelondb");
23683
23889
  var import_decorators7 = require("@nozbe/watermelondb/decorators");
23684
- var Project = class extends import_watermelondb16.Model {
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 import_watermelondb17 = require("@nozbe/watermelondb");
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 import_watermelondb17.Model {
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 import_watermelondb18 = require("@nozbe/watermelondb");
23950
+ var import_watermelondb19 = require("@nozbe/watermelondb");
23745
23951
  var import_decorators9 = require("@nozbe/watermelondb/decorators");
23746
- var ModelPreference = class extends import_watermelondb18.Model {
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 import_watermelondb19 = require("@nozbe/watermelondb");
23963
+ var import_watermelondb20 = require("@nozbe/watermelondb");
23758
23964
  var import_decorators10 = require("@nozbe/watermelondb/decorators");
23759
- var UserPreference = class extends import_watermelondb19.Model {
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 import_watermelondb20 = require("@nozbe/watermelondb");
23994
+ var import_watermelondb21 = require("@nozbe/watermelondb");
23789
23995
  var import_decorators11 = require("@nozbe/watermelondb/decorators");
23790
- var VaultFolder = class extends import_watermelondb20.Model {
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, import_watermelondb21.appSchema)({
24024
+ var sdkSchema = (0, import_watermelondb22.appSchema)({
23819
24025
  version: SDK_SCHEMA_VERSION,
23820
24026
  tables: [
23821
- (0, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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, import_watermelondb21.tableSchema)({
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 import_watermelondb22 = require("@nozbe/watermelondb");
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 import_watermelondb22.Database({
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 import_watermelondb23 = require("@nozbe/watermelondb");
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(import_watermelondb23.Q.where("conversation_id", conversationId), import_watermelondb23.Q.sortBy("created_at", import_watermelondb23.Q.asc)).fetch();
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(import_watermelondb23.Q.where("conversation_id", conversationId), import_watermelondb23.Q.sortBy("created_at", import_watermelondb23.Q.asc)).fetch();
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(import_watermelondb23.Q.where("conversation_id", conversationId)).fetch();
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 import_watermelondb24 = require("@nozbe/watermelondb");
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(import_watermelondb24.Q.where("is_deleted", false), import_watermelondb24.Q.sortBy("created_at", import_watermelondb24.Q.desc)).fetch();
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(import_watermelondb24.Q.where("folder_id", id), import_watermelondb24.Q.where("is_deleted", false)).fetch() : [];
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(import_watermelondb24.Q.where("folder_id", id), import_watermelondb24.Q.where("is_deleted", false)).fetch();
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(import_watermelondb24.Q.where("folder_id", folderId), import_watermelondb24.Q.where("is_deleted", false)).fetchCount();
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,