@anuma/sdk 6.1.1 → 6.3.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.
@@ -16214,7 +16214,8 @@ function messageToStoredRaw(message, projection) {
16214
16214
  thinking: message.thinking,
16215
16215
  parentMessageId: message.parentMessageId,
16216
16216
  feedback: message.feedback || null,
16217
- toolCallEvents: parseJsonField(toolCallEventsRaw)
16217
+ toolCallEvents: parseJsonField(toolCallEventsRaw),
16218
+ origin: message.origin
16218
16219
  };
16219
16220
  }
16220
16221
  async function messageToStored(message, walletAddress, signMessage, embeddedWalletSigner, projection) {
@@ -16275,7 +16276,11 @@ function messageRawToStoredRaw(raw, projection) {
16275
16276
  thinking: raw.thinking,
16276
16277
  parentMessageId: raw.parent_message_id,
16277
16278
  feedback: raw.feedback || null,
16278
- toolCallEvents: parseJsonField(raw.tool_call_events)
16279
+ toolCallEvents: parseJsonField(raw.tool_call_events),
16280
+ // Load-bearing on this path specifically: getMessagesOp reads raws, and it is
16281
+ // what the deferred embedding sweep iterates, so the provenance gate depends
16282
+ // on `origin` surviving the raw mapper as well as the Model one.
16283
+ origin: raw.origin
16279
16284
  };
16280
16285
  }
16281
16286
  async function messageRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner, projection) {
@@ -16538,6 +16543,7 @@ function applyMessageFields(msg, encryptedOpts) {
16538
16543
  const tceValue = typeof encryptedOpts.toolCallEvents === "string" ? encryptedOpts.toolCallEvents : JSON.stringify(encryptedOpts.toolCallEvents);
16539
16544
  msg._setRaw("tool_call_events", tceValue);
16540
16545
  }
16546
+ if (encryptedOpts.origin) msg._setRaw("origin", encryptedOpts.origin);
16541
16547
  }
