@anuma/sdk 6.21.0 → 6.22.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.
@@ -11,6 +11,7 @@ import {
11
11
  ENTITY_FANOUT,
12
12
  ENTITY_KINDS,
13
13
  EncryptionKeyMissingError,
14
+ ExtractionJob,
14
15
  LRUCache,
15
16
  MAX_HOPS,
16
17
  NODE_BUDGET,
@@ -65,6 +66,7 @@ import {
65
66
  deleteAllVaultMemoriesForUserOp,
66
67
  deleteApiV1WalletsBindingByAddress,
67
68
  deleteConversationOp,
69
+ deleteMessageOp,
68
70
  deleteVaultMemoryOp,
69
71
  eagerEmbedContent,
70
72
  embedAllMessages,
@@ -179,14 +181,14 @@ import {
179
181
  updateVaultMemoryOp,
180
182
  useEncryption,
181
183
  vaultMemoryToStored
182
- } from "./chunk-JRVAUZHM.mjs";
184
+ } from "./chunk-K4N52PSK.mjs";
183
185
  import {
184
186
  PiiRedactor,
185
187
  createStreamingDeAnonymizer,
186
188
  isPiiRedactor,
187
189
  notifyConsolidationFallback,
188
190
  resolvePiiRedactor
189
- } from "./chunk-AVYB5IXC.mjs";
191
+ } from "./chunk-GPLMMMZN.mjs";
190
192
  import {
191
193
  INTERNAL_FLOW_MARKER,
192
194
  callPortalJsonCompletion,
@@ -202,7 +204,7 @@ import {
202
204
  taskTypeHeader,
203
205
  validateEndpointOverride,
204
206
  withInternalFlowMarker
205
- } from "./chunk-WUG6GTHO.mjs";
207
+ } from "./chunk-MHZB6KIX.mjs";
206
208
  import {
207
209
  BASE_URL,
208
210
  MCP_R2_DOMAIN,
@@ -6959,7 +6961,8 @@ function classifyDecay(m, now, policy) {
6959
6961
  if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
6960
6962
  if (m.eventTimeEnd >= now) return "keep";
6961
6963
  }
6962
- if (now - m.updatedAt > ttlForType(m.factType, resolved)) return "archive";
6964
+ const observedAt = Number.isFinite(m.lastObservedAt) ? m.lastObservedAt : m.updatedAt;
6965
+ if (now - Math.max(m.updatedAt, observedAt) > ttlForType(m.factType, resolved)) return "archive";
6963
6966
  return "keep";
6964
6967
  }
6965
6968
 
@@ -7525,6 +7528,7 @@ async function retain(content, ctx, options = {}) {
7525
7528
  const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
7526
7529
  content: existing.content,
7527
7530
  proofCountIncrement: 1,
7531
+ observationSourceIds: options.sourceChunkIds,
7528
7532
  sourceChunkIds: mergedSourceIds,
7529
7533
  // resurrect encodes the decay gate: ACTIVE target → { preserveUpdatedAt:
7530
7534
  // true } (main's normal re-observation path — bump proof_count without
@@ -7731,7 +7735,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7731
7735
  content: m.content,
7732
7736
  similarity: m.similarity
7733
7737
  }));
7734
- const { consolidateMemory: doConsolidate } = await import("./consolidate-URHGJT7I.mjs");
7738
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-XKS6IZFC.mjs");
7735
7739
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
7736
7740
  if (decision.action === "create") return decision.fallbackReason ? null : { create: true };
7737
7741
  if (decision.action === "supersede" && decision.content) {
@@ -7768,6 +7772,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7768
7772
  const updated = await updateVaultMemoryOp(ctx.vaultCtx, decision.targetId, {
7769
7773
  content: existing.content,
7770
7774
  proofCountIncrement: 1,
7775
+ observationSourceIds: options.sourceChunkIds,
7771
7776
  sourceChunkIds: mergedSourceIds,
7772
7777
  // ACTIVE target → { preserveUpdatedAt: true } (main's normal re-observation
7773
7778
  // path); ARCHIVED (non-superseded, non-deleted) → { restore: true } and no
@@ -7817,6 +7822,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7817
7822
  const updated = await updateVaultMemoryOp(ctx.vaultCtx, decision.targetId, {
7818
7823
  content: decision.content,
7819
7824
  proofCountIncrement: 1,
7825
+ observationSourceIds: options.sourceChunkIds,
7820
7826
  sourceChunkIds: mergedSourceIds,
7821
7827
  embedding: JSON.stringify(newEmbedding),
7822
7828
  embeddingModel: consolidatedModel,
@@ -8453,7 +8459,7 @@ function createAutoExtractor(options) {
8453
8459
  onQuarantined: (info) => options.onMemoryQuarantined?.({ ...info, conversationId })
8454
8460
  }
8455
8461
  });
8456
- if (outcome !== "empty-after-retry") {
8462
+ if (outcome !== "empty-after-retry" && failedCount === 0) {
8457
8463
  const advancedTo = window2[window2.length - 1].id;
8458
8464
  stateFor(conversationId).watermark = advancedTo;
8459
8465
  persistCursor(conversationId, messages, advancedTo, contiguous);
@@ -8608,6 +8614,7 @@ function toDecayInput(c) {
8608
8614
  eventTimeEnd: c.eventTimeEnd,
8609
8615
  eventTimeKind: c.eventTimeKind,
8610
8616
  updatedAt: c.updatedAt,
8617
+ lastObservedAt: c.lastObservedAt,
8611
8618
  archivedAt: c.archivedAt,
8612
8619
  source: c.source,
8613
8620
  trustTier: c.trustTier
@@ -8689,7 +8696,8 @@ function createDecaySweeper(options) {
8689
8696
  for (const c of toArchive) {
8690
8697
  const ok = await archiveVaultMemoryOp(vaultCtx, c.uniqueId, {
8691
8698
  now,
8692
- expectedUpdatedAt: c.updatedAt
8699
+ expectedUpdatedAt: c.updatedAt,
8700
+ expectedLastObservedAt: c.lastObservedAt ?? null
8693
8701
  });
8694
8702
  if (ok) archived++;
8695
8703
  }
@@ -8934,6 +8942,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
8934
8942
  budget: defaultBudget,
8935
8943
  ...toolOptions?.minScore !== void 0 && { minScore: toolOptions.minScore },
8936
8944
  ...toolOptions?.scopes && { scopes: toolOptions.scopes },
8945
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
8937
8946
  ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId },
8938
8947
  ...toolOptions?.excludeConversationId && {
8939
8948
  excludeConversationId: toolOptions.excludeConversationId
@@ -9338,13 +9347,25 @@ async function synthesizeProfile(ctx, options = {}) {
9338
9347
  watermark,
9339
9348
  options.reviewedMemoryIds
9340
9349
  );
9350
+ const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
9351
+ const fallbackPriors = /* @__PURE__ */ new Map();
9352
+ if (previous) {
9353
+ for (const section of previous.sections) {
9354
+ if (section.sourceMemoryIds.length > 0 && section.sourceMemoryIds.every((id) => {
9355
+ const memory = memoriesById.get(id);
9356
+ return memory && !memory.isDeleted && !memory.supersededBy && scopes.includes(memory.scope) && (options.reviewedMemoryIds === void 0 || options.reviewedMemoryIds.includes(id)) && changeTime(memory) <= previous.vaultWatermark;
9357
+ })) {
9358
+ fallbackPriors.set(section.key, section);
9359
+ }
9360
+ }
9361
+ }
9341
9362
  const settled = await Promise.allSettled(
9342
9363
  facets.map(async (facet) => {
9343
9364
  const prior = previous?.sections.find((s) => s.key === facet.key);
9344
9365
  if (prior && !staleKeys.has(facet.key)) {
9345
9366
  return prior;
9346
9367
  }
9347
- return synthesizeFacet(facet, ctx, options, prior);
9368
+ return synthesizeFacet(facet, ctx, options, fallbackPriors.get(facet.key));
9348
9369
  })
9349
9370
  );
9350
9371
  const sections = settled.map((r, i) => {
@@ -9357,10 +9378,7 @@ async function synthesizeProfile(ctx, options = {}) {
9357
9378
  error: r.reason instanceof Error ? r.reason.message : String(r.reason)
9358
9379
  }
9359
9380
  );
9360
- return fallbackSection(
9361
- facet,
9362
- previous?.sections.find((s) => s.key === facet.key)
9363
- );
9381
+ return fallbackSection(facet, fallbackPriors.get(facet.key));
9364
9382
  });
9365
9383
  return {
9366
9384
  version: PROFILE_DOC_VERSION,
@@ -9548,7 +9566,7 @@ async function synthesizeFacet(facet, ctx, options, prior) {
9548
9566
  const { text: text12, legitimateEmpty } = extractFacetText(result.structuredOutput);
9549
9567
  if (!text12 && !legitimateEmpty && !noEvidence) {
9550
9568
  getLogger().warn(
9551
- "[memory/synthesizeProfile] facet synthesis returned degraded-empty; keeping prior section",
9569
+ "[memory/synthesizeProfile] facet synthesis returned degraded-empty; using fallback section",
9552
9570
  { facet: facet.key, recalledCount: result.basedOn.memoryIds.length }
9553
9571
  );
9554
9572
  return fallbackSection(facet, prior);
@@ -10114,6 +10132,462 @@ function createMessageSourceResolver(ctx) {
10114
10132
  };
10115
10133
  }
10116
10134
 
10135
+ // src/lib/memory/context.ts
10136
+ function shouldRecallMemory(query) {
10137
+ const normalized = query.trim().toLowerCase().replace(/[.!?。!?¡¿]+$/u, "").replace(/^[¡¿]+/u, "");
10138
+ return normalized.length > 0 && !/^(hi|hi there|hello|hey|yes|no|yep|nope|sure|k|ok|okay|thanks|thank you|thank you very much|thanks a lot|cool|great|got it|sounds good|hola|buenos días|buenas|sí|si|gracias|muchas gracias|vale|bonjour|salut|oui|non|merci|merci beaucoup|d'accord|hallo|guten tag|ja|nein|danke|danke schön|alles klar|olá|obrigado|obrigada|ciao|grazie|sì|你好|谢谢|好的|こんにちは|ありがとう|안녕하세요|감사합니다)$/u.test(
10139
+ normalized
10140
+ );
10141
+ }
10142
+ async function assembleMemoryContext(options) {
10143
+ const { query, recall: recall2, loadFacts, loadSessionRefs } = options;
10144
+ const memoryIds = options.memoryIds ?? options.recallOptions?.memoryIds;
10145
+ const ranked = shouldRecallMemory(query);
10146
+ const degraded = [];
10147
+ const guard = async (lane, run, fallback) => {
10148
+ try {
10149
+ return await run();
10150
+ } catch (error) {
10151
+ degraded.push(lane);
10152
+ try {
10153
+ options.onDegraded?.(lane, error);
10154
+ } catch {
10155
+ }
10156
+ return fallback;
10157
+ }
10158
+ };
10159
+ const scoped = memoryIds !== void 0 || options.recallOptions?.scopes !== void 0 || options.recallOptions?.folderId !== void 0;
10160
+ const allowed = memoryIds !== void 0 ? new Set(memoryIds) : void 0;
10161
+ const filters = {
10162
+ ...options.recallOptions?.scopes && { scopes: options.recallOptions.scopes },
10163
+ ...options.recallOptions?.folderId !== void 0 && {
10164
+ folderId: options.recallOptions.folderId
10165
+ }
10166
+ };
10167
+ const active = (m) => !m.isDeleted && !m.archivedAt && !m.supersededBy && m.trustTier !== "quarantined" && (!allowed || allowed.has(m.uniqueId));
10168
+ const asItem = (m, lane, score = 1) => ({
10169
+ id: m.uniqueId,
10170
+ content: m.content,
10171
+ score,
10172
+ lane,
10173
+ sourceIds: m.sourceChunkIds ?? []
10174
+ });
10175
+ const empty = {
10176
+ memories: [],
10177
+ usedBudget: options.recallOptions?.budget ?? "low",
10178
+ reranked: false,
10179
+ candidateCount: 0
10180
+ };
10181
+ const [facts, episodes, profile, session] = await Promise.all([
10182
+ ranked ? guard(
10183
+ "fact",
10184
+ () => recall2(query, { ...options.recallOptions, types: ["fact"], limit: 20, memoryIds }),
10185
+ empty
10186
+ ) : empty,
10187
+ ranked && !scoped && options.includeEpisodes !== false ? guard(
10188
+ "episode",
10189
+ () => recall2(query, {
10190
+ ...options.recallOptions,
10191
+ types: ["chunk"],
10192
+ limit: 4,
10193
+ minScore: 0.5,
10194
+ onDiagnostics: void 0
10195
+ }),
10196
+ empty
10197
+ ) : empty,
10198
+ loadFacts ? guard(
10199
+ "profile",
10200
+ async () => {
10201
+ const stable = await loadFacts({
10202
+ ...filters,
10203
+ memoryIds,
10204
+ factTypes: ["identity", "preference", "constraint", "relationship"],
10205
+ limit: 8
10206
+ });
10207
+ const dynamic = await loadFacts({
10208
+ ...filters,
10209
+ memoryIds,
10210
+ factTypes: ["ongoing_context", "plan"],
10211
+ limit: 4
10212
+ });
10213
+ return [...stable, ...dynamic].filter(active).map((m) => asItem(m, "profile"));
10214
+ },
10215
+ []
10216
+ ) : [],
10217
+ loadFacts && loadSessionRefs ? guard(
10218
+ "session",
10219
+ async () => {
10220
+ const refs = (await loadSessionRefs()).filter((r) => !allowed || allowed.has(r.memoryId)).sort((a, b) => b.score - a.score).slice(0, 10);
10221
+ if (!refs.length) return [];
10222
+ const rows = await loadFacts({ ...filters, memoryIds: refs.map((r) => r.memoryId) });
10223
+ const byId = new Map(rows.filter(active).map((m) => [m.uniqueId, m]));
10224
+ return refs.flatMap((ref) => {
10225
+ const m = byId.get(ref.memoryId);
10226
+ return m ? [asItem(m, "session", ref.score)] : [];
10227
+ });
10228
+ },
10229
+ []
10230
+ ) : []
10231
+ ]);
10232
+ const toItems = (result, lane) => result.memories.filter((m) => !allowed || allowed.has(m.id)).map((m) => ({
10233
+ id: m.id,
10234
+ content: m.content,
10235
+ score: m.score,
10236
+ lane,
10237
+ ...lane === "fact" && { recalled: true },
10238
+ sourceIds: m.sourceChunkIds ?? (m.messageId ? [m.messageId] : [])
10239
+ }));
10240
+ const recalledFacts = toItems(facts, "fact");
10241
+ const recalledScores = /* @__PURE__ */ new Map();
10242
+ const recalledContentScores = /* @__PURE__ */ new Map();
10243
+ for (const item of recalledFacts) {
10244
+ recalledScores.set(item.id, Math.max(recalledScores.get(item.id) ?? -Infinity, item.score));
10245
+ const content = item.content.trim();
10246
+ recalledContentScores.set(
10247
+ content,
10248
+ Math.max(recalledContentScores.get(content) ?? -Infinity, item.score)
10249
+ );
10250
+ }
10251
+ const rankedProfile = profile.map((item) => {
10252
+ const score = Math.max(
10253
+ recalledScores.get(item.id) ?? -Infinity,
10254
+ recalledContentScores.get(item.content.trim()) ?? -Infinity
10255
+ );
10256
+ return score === -Infinity ? item : { ...item, score, recalled: true };
10257
+ });
10258
+ const lanes = [
10259
+ [rankedProfile, 2e3],
10260
+ [recalledFacts, 6e3],
10261
+ [toItems(episodes, "episode"), 3e3],
10262
+ [session, 1e3]
10263
+ ];
10264
+ const items = [];
10265
+ const seenIds = /* @__PURE__ */ new Set();
10266
+ const seenContent = /* @__PURE__ */ new Set();
10267
+ let remaining = Math.max(0, options.maxChars ?? 12e3);
10268
+ let truncated = false;
10269
+ for (const [candidates, laneBudget] of lanes) {
10270
+ let laneRemaining = Math.min(laneBudget, remaining);
10271
+ for (const item of candidates) {
10272
+ const content = item.content?.trim();
10273
+ const key = `${item.lane === "episode" ? "episode" : "fact"}:${item.id}`;
10274
+ if (!content || seenIds.has(key) || seenContent.has(content)) continue;
10275
+ if (content.length > laneRemaining) {
10276
+ truncated = true;
10277
+ continue;
10278
+ }
10279
+ items.push({ ...item, content });
10280
+ seenIds.add(key);
10281
+ seenContent.add(content);
10282
+ remaining -= content.length;
10283
+ laneRemaining -= content.length;
10284
+ }
10285
+ }
10286
+ return { items, ranked, rankedCount: recalledFacts.length, degraded, truncated };
10287
+ }
10288
+
10289
+ // src/lib/memory/durableExtraction.ts
10290
+ import { Q as Q5 } from "@nozbe/watermelondb";
10291
+ var MAX_JOBS_PER_PASS = 3;
10292
+ var MAX_ATTEMPTS = 3;
10293
+ function idsOf(job) {
10294
+ return JSON.parse(String(job._getRaw("message_ids")));
10295
+ }
10296
+ function seqOf(job) {
10297
+ const raw = job._getRaw("watermark_seq");
10298
+ return typeof raw === "number" && raw > 0 ? raw : void 0;
10299
+ }
10300
+ function createDurableAutoExtractor(options) {
10301
+ const vault = options.retainCtx.vaultCtx;
10302
+ const database = vault.database;
10303
+ const owner = vault.userId ?? vault.walletAddress;
10304
+ if (!owner) throw new Error("Durable extraction requires a user or wallet owner");
10305
+ const jobs = database.get(ExtractionJob.table);
10306
+ const storage = {
10307
+ database,
10308
+ messagesCollection: database.get("history"),
10309
+ conversationsCollection: database.get("conversations"),
10310
+ walletAddress: vault.walletAddress,
10311
+ signMessage: vault.signMessage,
10312
+ embeddedWalletSigner: vault.embeddedWalletSigner
10313
+ };
10314
+ const folderId = options.folderId ?? null;
10315
+ let disposed = false;
10316
+ let running = false;
10317
+ let wakeRequested = false;
10318
+ let timer;
10319
+ let writes = Promise.resolve();
10320
+ let storeFailures = 0;
10321
+ const attempts = /* @__PURE__ */ new Map();
10322
+ const reportError = (error, conversationId) => {
10323
+ try {
10324
+ options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
10325
+ } catch {
10326
+ }
10327
+ };
10328
+ const currentScope = () => {
10329
+ try {
10330
+ const value = typeof options.scope === "function" ? options.scope() : options.scope;
10331
+ return value ?? "private";
10332
+ } catch (error) {
10333
+ reportError(error);
10334
+ return "private";
10335
+ }
10336
+ };
10337
+ function schedule(delay) {
10338
+ if (disposed) return;
10339
+ if (running || timer !== void 0) {
10340
+ if (running) wakeRequested = true;
10341
+ return;
10342
+ }
10343
+ timer = setTimeout(() => {
10344
+ timer = void 0;
10345
+ void drain();
10346
+ }, delay);
10347
+ }
10348
+ async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
10349
+ let watchdog;
10350
+ try {
10351
+ return await Promise.race([
10352
+ new Promise((resolve, reject) => {
10353
+ const worker = createAutoExtractor({
10354
+ ...options,
10355
+ retainCtx: {
10356
+ ...options.retainCtx,
10357
+ vaultCtx: {
10358
+ ...vault,
10359
+ canWrite: async () => !disposed && await storage.conversationsCollection.query(Q5.where("conversation_id", conversationId), Q5.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q5.where("conversation_id", conversationId), Q5.where("id", Q5.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
10360
+ }
10361
+ },
10362
+ // Never publish a private queued observation after a mode flip.
10363
+ scope: jobScope,
10364
+ folderId: jobFolderId,
10365
+ cursorStore: void 0,
10366
+ windowSize: 20,
10367
+ maxWindowSize: 20,
10368
+ onTurnComplete: resolve,
10369
+ onError: reject
10370
+ });
10371
+ worker.processTurn(messages, conversationId);
10372
+ worker.dispose();
10373
+ }),
10374
+ new Promise((_resolve, reject) => {
10375
+ watchdog = setTimeout(
10376
+ () => reject(new Error("Extraction did not settle in time; retained for retry")),
10377
+ options.batchTimeoutMs ?? 18e4
10378
+ );
10379
+ })
10380
+ ]);
10381
+ } finally {
10382
+ if (watchdog !== void 0) clearTimeout(watchdog);
10383
+ }
10384
+ }
10385
+ async function drain() {
10386
+ if (disposed || running) return;
10387
+ running = true;
10388
+ wakeRequested = false;
10389
+ let retry = false;
10390
+ let scheduleAfterSuccess = false;
10391
+ try {
10392
+ await writes;
10393
+ const pending = await jobs.query(Q5.where("owner_key", owner), Q5.where("message_ids", Q5.notEq("[]"))).fetch();
10394
+ storeFailures = 0;
10395
+ let processed = 0;
10396
+ for (const job of pending) {
10397
+ if (disposed) break;
10398
+ const attempted = attempts.get(job.id) ?? 0;
10399
+ if (attempted >= MAX_ATTEMPTS) continue;
10400
+ if (processed >= MAX_JOBS_PER_PASS) {
10401
+ scheduleAfterSuccess = true;
10402
+ break;
10403
+ }
10404
+ processed++;
10405
+ const conversationId = String(job._getRaw("conversation_id"));
10406
+ try {
10407
+ const conversations = await storage.conversationsCollection.query(Q5.where("conversation_id", conversationId), Q5.where("is_deleted", false)).fetchCount();
10408
+ if (!conversations) {
10409
+ await database.write(() => job.destroyPermanently());
10410
+ continue;
10411
+ }
10412
+ const ids = idsOf(job).slice(0, 20);
10413
+ const loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
10414
+ const missing = ids.filter((_id, index) => loaded[index] === null);
10415
+ if (missing.length) {
10416
+ if (attempted < MAX_ATTEMPTS - 1)
10417
+ throw new Error("Source messages not yet available; retained for retry");
10418
+ const dropped = new Set(missing);
10419
+ await database.write(
10420
+ () => job.update(
10421
+ (r) => r._setRaw(
10422
+ "message_ids",
10423
+ JSON.stringify(idsOf(job).filter((id) => !dropped.has(id)))
10424
+ )
10425
+ )
10426
+ );
10427
+ attempts.delete(job.id);
10428
+ scheduleAfterSuccess = true;
10429
+ reportError(
10430
+ new Error(
10431
+ `Dropped ${missing.length} unresolvable source id(s) to unblock extraction`
10432
+ ),
10433
+ conversationId
10434
+ );
10435
+ continue;
10436
+ }
10437
+ if (loaded.some(
10438
+ (message) => message && (message.decryptionStatus || isEncrypted(message.content))
10439
+ )) {
10440
+ throw new Error("Source messages are locked; retained for retry");
10441
+ }
10442
+ const messages = loaded.flatMap(
10443
+ (m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
10444
+ );
10445
+ let success = messages.length === 0;
10446
+ if (messages.length) {
10447
+ const result = await extractBatch(
10448
+ messages,
10449
+ conversationId,
10450
+ ids,
10451
+ currentScope() === "private" ? "private" : String(job._getRaw("scope")),
10452
+ job._getRaw("folder_id") ?? null
10453
+ );
10454
+ success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
10455
+ options.onTurnComplete?.(result);
10456
+ }
10457
+ if (!success) throw new Error("Extraction batch incomplete; retained for retry");
10458
+ attempts.delete(job.id);
10459
+ const sequences = /* @__PURE__ */ new Map();
10460
+ for (const message of loaded)
10461
+ if (message && message.messageId > 0)
10462
+ sequences.set(message.uniqueId, message.messageId);
10463
+ await database.write(async () => {
10464
+ const current = idsOf(job);
10465
+ const acknowledged = ids.filter((id) => current.includes(id));
10466
+ if (!acknowledged.length) return;
10467
+ const done = new Set(acknowledged);
10468
+ const remaining = current.filter((id) => !done.has(id));
10469
+ if (remaining.length) {
10470
+ await job.update(
10471
+ (r) => r._setRaw("message_ids", JSON.stringify([...acknowledged.slice(-2), ...remaining]))
10472
+ );
10473
+ } else await job.update((r) => r._setRaw("message_ids", "[]"));
10474
+ const newest = acknowledged[acknowledged.length - 1];
10475
+ await job.update((r) => {
10476
+ r._setRaw("watermark", newest);
10477
+ const sequence = sequences.get(newest);
10478
+ if (sequence !== void 0) {
10479
+ const prior = seqOf(job);
10480
+ r._setRaw(
10481
+ "watermark_seq",
10482
+ prior === void 0 ? sequence : Math.max(prior, sequence)
10483
+ );
10484
+ }
10485
+ });
10486
+ });
10487
+ scheduleAfterSuccess = true;
10488
+ } catch (error) {
10489
+ attempts.set(job.id, attempted + 1);
10490
+ retry = true;
10491
+ reportError(error, conversationId);
10492
+ }
10493
+ }
10494
+ } catch (error) {
10495
+ retry = ++storeFailures < 3;
10496
+ reportError(error);
10497
+ } finally {
10498
+ running = false;
10499
+ const woken = wakeRequested;
10500
+ wakeRequested = false;
10501
+ if (retry || scheduleAfterSuccess || woken)
10502
+ schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
10503
+ }
10504
+ }
10505
+ schedule(0);
10506
+ return {
10507
+ processTurn(messages, conversationId) {
10508
+ if (disposed || !conversationId || !messages.length) return false;
10509
+ const ids = messages.map((m) => m.id);
10510
+ const scope = currentScope();
10511
+ writes = writes.then(
10512
+ () => database.write(async () => {
10513
+ const existing = await jobs.query(Q5.where("owner_key", owner), Q5.where("conversation_id", conversationId)).fetch();
10514
+ const job = existing.find(
10515
+ (candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
10516
+ );
10517
+ const positions = new Map(ids.map((id, index) => [id, index]));
10518
+ const rows = await storage.messagesCollection.query(Q5.where("id", Q5.oneOf(ids))).fetch();
10519
+ const sequences = /* @__PURE__ */ new Map();
10520
+ for (const row of rows) {
10521
+ const sequence = Number(row._getRaw("message_id"));
10522
+ if (Number.isFinite(sequence) && sequence > 0) sequences.set(row.id, sequence);
10523
+ }
10524
+ let boundary = -1;
10525
+ let observedSeq = 0;
10526
+ const foreignSources = /* @__PURE__ */ new Set();
10527
+ for (const prior of existing) {
10528
+ const sources = [...idsOf(prior), String(prior._getRaw("watermark") ?? "")];
10529
+ for (const id of sources) {
10530
+ boundary = Math.max(boundary, positions.get(id) ?? -1);
10531
+ if (prior !== job) foreignSources.add(id);
10532
+ }
10533
+ observedSeq = Math.max(observedSeq, seqOf(prior) ?? 0);
10534
+ for (const id of idsOf(prior))
10535
+ observedSeq = Math.max(observedSeq, sequences.get(id) ?? 0);
10536
+ }
10537
+ if (observedSeq > 0)
10538
+ ids.forEach((id, index) => {
10539
+ const sequence = sequences.get(id);
10540
+ if (sequence !== void 0 && sequence <= observedSeq)
10541
+ boundary = Math.max(boundary, index);
10542
+ });
10543
+ if (!existing.length && options.cursorStore) {
10544
+ try {
10545
+ const cursor = options.cursorStore.get(conversationId);
10546
+ if (cursor) boundary = Math.max(boundary, positions.get(cursor) ?? -1);
10547
+ } catch (error) {
10548
+ reportError(error, conversationId);
10549
+ }
10550
+ }
10551
+ if (boundary < 0 && existing.some((prior) => idsOf(prior).length > 0 || seqOf(prior) !== void 0)) {
10552
+ reportError(
10553
+ new Error("Extraction boundary unresolved; skipped rather than re-observing"),
10554
+ conversationId
10555
+ );
10556
+ return;
10557
+ }
10558
+ const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
10559
+ if (start >= ids.length) return;
10560
+ const ownWatermark = job?._getRaw("watermark");
10561
+ const atOwnWatermark = !!job && boundary >= 0 && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
10562
+ const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
10563
+ const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
10564
+ if (!fresh.length) return;
10565
+ if (job) {
10566
+ await job.update(
10567
+ (r) => r._setRaw("message_ids", JSON.stringify([.../* @__PURE__ */ new Set([...idsOf(job), ...fresh])]))
10568
+ );
10569
+ attempts.delete(job.id);
10570
+ } else {
10571
+ await jobs.create((r) => {
10572
+ r._setRaw("owner_key", owner);
10573
+ r._setRaw("conversation_id", conversationId);
10574
+ r._setRaw("scope", scope);
10575
+ r._setRaw("folder_id", folderId);
10576
+ r._setRaw("message_ids", JSON.stringify([...new Set(fresh)]));
10577
+ });
10578
+ }
10579
+ })
10580
+ ).then(() => schedule(options.debounceMs ?? 2e4)).catch((error) => reportError(error, conversationId));
10581
+ return true;
10582
+ },
10583
+ isProcessing: () => running,
10584
+ dispose() {
10585
+ disposed = true;
10586
+ if (timer !== void 0) clearTimeout(timer);
10587
+ }
10588
+ };
10589
+ }
10590
+
10117
10591
  // src/lib/memoryEngine/quantization.ts
10118
10592
  var INT8_MAX = 127;
10119
10593
  function quantizeEmbedding(v) {
@@ -14688,10 +15162,25 @@ __decorateClass([
14688
15162
  ], VaultFolder.prototype, "context", 2);
14689
15163
 
14690
15164
  // src/lib/db/schema.ts
14691
- var SDK_SCHEMA_VERSION = 45;
15165
+ var SDK_SCHEMA_VERSION = 46;
14692
15166
  var sdkSchema = appSchema2({
14693
15167
  version: SDK_SCHEMA_VERSION,
14694
15168
  tables: [
15169
+ tableSchema2({
15170
+ name: "memory_extraction_jobs",
15171
+ columns: [
15172
+ { name: "owner_key", type: "string", isIndexed: true },
15173
+ { name: "conversation_id", type: "string", isIndexed: true },
15174
+ { name: "scope", type: "string" },
15175
+ { name: "message_ids", type: "string" },
15176
+ { name: "watermark", type: "string", isOptional: true },
15177
+ // Deletion-proof anchor: history.message_id of the newest acknowledged
15178
+ // source. `watermark` alone is an id, and deleting that message erased
15179
+ // the anchor — see the column note in extractionJobs/models.ts.
15180
+ { name: "watermark_seq", type: "number", isOptional: true },
15181
+ { name: "folder_id", type: "string", isOptional: true }
15182
+ ]
15183
+ }),
14695
15184
  // Chat storage tables
14696
15185
  tableSchema2({
14697
15186
  name: "history",
@@ -15696,10 +16185,28 @@ var sdkMigrations = schemaMigrations2({
15696
16185
  columns: [{ name: "media", type: "string", isOptional: true }]
15697
16186
  })
15698
16187
  ]
16188
+ },
16189
+ {
16190
+ toVersion: 46,
16191
+ steps: [
16192
+ createTable({
16193
+ name: "memory_extraction_jobs",
16194
+ columns: [
16195
+ { name: "owner_key", type: "string", isIndexed: true },
16196
+ { name: "conversation_id", type: "string", isIndexed: true },
16197
+ { name: "scope", type: "string" },
16198
+ { name: "message_ids", type: "string" },
16199
+ { name: "watermark", type: "string", isOptional: true },
16200
+ { name: "watermark_seq", type: "number", isOptional: true },
16201
+ { name: "folder_id", type: "string", isOptional: true }
16202
+ ]
16203
+ })
16204
+ ]
15699
16205
  }
15700
16206
  ]
15701
16207
  });
15702
16208
  var sdkModelClasses = [
16209
+ ExtractionJob,
15703
16210
  Message,
15704
16211
  Conversation,
15705
16212
  ConversationSummary,
@@ -15883,7 +16390,7 @@ function useDatabaseManager(walletAddress, manager) {
15883
16390
  }
15884
16391
 
15885
16392
  // src/lib/db/project/operations.ts
15886
- import { Q as Q5 } from "@nozbe/watermelondb";
16393
+ import { Q as Q6 } from "@nozbe/watermelondb";
15887
16394
 
15888
16395
  // src/lib/db/project/types.ts
15889
16396
  function generateProjectId() {
@@ -15914,15 +16421,15 @@ async function createProjectOp(ctx, opts, defaultName = "New Project") {
15914
16421
  return projectToStored(created);
15915
16422
  }
15916
16423
  async function getProjectOp(ctx, id) {
15917
- const results = await ctx.projectsCollection.query(Q5.where("project_id", id), Q5.where("is_deleted", false)).fetch();
16424
+ const results = await ctx.projectsCollection.query(Q6.where("project_id", id), Q6.where("is_deleted", false)).fetch();
15918
16425
  return results.length > 0 ? projectToStored(results[0]) : null;
15919
16426
  }
15920
16427
  async function getProjectsOp(ctx) {
15921
- const results = await ctx.projectsCollection.query(Q5.where("is_deleted", false), Q5.sortBy("created_at", Q5.desc)).fetch();
16428
+ const results = await ctx.projectsCollection.query(Q6.where("is_deleted", false), Q6.sortBy("created_at", Q6.desc)).fetch();
15922
16429
  return results.map(projectToStored);
15923
16430
  }
15924
16431
  async function updateProjectNameOp(ctx, id, name) {
15925
- const results = await ctx.projectsCollection.query(Q5.where("project_id", id), Q5.where("is_deleted", false)).fetch();
16432
+ const results = await ctx.projectsCollection.query(Q6.where("project_id", id), Q6.where("is_deleted", false)).fetch();
15926
16433
  if (results.length > 0) {
15927
16434
  await ctx.database.write(async () => {
15928
16435
  await results[0].update((proj) => {
@@ -15934,7 +16441,7 @@ async function updateProjectNameOp(ctx, id, name) {
15934
16441
  return false;
15935
16442
  }
15936
16443
  async function updateProjectOp(ctx, id, opts) {
15937
- const results = await ctx.projectsCollection.query(Q5.where("project_id", id), Q5.where("is_deleted", false)).fetch();
16444
+ const results = await ctx.projectsCollection.query(Q6.where("project_id", id), Q6.where("is_deleted", false)).fetch();
15938
16445
  if (results.length > 0) {
15939
16446
  await ctx.database.write(async () => {
15940
16447
  await results[0].update((proj) => {
@@ -15946,7 +16453,7 @@ async function updateProjectOp(ctx, id, opts) {
15946
16453
  return false;
15947
16454
  }
15948
16455
  async function deleteProjectOp(ctx, id) {
15949
- const results = await ctx.projectsCollection.query(Q5.where("project_id", id), Q5.where("is_deleted", false)).fetch();
16456
+ const results = await ctx.projectsCollection.query(Q6.where("project_id", id), Q6.where("is_deleted", false)).fetch();
15950
16457
  if (results.length > 0) {
15951
16458
  await ctx.database.write(async () => {
15952
16459
  await results[0].update((proj) => {
@@ -15959,18 +16466,18 @@ async function deleteProjectOp(ctx, id) {
15959
16466
  }
15960
16467
  async function getProjectConversationsOp(ctx, projectId) {
15961
16468
  const results = await ctx.conversationsCollection.query(
15962
- Q5.where("project_id", projectId),
15963
- Q5.where("is_deleted", false),
15964
- Q5.sortBy("created_at", Q5.desc)
16469
+ Q6.where("project_id", projectId),
16470
+ Q6.where("is_deleted", false),
16471
+ Q6.sortBy("created_at", Q6.desc)
15965
16472
  ).fetch();
15966
16473
  return results.map(conversationToStoredRaw);
15967
16474
  }
15968
16475
  async function getProjectConversationCountOp(ctx, projectId) {
15969
- return await ctx.conversationsCollection.query(Q5.where("project_id", projectId), Q5.where("is_deleted", false)).fetchCount();
16476
+ return await ctx.conversationsCollection.query(Q6.where("project_id", projectId), Q6.where("is_deleted", false)).fetchCount();
15970
16477
  }
15971
16478
 
15972
16479
  // src/react/useFiles.ts
15973
- import { Q as Q6 } from "@nozbe/watermelondb";
16480
+ import { Q as Q7 } from "@nozbe/watermelondb";
15974
16481
  import { useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo5, useState as useState5 } from "react";
15975
16482
  function useFiles(options) {
15976
16483
  const { database, walletAddress } = options;
@@ -15988,7 +16495,7 @@ function useFiles(options) {
15988
16495
  setIsLoading(true);
15989
16496
  try {
15990
16497
  const coll = database.get("media");
15991
- await coll.query(Q6.take(1)).fetch();
16498
+ await coll.query(Q7.take(1)).fetch();
15992
16499
  setMediaCollection(coll);
15993
16500
  setIsReady(true);
15994
16501
  } catch (error) {
@@ -16396,7 +16903,7 @@ function useFiles(options) {
16396
16903
  }
16397
16904
 
16398
16905
  // src/react/useProjects.ts
16399
- import { Q as Q7 } from "@nozbe/watermelondb";
16906
+ import { Q as Q8 } from "@nozbe/watermelondb";
16400
16907
  import { useCallback as useCallback6, useEffect as useEffect5, useMemo as useMemo6, useState as useState6 } from "react";
16401
16908
  function useProjects(options) {
16402
16909
  const { database, initialProjectId } = options;
@@ -16418,7 +16925,7 @@ function useProjects(options) {
16418
16925
  conversations: convColl?.table
16419
16926
  });
16420
16927
  getLogger().debug("[useProjects] Running test query on projects table...");
16421
- const testResult = await projColl.query(Q7.take(1)).fetch();
16928
+ const testResult = await projColl.query(Q8.take(1)).fetch();
16422
16929
  getLogger().debug(
16423
16930
  "[useProjects] Test query succeeded, found",
16424
16931
  testResult.length,
@@ -16505,7 +17012,7 @@ function useProjects(options) {
16505
17012
  if (!projectsCollection) {
16506
17013
  return;
16507
17014
  }
16508
- const subscription = projectsCollection.query(Q7.where("is_deleted", false)).observe().subscribe((records) => {
17015
+ const subscription = projectsCollection.query(Q8.where("is_deleted", false)).observe().subscribe((records) => {
16509
17016
  setProjects(records.map(projectToStored));
16510
17017
  });
16511
17018
  return () => subscription.unsubscribe();
@@ -16628,7 +17135,7 @@ function useProjects(options) {
16628
17135
  }
16629
17136
 
16630
17137
  // src/lib/db/settings/operations.ts
16631
- import { Q as Q8 } from "@nozbe/watermelondb";
17138
+ import { Q as Q9 } from "@nozbe/watermelondb";
16632
17139
  function modelPreferenceToStored(preference) {
16633
17140
  return {
16634
17141
  uniqueId: preference.id,
@@ -16637,12 +17144,12 @@ function modelPreferenceToStored(preference) {
16637
17144
  };
16638
17145
  }
16639
17146
  async function getModelPreferenceOp(ctx, walletAddress) {
16640
- const results = await ctx.modelPreferencesCollection.query(Q8.where("wallet_address", walletAddress)).fetch();
17147
+ const results = await ctx.modelPreferencesCollection.query(Q9.where("wallet_address", walletAddress)).fetch();
16641
17148
  return results.length > 0 ? modelPreferenceToStored(results[0]) : null;
16642
17149
  }
16643
17150
  async function setModelPreferenceOp(ctx, walletAddress, models) {
16644
17151
  const result = await ctx.database.write(async () => {
16645
- const results = await ctx.modelPreferencesCollection.query(Q8.where("wallet_address", walletAddress)).fetch();
17152
+ const results = await ctx.modelPreferencesCollection.query(Q9.where("wallet_address", walletAddress)).fetch();
16646
17153
  if (results.length > 0) {
16647
17154
  const preference = results[0];
16648
17155
  await preference.update((pref) => {
@@ -16660,7 +17167,7 @@ async function setModelPreferenceOp(ctx, walletAddress, models) {
16660
17167
  return modelPreferenceToStored(result);
16661
17168
  }
16662
17169
  async function deleteModelPreferenceOp(ctx, walletAddress) {
16663
- const results = await ctx.modelPreferencesCollection.query(Q8.where("wallet_address", walletAddress)).fetch();
17170
+ const results = await ctx.modelPreferencesCollection.query(Q9.where("wallet_address", walletAddress)).fetch();
16664
17171
  if (results.length === 0) return false;
16665
17172
  await ctx.database.write(async () => {
16666
17173
  await results[0].destroyPermanently();
@@ -16684,7 +17191,7 @@ var settingsStorageSchema = appSchema3({
16684
17191
  });
16685
17192
 
16686
17193
  // src/lib/db/vaultFolders/operations.ts
16687
- import { Q as Q9 } from "@nozbe/watermelondb";
17194
+ import { Q as Q10 } from "@nozbe/watermelondb";
16688
17195
  function folderToStored(folder) {
16689
17196
  return {
16690
17197
  uniqueId: folder.id,
@@ -16709,7 +17216,7 @@ async function createVaultFolderOp(ctx, opts) {
16709
17216
  return folderToStored(created);
16710
17217
  }
16711
17218
  async function getAllVaultFoldersOp(ctx) {
16712
- const results = await ctx.vaultFolderCollection.query(Q9.where("is_deleted", false), Q9.sortBy("created_at", Q9.desc)).fetch();
17219
+ const results = await ctx.vaultFolderCollection.query(Q10.where("is_deleted", false), Q10.sortBy("created_at", Q10.desc)).fetch();
16713
17220
  return results.map(folderToStored);
16714
17221
  }
16715
17222
  async function updateVaultFolderOp(ctx, id, opts) {
@@ -16718,7 +17225,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
16718
17225
  if (record.isDeleted) return null;
16719
17226
  const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
16720
17227
  const updated = await ctx.database.write(async () => {
16721
- const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q9.where("folder_id", id), Q9.where("is_deleted", false)).fetch() : [];
17228
+ const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q10.where("folder_id", id), Q10.where("is_deleted", false)).fetch() : [];
16722
17229
  const updates = [];
16723
17230
  updates.push(
16724
17231
  record.prepareUpdate((r) => {
@@ -16746,7 +17253,7 @@ async function deleteVaultFolderOp(ctx, id) {
16746
17253
  const record = await ctx.vaultFolderCollection.find(id);
16747
17254
  if (record.isDeleted) return false;
16748
17255
  await ctx.database.write(async () => {
16749
- const memories = await ctx.vaultMemoryCollection.query(Q9.where("folder_id", id), Q9.where("is_deleted", false)).fetch();
17256
+ const memories = await ctx.vaultMemoryCollection.query(Q10.where("folder_id", id), Q10.where("is_deleted", false)).fetch();
16750
17257
  const preparedMemories = memories.map(
16751
17258
  (memory) => memory.prepareUpdate((r) => {
16752
17259
  r._setRaw("folder_id", null);
@@ -16815,7 +17322,7 @@ async function updateVaultFolderContextOp(ctx, id, context) {
16815
17322
  }
16816
17323
  }
16817
17324
  async function getVaultFolderMemoryCountOp(ctx, folderId) {
16818
- return await ctx.vaultMemoryCollection.query(Q9.where("folder_id", folderId), Q9.where("is_deleted", false)).fetchCount();
17325
+ return await ctx.vaultMemoryCollection.query(Q10.where("folder_id", folderId), Q10.where("is_deleted", false)).fetchCount();
16819
17326
  }
16820
17327
 
16821
17328
  // src/lib/db/vaultFolders/defaults.ts
@@ -16861,7 +17368,7 @@ async function _ensureDefaultFoldersImpl(ctx) {
16861
17368
  import { useCallback as useCallback7, useMemo as useMemo7, useSyncExternalStore } from "react";
16862
17369
 
16863
17370
  // src/lib/db/userPreferences/operations.ts
16864
- import { Q as Q10 } from "@nozbe/watermelondb";
17371
+ import { Q as Q11 } from "@nozbe/watermelondb";
16865
17372
  function userPreferenceToStored(preference) {
16866
17373
  return {
16867
17374
  uniqueId: preference.id,
@@ -16876,7 +17383,7 @@ function userPreferenceToStored(preference) {
16876
17383
  };
16877
17384
  }
16878
17385
  async function getUserPreferenceOp(ctx, walletAddress) {
16879
- const results = await ctx.userPreferencesCollection.query(Q10.where("wallet_address", walletAddress)).fetch();
17386
+ const results = await ctx.userPreferencesCollection.query(Q11.where("wallet_address", walletAddress)).fetch();
16880
17387
  return results.length > 0 ? userPreferenceToStored(results[0]) : null;
16881
17388
  }
16882
17389
  async function createUserPreferenceOp(ctx, opts) {
@@ -16896,7 +17403,7 @@ async function createUserPreferenceOp(ctx, opts) {
16896
17403
  return userPreferenceToStored(created);
16897
17404
  }
16898
17405
  async function updateUserPreferenceOp(ctx, walletAddress, opts) {
16899
- const results = await ctx.userPreferencesCollection.query(Q10.where("wallet_address", walletAddress)).fetch();
17406
+ const results = await ctx.userPreferencesCollection.query(Q11.where("wallet_address", walletAddress)).fetch();
16900
17407
  if (results.length === 0) return null;
16901
17408
  const preference = results[0];
16902
17409
  await ctx.database.write(async () => {
@@ -16924,7 +17431,7 @@ async function updateUserPreferenceOp(ctx, walletAddress, opts) {
16924
17431
  async function setUserPreferenceOp(ctx, walletAddress, opts) {
16925
17432
  const now = Date.now();
16926
17433
  const result = await ctx.database.write(async () => {
16927
- const results = await ctx.userPreferencesCollection.query(Q10.where("wallet_address", walletAddress)).fetch();
17434
+ const results = await ctx.userPreferencesCollection.query(Q11.where("wallet_address", walletAddress)).fetch();
16928
17435
  if (results.length > 0) {
16929
17436
  const preference = results[0];
16930
17437
  await preference.update((pref) => {
@@ -16972,7 +17479,7 @@ async function updateModelsOp(ctx, walletAddress, models) {
16972
17479
  return updateUserPreferenceOp(ctx, walletAddress, { models });
16973
17480
  }
16974
17481
  async function deleteUserPreferenceOp(ctx, walletAddress) {
16975
- const results = await ctx.userPreferencesCollection.query(Q10.where("wallet_address", walletAddress)).fetch();
17482
+ const results = await ctx.userPreferencesCollection.query(Q11.where("wallet_address", walletAddress)).fetch();
16976
17483
  if (results.length === 0) return false;
16977
17484
  await ctx.database.write(async () => {
16978
17485
  await results[0].destroyPermanently();
@@ -16987,9 +17494,9 @@ async function migrateFromModelPreferencesOp(ctx, walletAddress) {
16987
17494
  if (existing) {
16988
17495
  return existing;
16989
17496
  }
16990
- const modelResults = await ctx.modelPreferencesCollection.query(Q10.where("wallet_address", walletAddress)).fetch();
17497
+ const modelResults = await ctx.modelPreferencesCollection.query(Q11.where("wallet_address", walletAddress)).fetch();
16991
17498
  const personalityKey = `${walletAddress}_personality_settings`;
16992
- const personalityResults = await ctx.modelPreferencesCollection.query(Q10.where("wallet_address", personalityKey)).fetch();
17499
+ const personalityResults = await ctx.modelPreferencesCollection.query(Q11.where("wallet_address", personalityKey)).fetch();
16993
17500
  if (modelResults.length === 0 && personalityResults.length === 0) {
16994
17501
  return null;
16995
17502
  }
@@ -17095,7 +17602,7 @@ var SLIDER_CONFIG = [
17095
17602
  ];
17096
17603
 
17097
17604
  // src/react/userSettingsStore.ts
17098
- import { Q as Q11 } from "@nozbe/watermelondb";
17605
+ import { Q as Q12 } from "@nozbe/watermelondb";
17099
17606
  var EMPTY_SNAPSHOT = Object.freeze({
17100
17607
  modelPreference: null,
17101
17608
  userPreference: null,
@@ -17157,7 +17664,7 @@ async function startLoad(entry, walletAddress) {
17157
17664
  }
17158
17665
  function startObserve(entry, walletAddress) {
17159
17666
  let isInitialEmission = true;
17160
- entry.observeSub = entry.storageCtx.userPreferencesCollection.query(Q11.where("wallet_address", walletAddress)).observeWithColumns([
17667
+ entry.observeSub = entry.storageCtx.userPreferencesCollection.query(Q12.where("wallet_address", walletAddress)).observeWithColumns([
17161
17668
  "nickname",
17162
17669
  "occupation",
17163
17670
  "description",
@@ -17421,7 +17928,7 @@ function useSettings(options) {
17421
17928
  }
17422
17929
 
17423
17930
  // src/lib/db/appFiles/operations.ts
17424
- import { Q as Q12 } from "@nozbe/watermelondb";
17931
+ import { Q as Q13 } from "@nozbe/watermelondb";
17425
17932
 
17426
17933
  // src/utils/paths.ts
17427
17934
  function normalizePath(p) {
@@ -17447,7 +17954,7 @@ async function putAppFileOp(ctx, conversationId, path, content) {
17447
17954
  const normalized = normalizePath(path);
17448
17955
  const now = Date.now();
17449
17956
  const result = await ctx.database.write(async () => {
17450
- const existing = await ctx.appFilesCollection.query(Q12.where("conversation_id", conversationId), Q12.where("path", normalized)).fetch();
17957
+ const existing = await ctx.appFilesCollection.query(Q13.where("conversation_id", conversationId), Q13.where("path", normalized)).fetch();
17451
17958
  if (existing.length > 0) {
17452
17959
  await existing[0].update((f) => {
17453
17960
  f._setRaw("content", content);
@@ -17467,11 +17974,11 @@ async function putAppFileOp(ctx, conversationId, path, content) {
17467
17974
  }
17468
17975
  async function getAppFileOp(ctx, conversationId, path) {
17469
17976
  const normalized = normalizePath(path);
17470
- const results = await ctx.appFilesCollection.query(Q12.where("conversation_id", conversationId), Q12.where("path", normalized)).fetch();
17977
+ const results = await ctx.appFilesCollection.query(Q13.where("conversation_id", conversationId), Q13.where("path", normalized)).fetch();
17471
17978
  return results.length > 0 ? appFileToStored(results[0]) : null;
17472
17979
  }
17473
17980
  async function getAppFilesOp(ctx, conversationId) {
17474
- const results = await ctx.appFilesCollection.query(Q12.where("conversation_id", conversationId)).fetch();
17981
+ const results = await ctx.appFilesCollection.query(Q13.where("conversation_id", conversationId)).fetch();
17475
17982
  return results.map(appFileToStored);
17476
17983
  }
17477
17984
  async function getAppFileMapOp(ctx, conversationId) {
@@ -17482,7 +17989,7 @@ async function getAppFileMapOp(ctx, conversationId) {
17482
17989
  }
17483
17990
  async function deleteAppFileOp(ctx, conversationId, path) {
17484
17991
  const normalized = normalizePath(path);
17485
- const results = await ctx.appFilesCollection.query(Q12.where("conversation_id", conversationId), Q12.where("path", normalized)).fetch();
17992
+ const results = await ctx.appFilesCollection.query(Q13.where("conversation_id", conversationId), Q13.where("path", normalized)).fetch();
17486
17993
  if (results.length === 0) return false;
17487
17994
  await ctx.database.write(async () => {
17488
17995
  await results[0].destroyPermanently();
@@ -17490,7 +17997,7 @@ async function deleteAppFileOp(ctx, conversationId, path) {
17490
17997
  return true;
17491
17998
  }
17492
17999
  async function deleteAllAppFilesOp(ctx, conversationId) {
17493
- const results = await ctx.appFilesCollection.query(Q12.where("conversation_id", conversationId)).fetch();
18000
+ const results = await ctx.appFilesCollection.query(Q13.where("conversation_id", conversationId)).fetch();
17494
18001
  if (results.length === 0) return;
17495
18002
  await ctx.database.write(async () => {
17496
18003
  const batch = results.map((file) => file.prepareDestroyPermanently());
@@ -17499,7 +18006,7 @@ async function deleteAllAppFilesOp(ctx, conversationId) {
17499
18006
  }
17500
18007
 
17501
18008
  // src/lib/db/conversationMemory/operations.ts
17502
- import { Q as Q13 } from "@nozbe/watermelondb";
18009
+ import { Q as Q14 } from "@nozbe/watermelondb";
17503
18010
  var MAX_PER_CONVERSATION = 200;
17504
18011
  function conversationMemoryToStored(row) {
17505
18012
  return {
@@ -17514,7 +18021,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
17514
18021
  if (!conversationId || items.length === 0) return;
17515
18022
  const now = Date.now();
17516
18023
  await ctx.database.write(async () => {
17517
- const existing = await ctx.conversationMemoryCollection.query(Q13.where("conversation_id", conversationId), Q13.sortBy("created_at", Q13.asc)).fetch();
18024
+ const existing = await ctx.conversationMemoryCollection.query(Q14.where("conversation_id", conversationId), Q14.sortBy("created_at", Q14.asc)).fetch();
17518
18025
  const seen = new Set(existing.map((r) => r.memoryId));
17519
18026
  const batchSeen = /* @__PURE__ */ new Set();
17520
18027
  const deduped = [];
@@ -17549,20 +18056,20 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
17549
18056
  }
17550
18057
  async function getConversationMemoriesOp(ctx, conversationId) {
17551
18058
  if (!conversationId) return [];
17552
- const rows = await ctx.conversationMemoryCollection.query(Q13.where("conversation_id", conversationId), Q13.sortBy("created_at", Q13.asc)).fetch();
18059
+ const rows = await ctx.conversationMemoryCollection.query(Q14.where("conversation_id", conversationId), Q14.sortBy("created_at", Q14.asc)).fetch();
17553
18060
  return rows.map(conversationMemoryToStored);
17554
18061
  }
17555
18062
  async function clearConversationMemoriesOp(ctx, conversationId) {
17556
18063
  if (!conversationId) return;
17557
18064
  await ctx.database.write(async () => {
17558
- const rows = await ctx.conversationMemoryCollection.query(Q13.where("conversation_id", conversationId)).fetch();
18065
+ const rows = await ctx.conversationMemoryCollection.query(Q14.where("conversation_id", conversationId)).fetch();
17559
18066
  if (rows.length === 0) return;
17560
18067
  await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
17561
18068
  });
17562
18069
  }
17563
18070
 
17564
18071
  // src/lib/db/savedTools/operations.ts
17565
- import { Q as Q14 } from "@nozbe/watermelondb";
18072
+ import { Q as Q15 } from "@nozbe/watermelondb";
17566
18073
  function savedToolToStored(tool) {
17567
18074
  return {
17568
18075
  uniqueId: tool.id,
@@ -17595,7 +18102,7 @@ async function createSavedToolOp(ctx, opts) {
17595
18102
  return savedToolToStored(created);
17596
18103
  }
17597
18104
  async function getAllSavedToolsOp(ctx) {
17598
- const results = await ctx.savedToolsCollection.query(Q14.where("is_deleted", false), Q14.sortBy("created_at", Q14.desc)).fetch();
18105
+ const results = await ctx.savedToolsCollection.query(Q15.where("is_deleted", false), Q15.sortBy("created_at", Q15.desc)).fetch();
17599
18106
  return results.map(savedToolToStored);
17600
18107
  }
17601
18108
  async function getSavedToolByIdOp(ctx, uniqueId) {
@@ -20118,9 +20625,9 @@ async function pushConversationToDropbox(database, conversationId, userAddress,
20118
20625
  const filename = `${conversationId}.json`;
20119
20626
  const existingFile = await findDropboxFile(token, filename, backupFolder);
20120
20627
  if (existingFile) {
20121
- const { Q: Q15 } = await import("@nozbe/watermelondb");
20628
+ const { Q: Q16 } = await import("@nozbe/watermelondb");
20122
20629
  const conversationsCollection = database.get("conversations");
20123
- const records = await conversationsCollection.query(Q15.where("conversation_id", conversationId)).fetch();
20630
+ const records = await conversationsCollection.query(Q16.where("conversation_id", conversationId)).fetch();
20124
20631
  if (records.length > 0) {
20125
20632
  const conversation = conversationToStoredRaw(records[0]);
20126
20633
  const localUpdated = conversation.updatedAt.getTime();
@@ -20158,9 +20665,9 @@ async function pushConversationToDropbox(database, conversationId, userAddress,
20158
20665
  }
20159
20666
  async function performDropboxExport(database, userAddress, token, deps, onProgress, backupFolder = DEFAULT_BACKUP_FOLDER) {
20160
20667
  await deps.requestEncryptionKey(userAddress);
20161
- const { Q: Q15 } = await import("@nozbe/watermelondb");
20668
+ const { Q: Q16 } = await import("@nozbe/watermelondb");
20162
20669
  const conversationsCollection = database.get("conversations");
20163
- const records = await conversationsCollection.query(Q15.where("is_deleted", false)).fetch();
20670
+ const records = await conversationsCollection.query(Q16.where("is_deleted", false)).fetch();
20164
20671
  const conversations = records.map(conversationToStoredRaw);
20165
20672
  const total = conversations.length;
20166
20673
  if (total === 0) {
@@ -20802,9 +21309,9 @@ async function pushConversationToDrive(database, conversationId, userAddress, to
20802
21309
  const filename = `${conversationId}.json`;
20803
21310
  const existingFile = await findDriveFile(activeToken, folderId, filename);
20804
21311
  if (existingFile) {
20805
- const { Q: Q15 } = await import("@nozbe/watermelondb");
21312
+ const { Q: Q16 } = await import("@nozbe/watermelondb");
20806
21313
  const conversationsCollection = database.get("conversations");
20807
- const records = await conversationsCollection.query(Q15.where("conversation_id", conversationId)).fetch();
21314
+ const records = await conversationsCollection.query(Q16.where("conversation_id", conversationId)).fetch();
20808
21315
  if (records.length > 0) {
20809
21316
  const conversation = conversationToStoredRaw(records[0]);
20810
21317
  const localUpdated = conversation.updatedAt.getTime();
@@ -20857,9 +21364,9 @@ async function performGoogleDriveExport(database, userAddress, token, deps, onPr
20857
21364
  return { success: false, uploaded: 0, skipped: 0, total: 0 };
20858
21365
  }
20859
21366
  const { token: activeToken } = folderResult;
20860
- const { Q: Q15 } = await import("@nozbe/watermelondb");
21367
+ const { Q: Q16 } = await import("@nozbe/watermelondb");
20861
21368
  const conversationsCollection = database.get("conversations");
20862
- const records = await conversationsCollection.query(Q15.where("is_deleted", false)).fetch();
21369
+ const records = await conversationsCollection.query(Q16.where("is_deleted", false)).fetch();
20863
21370
  const conversations = records.map(conversationToStoredRaw);
20864
21371
  const total = conversations.length;
20865
21372
  if (total === 0) {
@@ -21444,9 +21951,9 @@ async function pushConversationToICloud(database, conversationId, userAddress, d
21444
21951
  const filename = `${conversationId}.json`;
21445
21952
  const existingFile = await findICloudFile(filename);
21446
21953
  if (existingFile) {
21447
- const { Q: Q15 } = await import("@nozbe/watermelondb");
21954
+ const { Q: Q16 } = await import("@nozbe/watermelondb");
21448
21955
  const conversationsCollection = database.get("conversations");
21449
- const records = await conversationsCollection.query(Q15.where("conversation_id", conversationId)).fetch();
21956
+ const records = await conversationsCollection.query(Q16.where("conversation_id", conversationId)).fetch();
21450
21957
  if (records.length > 0) {
21451
21958
  const conversation = conversationToStoredRaw(records[0]);
21452
21959
  const localUpdated = conversation.updatedAt.getTime();
@@ -21476,9 +21983,9 @@ async function pushConversationToICloud(database, conversationId, userAddress, d
21476
21983
  }
21477
21984
  async function performICloudExport(database, userAddress, deps, onProgress) {
21478
21985
  await deps.requestEncryptionKey(userAddress);
21479
- const { Q: Q15 } = await import("@nozbe/watermelondb");
21986
+ const { Q: Q16 } = await import("@nozbe/watermelondb");
21480
21987
  const conversationsCollection = database.get("conversations");
21481
- const records = await conversationsCollection.query(Q15.where("is_deleted", false)).fetch();
21988
+ const records = await conversationsCollection.query(Q16.where("is_deleted", false)).fetch();
21482
21989
  const conversations = records.map(conversationToStoredRaw);
21483
21990
  const total = conversations.length;
21484
21991
  if (total === 0) {
@@ -25329,6 +25836,7 @@ export {
25329
25836
  HARD_DELETE_WINDOW_MS,
25330
25837
  ICloudAuthProvider,
25331
25838
  INFERENCE_ID_HEADER,
25839
+ INTERNAL_FLOW_MARKER,
25332
25840
  LoggerProvider,
25333
25841
  MAX_HOPS,
25334
25842
  MEDIUM_TTL_MS,
@@ -25377,6 +25885,7 @@ export {
25377
25885
  addConversationMemoriesOp,
25378
25886
  appFileToStored,
25379
25887
  archiveVaultMemoryOp,
25888
+ assembleMemoryContext,
25380
25889
  backfillMemoryEntityUserIdsOp,
25381
25890
  backfillMemoryTopicsOp,
25382
25891
  capHopsForDensity,
@@ -25419,6 +25928,7 @@ export {
25419
25928
  createChunkVectorCache,
25420
25929
  createCryptoPricePreProcessor,
25421
25930
  createDecaySweeper,
25931
+ createDurableAutoExtractor,
25422
25932
  createGitHubTools,
25423
25933
  createLlmDecayClassifier,
25424
25934
  createLlmNeighborRefiner,
@@ -25455,6 +25965,7 @@ export {
25455
25965
  deleteMediaByConversationOp,
25456
25966
  deleteMediaByMessageOp,
25457
25967
  deleteMediaOp,
25968
+ deleteMessageOp,
25458
25969
  deleteProjectOp,
25459
25970
  deleteSavedToolOp,
25460
25971
  deleteVaultFolderOp,
@@ -25659,6 +26170,7 @@ export {
25659
26170
  setMemoryVisibilityOp,
25660
26171
  settingsStorageSchema,
25661
26172
  shouldChunkMessage,
26173
+ shouldRecallMemory,
25662
26174
  shouldRefreshTools,
25663
26175
  stampTopicsExtractedAtOp,
25664
26176
  startGithubAuth,
@@ -25724,5 +26236,6 @@ export {
25724
26236
  verifyMemoriesForPublish,
25725
26237
  walk,
25726
26238
  webPlatformStorage,
26239
+ withInternalFlowMarker,
25727
26240
  writeEncryptedFile
25728
26241
  };