16542
16548
  async function createMessageOp(ctx, opts) {
16543
16549
  if (opts.uniqueId) {
@@ -16956,7 +16962,8 @@ function makeSyntheticStoredMessage(opts) {
16956
16962
  thoughtProcess: opts.thoughtProcess,
16957
16963
  thinking: opts.thinking,
16958
16964
  parentMessageId: opts.parentMessageId,
16959
- toolCallEvents: opts.toolCallEvents
16965
+ toolCallEvents: opts.toolCallEvents,
16966
+ origin: opts.origin
16960
16967
  };
16961
16968
  }
16962
16969
  function makeSyntheticStoredConversation(opts, defaultTitle) {
@@ -17412,6 +17419,27 @@ var init_encryption2 = __esm({
17412
17419
  }
17413
17420
  });
17414
17421
 
17422
+ // src/lib/db/memoryVault/types.ts
17423
+ function parseMedia(value) {
17424
+ if (typeof value !== "string" || value === "") return null;
17425
+ try {
17426
+ const parsed = JSON.parse(value);
17427
+ if (!Array.isArray(parsed)) return null;
17428
+ const refs = parsed.filter((r) => typeof r === "object" && r !== null).map((r) => ({
17429
+ feedItemId: Number(r.feedItemId ?? r.feed_item_id),
17430
+ objectKey: r.objectKey ?? r.object_key ?? null
17431
+ })).filter((r) => Number.isFinite(r.feedItemId));
17432
+ return refs.length > 0 ? refs : null;
17433
+ } catch {
17434
+ return null;
17435
+ }
17436
+ }
17437
+ var init_types4 = __esm({
17438
+ "src/lib/db/memoryVault/types.ts"() {
17439
+ "use strict";
17440
+ }
17441
+ });
17442
+
17415
17443
  // src/lib/db/memoryVault/operations.ts
17416
17444
  function visibilityOrPrivate(value) {
17417
17445
  return value === "public" ? value : "private";
@@ -17473,6 +17501,7 @@ function vaultMemoryToStoredRaw(memory) {
17473
17501
  sourceChunkIds,
17474
17502
  proofCount: memory.proofCount ?? null,
17475
17503
  source: memory.source ?? null,
17504
+ media: parseMedia(memory.media),
17476
17505
  eventTimeStart: memory.eventTimeStart ?? null,
17477
17506
  eventTimeEnd: memory.eventTimeEnd ?? null,
17478
17507
  eventTimeKind: memory.eventTimeKind ?? null,
@@ -17755,6 +17784,7 @@ function vaultMemoryRawToStoredRaw(raw) {
17755
17784
  eventTimeKind: raw.event_time_kind ?? null,
17756
17785
  // SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
17757
17786
  topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
17787
+ media: parseMedia(raw.media),
17758
17788
  topics: parseTopics(raw.topics),
17759
17789
  topicsUpdatedAt: raw.topics_updated_at ?? null,
17760
17790
  topicsExtractedAt: raw.topics_extracted_at ?? null,
@@ -18479,6 +18509,7 @@ var init_operations3 = __esm({
18479
18509
  init_operations2();
18480
18510
  init_types3();
18481
18511
  init_encryption2();
18512
+ init_types4();
18482
18513
  NON_PRIVATE_VISIBILITIES = ["public"];
18483
18514
  KNOWN_TRUST_TIERS = /* @__PURE__ */ new Set(["quarantined", "trusted"]);
18484
18515
  TOPICS_EXTRACTION_VERSION = 3;
@@ -19719,6 +19750,9 @@ async function embedMessage(ctx, messageId, options) {
19719
19750
  if (message.vector && message.vector.length > 0) {
19720
19751
  return message;
19721
19752
  }
19753
+ if (message.origin === NON_EMBEDDABLE_ORIGIN) {
19754
+ return message;
19755
+ }
19722
19756
  const embedding = await generateEmbedding(message.content, options);
19723
19757
  const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
19724
19758
  return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
@@ -19740,6 +19774,9 @@ async function embedAllMessages(ctx, options, filter) {
19740
19774
  if (message.role === "system") {
19741
19775
  continue;
19742
19776
  }
19777
+ if (message.origin === NON_EMBEDDABLE_ORIGIN) {
19778
+ continue;
19779
+ }
19743
19780
  const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
19744
19781
  if (message.content.length < minLength) {
19745
19782
  continue;
@@ -19765,6 +19802,9 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
19765
19802
  if (message.chunks && message.chunks.length > 0) {
19766
19803
  return message;
19767
19804
  }
19805
+ if (message.origin === NON_EMBEDDABLE_ORIGIN) {
19806
+ return message;
19807
+ }
19768
19808
  const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
19769
19809
  if (!shouldChunkMessage(message.content, chunkSize)) {
19770
19810
  const embedding = await generateEmbedding(message.content, options);
@@ -19798,6 +19838,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
19798
19838
  if (hasVector && !filter?.rechunkExisting && !isStale) continue;
19799
19839
  if (filter?.roles && !filter.roles.includes(message.role)) continue;
19800
19840
  if (message.role === "system") continue;
19841
+ if (message.origin === NON_EMBEDDABLE_ORIGIN) continue;
19801
19842
  if (message.content.length < minLength) continue;
19802
19843
  if (shouldChunkMessage(message.content, chunkSize)) {
19803
19844
  longMessages.push({
@@ -19854,7 +19895,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
19854
19895
  }
19855
19896
  return embeddedCount;
19856
19897
  }
19857
- var DEFAULT_MIN_CONTENT_LENGTH;
19898
+ var DEFAULT_MIN_CONTENT_LENGTH, NON_EMBEDDABLE_ORIGIN;
19858
19899
  var init_embeddings = __esm({
19859
19900
  "src/lib/memoryEngine/embeddings.ts"() {
19860
19901
  "use strict";
@@ -19865,6 +19906,7 @@ var init_embeddings = __esm({
19865
19906
  init_generate();
19866
19907
  init_generate();
19867
19908
  DEFAULT_MIN_CONTENT_LENGTH = 10;
19909
+ NON_EMBEDDABLE_ORIGIN = "tool_result";
19868
19910
  }
19869
19911
  });
19870
19912
 
@@ -19979,17 +20021,17 @@ function recencyMultiplier(updatedAt, opts = {}) {
19979
20021
  const now = opts.now ?? /* @__PURE__ */ new Date();
19980
20022
  const nowMs2 = now.getTime();
19981
20023
  if (!Number.isFinite(nowMs2)) return noDate;
19982
- const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS);
20024
+ const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
19983
20025
  const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
19984
20026
  const floor = opts.floor ?? DEFAULT_FLOOR;
19985
20027
  const decay = perYearDecay * (ageDays2 / 365);
19986
20028
  return Math.max(floor, 1 - decay);
19987
20029
  }
19988
- var DAY_MS, DEFAULT_PER_YEAR_DECAY, DEFAULT_FLOOR, DEFAULT_NO_DATE_MULTIPLIER;
20030
+ var DAY_MS2, DEFAULT_PER_YEAR_DECAY, DEFAULT_FLOOR, DEFAULT_NO_DATE_MULTIPLIER;
19989
20031
  var init_recency = __esm({
19990
20032
  "src/lib/memory/recency.ts"() {
19991
20033
  "use strict";
19992
- DAY_MS = 1e3 * 60 * 60 * 24;
20034
+ DAY_MS2 = 1e3 * 60 * 60 * 24;
19993
20035
  DEFAULT_PER_YEAR_DECAY = 0.2;
19994
20036
  DEFAULT_FLOOR = 0.1;
19995
20037
  DEFAULT_NO_DATE_MULTIPLIER = 0.5;
@@ -20979,8 +21021,8 @@ function classifyObservationTrend(input, now = Date.now()) {
20979
21021
  const lastMsRaw = input.lastObservedAt;
20980
21022
  const lastMs = lastMsRaw !== null && lastMsRaw !== void 0 && Number.isFinite(lastMsRaw) ? Math.max(createdMs, lastMsRaw) : createdMs;
20981
21023
  const proofs = Math.max(1, input.proofCount ?? 1);
20982
- const ageDays2 = Math.max(0, (now - createdMs) / DAY_MS2);
20983
- const daysSinceLast = Math.max(0, (now - lastMs) / DAY_MS2);
21024
+ const ageDays2 = Math.max(0, (now - createdMs) / DAY_MS3);
21025
+ const daysSinceLast = Math.max(0, (now - lastMs) / DAY_MS3);
20984
21026
  if (daysSinceLast >= TREND_STALE_WINDOW_DAYS) return "stale";
20985
21027
  if (daysSinceLast >= TREND_RECENT_WINDOW_DAYS) return "weakening";
20986
21028
  if (ageDays2 <= TREND_RECENT_WINDOW_DAYS && proofs <= 2) return "new";
@@ -21001,11 +21043,11 @@ function summarizeObservationTrends(inputs, now = Date.now()) {
21001
21043
  }
21002
21044
  return counts;
21003
21045
  }
21004
- var DAY_MS2, TREND_RECENT_WINDOW_DAYS, TREND_STALE_WINDOW_DAYS;
21046
+ var DAY_MS3, TREND_RECENT_WINDOW_DAYS, TREND_STALE_WINDOW_DAYS;
21005
21047
  var init_observationTrend = __esm({
21006
21048
  "src/lib/memory/observationTrend.ts"() {
21007
21049
  "use strict";
21008
- DAY_MS2 = 1e3 * 60 * 60 * 24;
21050
+ DAY_MS3 = 1e3 * 60 * 60 * 24;
21009
21051
  TREND_RECENT_WINDOW_DAYS = 30;
21010
21052
  TREND_STALE_WINDOW_DAYS = 90;
21011
21053
  }
@@ -24021,6 +24063,7 @@ __export(index_exports, {
24021
24063
  hardDeleteMediaOp: () => hardDeleteMediaOp,
24022
24064
  hasEncryptionKey: () => hasEncryptionKey,
24023
24065
  hasKeyPair: () => hasKeyPair,
24066
+ ingestPublishedPhotoMemoriesOp: () => ingestPublishedPhotoMemoriesOp,
24024
24067
  injectionSignatureCatalog: () => injectionSignatureCatalog,
24025
24068
  isRerankerAvailable: () => isRerankerAvailable,
24026
24069
  isSupportedFile: () => isSupportedFile,
@@ -24031,6 +24074,7 @@ __export(index_exports, {
24031
24074
  mediaToStored: () => mediaToStored,
24032
24075
  migrateFromModelPreferencesOp: () => migrateFromModelPreferencesOp,
24033
24076
  onKeyAvailable: () => onKeyAvailable,
24077
+ parseMedia: () => parseMedia,
24034
24078
  preEmbedVaultMemories: () => preEmbedVaultMemories,
24035
24079
  preprocessFiles: () => preprocessFiles,
24036
24080
  progressiveSummarize: () => progressiveSummarize,
@@ -24211,6 +24255,9 @@ __decorateClass([
24211
24255
  __decorateClass([
24212
24256
  (0, import_decorators2.json)("tool_call_events", (raw) => raw)
24213
24257
  ], Message.prototype, "toolCallEvents", 2);
24258
+ __decorateClass([
24259
+ (0, import_decorators2.text)("origin")
24260
+ ], Message.prototype, "origin", 2);
24214
24261
  var Conversation = class extends import_watermelondb2.Model {
24215
24262
  };
24216
24263
  Conversation.table = "conversations";
@@ -24435,6 +24482,9 @@ __decorateClass([
24435
24482
  __decorateClass([
24436
24483
  (0, import_decorators6.field)("topics_updated_at")
24437
24484
  ], VaultMemory.prototype, "topicsUpdatedAt", 2);
24485
+ __decorateClass([
24486
+ (0, import_decorators6.field)("media")
24487
+ ], VaultMemory.prototype, "media", 2);
24438
24488
  __decorateClass([
24439
24489
  (0, import_decorators6.field)("topics_extracted_at")
24440
24490
  ], VaultMemory.prototype, "topicsExtractedAt", 2);
@@ -24618,7 +24668,7 @@ __decorateClass([
24618
24668
  ], VaultFolder.prototype, "context", 2);
24619
24669
 
24620
24670
  // src/lib/db/schema.ts
24621
- var SDK_SCHEMA_VERSION = 43;
24671
+ var SDK_SCHEMA_VERSION = 45;
24622
24672
  var sdkSchema = (0, import_watermelondb12.appSchema)({
24623
24673
  version: SDK_SCHEMA_VERSION,
24624
24674
  tables: [
@@ -24656,8 +24706,10 @@ var sdkSchema = (0, import_watermelondb12.appSchema)({
24656
24706
  // Parent message for branching
24657
24707
  { name: "feedback", type: "string", isOptional: true },
24658
24708
  // 'like' | 'dislike' | null
24659
- { name: "tool_call_events", type: "string", isOptional: true }
24709
+ { name: "tool_call_events", type: "string", isOptional: true },
24660
24710
  // JSON stringified LlmapiToolCallEvent[]
24711
+ { name: "origin", type: "string", isOptional: true }
24712
+ // MessageOrigin — provenance, NOT encrypted (see v44)
24661
24713
  ]
24662
24714
  }),
24663
24715
  (0, import_watermelondb12.tableSchema)({
@@ -24764,6 +24816,18 @@ var sdkSchema = (0, import_watermelondb12.appSchema)({
24764
24816
  // paths key on `updated_at` — so without this a topic-only change would
24765
24817
  // neither upload nor merge. Null = `topics` never written.
24766
24818
  { name: "topics_updated_at", type: "number", isOptional: true },
24819
+ // The photo(s) a SERVER-EXTRACTED memory was read out of, as a JSON
24820
+ // array of `{feed_item_id, object_key}` — exactly what
24821
+ // GET /api/memories/published returns in `media[]`. Enough to render the
24822
+ // source image without a second round-trip per memory.
24823
+ //
24824
+ // A JSON column rather than a join table: nothing on the client ever
24825
+ // queries BY photo (the only direction is memory -> render its image),
24826
+ // so a table would add a sync lane and a local-id space to serve a
24827
+ // question nobody asks. `topics` and `source_chunk_ids` set the
24828
+ // precedent for a list that is only ever read back whole. Null on
24829
+ // anything not extracted from a photo.
24830
+ { name: "media", type: "string", isOptional: true },
24767
24831
  // Unix ms of the last LLM topic-extraction pass over this memory's
24768
24832
  // content. Null = never extracted standalone (legacy rows with entity
24769
24833
  // links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
@@ -25585,6 +25649,33 @@ var sdkMigrations = (0, import_migrations.schemaMigrations)({
25585
25649
  "CREATE INDEX IF NOT EXISTS conversations_is_deleted_created_at ON conversations (is_deleted, created_at);"
25586
25650
  )
25587
25651
  ]
25652
+ },
25653
+ // v43 -> v44: Added origin column to history — the provenance tag the embedding
25654
+ // sweep reads to skip never-rendered tool-result rows. No backfill: NULL means
25655
+ // "legacy, provenance unknown" and keeps the pre-v44 behaviour of embedding the
25656
+ // row, so the only rows that stop being embedded are ones a v44+ producer tagged.
25657
+ {
25658
+ toVersion: 44,
25659
+ steps: [
25660
+ (0, import_migrations.addColumns)({
25661
+ table: "history",
25662
+ columns: [{ name: "origin", type: "string", isOptional: true }]
25663
+ })
25664
+ ]
25665
+ },
25666
+ // v44 -> v45: `media` on memory_vault — the photo(s) a server-extracted
25667
+ // memory was read out of, as JSON `[{feed_item_id, object_key}]`, mirroring
25668
+ // the `media[]` that GET /api/memories/published already returns. Existing
25669
+ // rows keep NULL, which is the correct value for every memory that did not
25670
+ // come from a photo (i.e. all of them until photo ingest runs).
25671
+ {
25672
+ toVersion: 45,
25673
+ steps: [
25674
+ (0, import_migrations.addColumns)({
25675
+ table: "memory_vault",
25676
+ columns: [{ name: "media", type: "string", isOptional: true }]
25677
+ })
25678
+ ]
25588
25679
  }
25589
25680
  ]
25590
25681
  });
@@ -26876,6 +26967,138 @@ async function cleanupConversationSummary(database, conversationId) {
26876
26967
  // src/lib/db/memoryVault/index.ts
26877
26968
  init_operations3();
26878
26969
 
26970
+ // src/lib/memory/decay.ts
26971
+ init_logger();
26972
+ var DAY_MS = 24 * 60 * 60 * 1e3;
26973
+ var SHORT_TTL_MS = 30 * DAY_MS;
26974
+ var MEDIUM_TTL_MS = 180 * DAY_MS;
26975
+ var SOURCE_PHOTO = "photo";
26976
+ var NEVER_TTL_MS = Number.POSITIVE_INFINITY;
26977
+ var HARD_DELETE_WINDOW_MS = 30 * DAY_MS;
26978
+ var PAST_EVENT_GRACE_MS = 7 * DAY_MS;
26979
+ var DEFAULT_DECAY_POLICY = {
26980
+ ttlByType: {
26981
+ identity: NEVER_TTL_MS,
26982
+ preference: NEVER_TTL_MS,
26983
+ relationship: NEVER_TTL_MS,
26984
+ constraint: NEVER_TTL_MS,
26985
+ plan: SHORT_TTL_MS,
26986
+ ongoing_context: SHORT_TTL_MS,
26987
+ other: MEDIUM_TTL_MS
26988
+ },
26989
+ fallbackTtlMs: MEDIUM_TTL_MS,
26990
+ hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
26991
+ pastEventGraceMs: PAST_EVENT_GRACE_MS
26992
+ };
26993
+ function resolvePolicy(policy) {
26994
+ if (!policy) return DEFAULT_DECAY_POLICY;
26995
+ return {
26996
+ ttlByType: { ...DEFAULT_DECAY_POLICY.ttlByType, ...policy.ttlByType },
26997
+ fallbackTtlMs: policy.fallbackTtlMs ?? DEFAULT_DECAY_POLICY.fallbackTtlMs,
26998
+ hardDeleteWindowMs: policy.hardDeleteWindowMs ?? DEFAULT_DECAY_POLICY.hardDeleteWindowMs,
26999
+ pastEventGraceMs: policy.pastEventGraceMs ?? DEFAULT_DECAY_POLICY.pastEventGraceMs
27000
+ };
27001
+ }
27002
+ function ttlForType(factType, policy) {
27003
+ const resolved = resolvePolicy(policy);
27004
+ if (factType === null) return resolved.fallbackTtlMs;
27005
+ return resolved.ttlByType[factType] ?? resolved.fallbackTtlMs;
27006
+ }
27007
+ function isTimeSensitiveType(factType) {
27008
+ return factType === "plan" || factType === "ongoing_context";
27009
+ }
27010
+ function hasFiniteTimestamps(m, now) {
27011
+ return Number.isFinite(now) && Number.isFinite(m.updatedAt) && (m.archivedAt === null || Number.isFinite(m.archivedAt));
27012
+ }
27013
+ function classifyDecay(m, now, policy) {
27014
+ const resolved = resolvePolicy(policy);
27015
+ if (!hasFiniteTimestamps(m, now)) {
27016
+ getLogger().warn("[memory/decay] non-finite timestamp on a memory row; keeping it", {
27017
+ now,
27018
+ updatedAt: m.updatedAt,
27019
+ archivedAt: m.archivedAt,
27020
+ factType: m.factType
27021
+ });
27022
+ return "keep";
27023
+ }
27024
+ if (m.archivedAt !== null) {
27025
+ return now - m.archivedAt > resolved.hardDeleteWindowMs ? "delete" : "keep";
27026
+ }
27027
+ if (m.source === "manual" || m.source === SOURCE_PHOTO) return "keep";
27028
+ if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
27029
+ if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
27030
+ if (m.eventTimeEnd >= now) return "keep";
27031
+ }
27032
+ if (now - m.updatedAt > ttlForType(m.factType, resolved)) return "archive";
27033
+ return "keep";
27034
+ }
27035
+
27036
+ // src/lib/db/memoryVault/photoIngest.ts
27037
+ init_encryption2();
27038
+ var PHOTO_MEMORY_ID_PREFIX = "photo:";
27039
+ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
27040
+ const byId = /* @__PURE__ */ new Map();
27041
+ for (const r of rows) {
27042
+ if (typeof r.memoryId !== "string" || !r.memoryId.startsWith(PHOTO_MEMORY_ID_PREFIX)) continue;
27043
+ if (!byId.has(r.memoryId)) byId.set(r.memoryId, r);
27044
+ }
27045
+ const photoRows = [...byId.values()];
27046
+ if (photoRows.length === 0) return { inserted: 0, skipped: 0 };
27047
+ const known = await ctx.vaultMemoryCollection.query().fetchIds().then((ids) => new Set(ids));
27048
+ const candidates = photoRows.filter((r) => !known.has(r.memoryId));
27049
+ if (candidates.length === 0) return { inserted: 0, skipped: photoRows.length };
27050
+ const fresh = candidates;
27051
+ const contents = await Promise.all(
27052
+ fresh.map(async (r) => {
27053
+ if (ctx.walletAddress && ctx.signMessage) {
27054
+ return encryptVaultMemoryContent(
27055
+ r.text,
27056
+ ctx.walletAddress,
27057
+ ctx.signMessage,
27058
+ ctx.embeddedWalletSigner
27059
+ );
27060
+ }
27061
+ return r.text;
27062
+ })
27063
+ );
27064
+ const now = Date.now();
27065
+ let inserted = 0;
27066
+ await ctx.database.write(async () => {
27067
+ const present = new Set(await ctx.vaultMemoryCollection.query().fetchIds());
27068
+ const writable = fresh.map((row, i) => ({ row, content: contents[i] })).filter(({ row }) => !present.has(row.memoryId));
27069
+ inserted = writable.length;
27070
+ if (writable.length === 0) return;
27071
+ const prepared = writable.map(
27072
+ ({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record) => {
27073
+ record._raw.id = row.memoryId;
27074
+ record._setRaw("content", content);
27075
+ record._setRaw("scope", "private");
27076
+ record._setRaw("folder_id", null);
27077
+ record._setRaw("user_id", ctx.userId ?? null);
27078
+ record._setRaw("is_deleted", false);
27079
+ record._setRaw("proof_count", 1);
27080
+ record._setRaw("source", SOURCE_PHOTO);
27081
+ record._setRaw(
27082
+ "media",
27083
+ row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
27084
+ );
27085
+ record._setRaw("visibility", "public");
27086
+ record._setRaw("published_at", now);
27087
+ if (row.eventTime) {
27088
+ record._setRaw("event_time_start", row.eventTime.start ?? null);
27089
+ record._setRaw("event_time_end", row.eventTime.end ?? null);
27090
+ record._setRaw("event_time_kind", row.eventTime.kind ?? null);
27091
+ }
27092
+ })
27093
+ );
27094
+ await ctx.database.batch(...prepared);
27095
+ });
27096
+ return { inserted, skipped: photoRows.length - inserted };
27097
+ }
27098
+
27099
+ // src/lib/db/memoryVault/index.ts
27100
+ init_types4();
27101
+
26879
27102
  // src/lib/db/project/operations.ts
26880
27103
  var import_watermelondb18 = __toESM(require_watermelondb());
26881
27104
  init_operations();
@@ -29583,71 +29806,6 @@ function createChunkVectorCache(maxSize = DEFAULT_CHUNK_CACHE_SIZE) {
29583
29806
  return new LRUCache(maxSize);
29584
29807
  }
29585
29808
 
29586
- // src/lib/memory/decay.ts
29587
- init_logger();
29588
- var DAY_MS3 = 24 * 60 * 60 * 1e3;
29589
- var SHORT_TTL_MS = 30 * DAY_MS3;
29590
- var MEDIUM_TTL_MS = 180 * DAY_MS3;
29591
- var NEVER_TTL_MS = Number.POSITIVE_INFINITY;
29592
- var HARD_DELETE_WINDOW_MS = 30 * DAY_MS3;
29593
- var PAST_EVENT_GRACE_MS = 7 * DAY_MS3;
29594
- var DEFAULT_DECAY_POLICY = {
29595
- ttlByType: {
29596
- identity: NEVER_TTL_MS,
29597
- preference: NEVER_TTL_MS,
29598
- relationship: NEVER_TTL_MS,
29599
- constraint: NEVER_TTL_MS,
29600
- plan: SHORT_TTL_MS,
29601
- ongoing_context: SHORT_TTL_MS,
29602
- other: MEDIUM_TTL_MS
29603
- },
29604
- fallbackTtlMs: MEDIUM_TTL_MS,
29605
- hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
29606
- pastEventGraceMs: PAST_EVENT_GRACE_MS
29607
- };
29608
- function resolvePolicy(policy) {
29609
- if (!policy) return DEFAULT_DECAY_POLICY;
29610
- return {
29611
- ttlByType: { ...DEFAULT_DECAY_POLICY.ttlByType, ...policy.ttlByType },
29612
- fallbackTtlMs: policy.fallbackTtlMs ?? DEFAULT_DECAY_POLICY.fallbackTtlMs,
29613
- hardDeleteWindowMs: policy.hardDeleteWindowMs ?? DEFAULT_DECAY_POLICY.hardDeleteWindowMs,
29614
- pastEventGraceMs: policy.pastEventGraceMs ?? DEFAULT_DECAY_POLICY.pastEventGraceMs
29615
- };
29616
- }
29617
- function ttlForType(factType, policy) {
29618
- const resolved = resolvePolicy(policy);
29619
- if (factType === null) return resolved.fallbackTtlMs;
29620
- return resolved.ttlByType[factType] ?? resolved.fallbackTtlMs;
29621
- }
29622
- function isTimeSensitiveType(factType) {
29623
- return factType === "plan" || factType === "ongoing_context";
29624
- }
29625
- function hasFiniteTimestamps(m, now) {
29626
- return Number.isFinite(now) && Number.isFinite(m.updatedAt) && (m.archivedAt === null || Number.isFinite(m.archivedAt));
29627
- }
29628
- function classifyDecay(m, now, policy) {
29629
- const resolved = resolvePolicy(policy);
29630
- if (!hasFiniteTimestamps(m, now)) {
29631
- getLogger().warn("[memory/decay] non-finite timestamp on a memory row; keeping it", {
29632
- now,
29633
- updatedAt: m.updatedAt,
29634
- archivedAt: m.archivedAt,
29635
- factType: m.factType
29636
- });
29637
- return "keep";
29638
- }
29639
- if (m.archivedAt !== null) {
29640
- return now - m.archivedAt > resolved.hardDeleteWindowMs ? "delete" : "keep";
29641
- }
29642
- if (m.source === "manual") return "keep";
29643
- if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
29644
- if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
29645
- if (m.eventTimeEnd >= now) return "keep";
29646
- }
29647
- if (now - m.updatedAt > ttlForType(m.factType, resolved)) return "archive";
29648
- return "keep";
29649
- }
29650
-
29651
29809
  // src/lib/memory/decayClassifier.ts
29652
29810
  init_logger();
29653
29811
  init_redactor();
@@ -29750,7 +29908,7 @@ function toDecayInput(c) {
29750
29908
  };
29751
29909
  }
29752
29910
  function isBorderline(input) {
29753
- if (input.source === "manual") return false;
29911
+ if (input.source === "manual" || input.source === SOURCE_PHOTO) return false;
29754
29912
  if (input.trustTier === "quarantined") return false;
29755
29913
  if (input.archivedAt !== null) return false;
29756
29914
  if (input.factType === null || input.factType === "other") return true;
@@ -37070,6 +37228,7 @@ function buildSystemPrompt(ctx, options) {
37070
37228
  hardDeleteMediaOp,
37071
37229
  hasEncryptionKey,
37072
37230
  hasKeyPair,
37231
+ ingestPublishedPhotoMemoriesOp,
37073
37232
  injectionSignatureCatalog,
37074
37233
  isRerankerAvailable,
37075
37234
  isSupportedFile,
@@ -37080,6 +37239,7 @@ function buildSystemPrompt(ctx, options) {
37080
37239
  mediaToStored,
37081
37240
  migrateFromModelPreferencesOp,
37082
37241
  onKeyAvailable,
37242
+ parseMedia,
37083
37243
  preEmbedVaultMemories,
37084
37244
  preprocessFiles,
37085
37245
  progressiveSummarize,