@anuma/sdk 7.2.0 → 7.3.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.
@@ -11131,9 +11131,72 @@ import { Q as Q5 } from "@nozbe/watermelondb";
11131
11131
 
11132
11132
  // src/lib/db/entities/operations.ts
11133
11133
  import { Q as Q4 } from "@nozbe/watermelondb";
11134
+
11135
+ // src/lib/db/memoryVault/types.ts
11136
+ var MEMORY_KINDS = [
11137
+ "display_name",
11138
+ "birth_date",
11139
+ "bio",
11140
+ "occupation",
11141
+ "interest",
11142
+ "gender",
11143
+ "height_cm",
11144
+ "looking_for",
11145
+ "politics",
11146
+ "religion",
11147
+ "ethnicity",
11148
+ "smoking",
11149
+ "drinking",
11150
+ "exercise",
11151
+ "sexuality",
11152
+ "prompt"
11153
+ ];
11154
+ var MEMORY_LEVELS = ["private", "matching", "profile"];
11155
+ var MemoryLevelError = class extends Error {
11156
+ constructor(message) {
11157
+ super(message);
11158
+ this.name = "MemoryLevelError";
11159
+ }
11160
+ };
11161
+ var MemorySourceIneligibleError = class extends Error {
11162
+ constructor() {
11163
+ super("Memory source is no longer eligible");
11164
+ this.name = "MemorySourceIneligibleError";
11165
+ }
11166
+ };
11167
+ var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
11168
+ function levelFromScope(scope) {
11169
+ return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
11170
+ }
11171
+ function scopeForLevel(level) {
11172
+ return level === "private" ? "private" : "shared";
11173
+ }
11174
+ function resolveMemoryLevel(level, scope) {
11175
+ return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
11176
+ }
11177
+ function levelForScopeChange(current, nextScope) {
11178
+ const implied = levelFromScope(nextScope);
11179
+ return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
11180
+ }
11181
+ function parseMedia(value) {
11182
+ if (typeof value !== "string" || value === "") return null;
11183
+ try {
11184
+ const parsed = JSON.parse(value);
11185
+ if (!Array.isArray(parsed)) return null;
11186
+ const refs = parsed.filter((r) => typeof r === "object" && r !== null).map((r) => ({
11187
+ feedItemId: Number(r.feedItemId ?? r.feed_item_id),
11188
+ objectKey: r.objectKey ?? r.object_key ?? null
11189
+ })).filter((r) => Number.isFinite(r.feedItemId));
11190
+ return refs.length > 0 ? refs : null;
11191
+ } catch {
11192
+ return null;
11193
+ }
11194
+ }
11195
+
11196
+ // src/lib/db/entities/operations.ts
11134
11197
  async function assertCanWrite(ctx) {
11135
11198
  if (ctx.canWrite && !await ctx.canWrite()) {
11136
- throw new Error("Memory source is no longer eligible");
11199
+ throw new MemorySourceIneligibleError();
11137
11200
  }
11138
11201
  }
11139
11202
  function entityToStored(e) {
@@ -11525,61 +11588,6 @@ function serializeSourceChunkIds(ids) {
11525
11588
  return JSON.stringify(ids.slice(start));
11526
11589
  }
11527
11590
 
11528
- // src/lib/db/memoryVault/types.ts
11529
- var MEMORY_KINDS = [
11530
- "display_name",
11531
- "birth_date",
11532
- "bio",
11533
- "occupation",
11534
- "interest",
11535
- "gender",
11536
- "height_cm",
11537
- "looking_for",
11538
- "politics",
11539
- "religion",
11540
- "ethnicity",
11541
- "smoking",
11542
- "drinking",
11543
- "exercise",
11544
- "sexuality",
11545
- "prompt"
11546
- ];
11547
- var MEMORY_LEVELS = ["private", "matching", "profile"];
11548
- var MemoryLevelError = class extends Error {
11549
- constructor(message) {
11550
- super(message);
11551
- this.name = "MemoryLevelError";
11552
- }
11553
- };
11554
- var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
11555
- function levelFromScope(scope) {
11556
- return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
11557
- }
11558
- function scopeForLevel(level) {
11559
- return level === "private" ? "private" : "shared";
11560
- }
11561
- function resolveMemoryLevel(level, scope) {
11562
- return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
11563
- }
11564
- function levelForScopeChange(current, nextScope) {
11565
- const implied = levelFromScope(nextScope);
11566
- return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
11567
- }
11568
- function parseMedia(value) {
11569
- if (typeof value !== "string" || value === "") return null;
11570
- try {
11571
- const parsed = JSON.parse(value);
11572
- if (!Array.isArray(parsed)) return null;
11573
- const refs = parsed.filter((r) => typeof r === "object" && r !== null).map((r) => ({
11574
- feedItemId: Number(r.feedItemId ?? r.feed_item_id),
11575
- objectKey: r.objectKey ?? r.object_key ?? null
11576
- })).filter((r) => Number.isFinite(r.feedItemId));
11577
- return refs.length > 0 ? refs : null;
11578
- } catch {
11579
- return null;
11580
- }
11581
- }
11582
-
11583
11591
  // src/lib/db/memoryVault/operations.ts
11584
11592
  function visibilityOrPrivate(value) {
11585
11593
  return value === "public" ? value : "private";
@@ -11599,7 +11607,7 @@ function isKinded(record2) {
11599
11607
  }
11600
11608
  async function assertCanWrite2(ctx) {
11601
11609
  if (ctx.canWrite && !await ctx.canWrite()) {
11602
- throw new Error("Memory source is no longer eligible");
11610
+ throw new MemorySourceIneligibleError();
11603
11611
  }
11604
11612
  }
11605
11613
  function assertValidKindLevel(kind, level) {
@@ -12290,7 +12298,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
12290
12298
  ctx.embeddedWalletSigner
12291
12299
  );
12292
12300
  } catch (err) {
12293
- if (err instanceof MemoryLevelError) throw err;
12301
+ if (err instanceof MemoryLevelError || err instanceof MemorySourceIneligibleError) throw err;
12294
12302
  return null;
12295
12303
  }
12296
12304
  }
@@ -15807,6 +15815,13 @@ var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
15807
15815
  var DEFAULT_SCOPE = "private";
15808
15816
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
15809
15817
  var DEFAULT_CONSOLIDATE_TOP_K = 20;
15818
+ var RetainError = class extends Error {
15819
+ constructor(reason, message) {
15820
+ super(message);
15821
+ this.reason = reason;
15822
+ this.name = "RetainError";
15823
+ }
15824
+ };
15810
15825
  async function retain(content, ctx, options = {}) {
15811
15826
  const embeddingOptions = {
15812
15827
  ...ctx.embeddingOptions,
@@ -15862,7 +15877,8 @@ async function retainWithPersistence(content, ctx, options = {}) {
15862
15877
  });
15863
15878
  prepared = withoutKindedRows(prepared);
15864
15879
  if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
15865
- throw new Error(
15880
+ throw new RetainError(
15881
+ "embeddings-unavailable",
15866
15882
  "retain: embeddings unavailable \u2014 refusing to auto-merge against an inert cosine lane, which would create a duplicate instead of merging into the existing memory. Retry when embeddings recover, or pass enableAutoMerge: false to force a create."
15867
15883
  );
15868
15884
  }
@@ -16232,7 +16248,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16232
16248
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
16233
16249
  const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
16234
16250
  if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
16235
- throw new Error(`retain: merge into memory ${targetId} failed to persist`);
16251
+ throw new RetainError(
16252
+ "merge-not-persisted",
16253
+ `retain: merge into memory ${targetId} failed to persist`
16254
+ );
16236
16255
  }
16237
16256
  }
16238
16257
 
@@ -16390,6 +16409,12 @@ function restoreCandidates(candidates, redactor, ownNames) {
16390
16409
  (c) => c.candidate.content.length <= MAX_CONTENT_LENGTH && !c.unresolved && !isLowSignalContent(c.candidate.content, ownNames)
16391
16410
  ).map((c) => c.candidate);
16392
16411
  }
16412
+ function writeFailureReasonOf(err) {
16413
+ if (err instanceof MemorySourceIneligibleError) return "source-ineligible";
16414
+ if (err instanceof RetainError) return err.reason;
16415
+ if (err?.name === "AbortError") return "aborted";
16416
+ return "unknown";
16417
+ }
16393
16418
  async function extractAndRetain(messages, retainCtx, options) {
16394
16419
  const { memoryStore, signal } = options;
16395
16420
  if (memoryStore === null) throw new Error("Memory store is not ready");
@@ -16479,6 +16504,7 @@ async function extractAndRetain(messages, retainCtx, options) {
16479
16504
  const results = [];
16480
16505
  const quarantinedInfo = [];
16481
16506
  let failedWrites = 0;
16507
+ let writeFailureReason;
16482
16508
  let auditRows;
16483
16509
  const tRetain = Date.now();
16484
16510
  for (const { candidate, isQuarantined, reason, signature } of toRetain) {
@@ -16574,6 +16600,7 @@ async function extractAndRetain(messages, retainCtx, options) {
16574
16600
  }
16575
16601
  } catch (err) {
16576
16602
  failedWrites++;
16603
+ writeFailureReason ?? (writeFailureReason = writeFailureReasonOf(err));
16577
16604
  log.warn("[memory/extract] retain failed for one candidate", err);
16578
16605
  options.onCandidateFailed?.(candidate, err);
16579
16606
  }
@@ -16586,6 +16613,7 @@ async function extractAndRetain(messages, retainCtx, options) {
16586
16613
  candidates: succeededCandidates,
16587
16614
  results,
16588
16615
  failedCount: failedWrites,
16616
+ ...writeFailureReason !== void 0 && { writeFailureReason },
16589
16617
  outcome: outcome2,
16590
16618
  quarantined: quarantinedInfo,
16591
16619
  funnel: {
@@ -16854,7 +16882,17 @@ function createAutoExtractor(options) {
16854
16882
  const t0 = Date.now();
16855
16883
  void (async () => {
16856
16884
  try {
16857
- const { candidates, results, failedCount, outcome: outcome2, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
16885
+ const {
16886
+ candidates,
16887
+ results,
16888
+ failedCount,
16889
+ writeFailureReason,
16890
+ outcome: outcome2,
16891
+ failure,
16892
+ funnel,
16893
+ timings,
16894
+ model
16895
+ } = await extractAndRetain(window2, retainCtx, {
16858
16896
  extract,
16859
16897
  memoryStore: options.memoryStore,
16860
16898
  signal: options.signal,
@@ -16890,6 +16928,7 @@ function createAutoExtractor(options) {
16890
16928
  candidates,
16891
16929
  results,
16892
16930
  failedCount,
16931
+ ...writeFailureReason !== void 0 && { writeFailureReason },
16893
16932
  durationMs: Date.now() - t0,
16894
16933
  conversationId,
16895
16934
  outcome: outcome2,
@@ -18976,10 +19015,10 @@ function createLocalMemoryStore(options) {
18976
19015
  const assertWrite = async (writeOptions) => {
18977
19016
  writeOptions?.signal?.throwIfAborted();
18978
19017
  if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
18979
- throw new Error("Memory source is no longer eligible");
19018
+ throw new MemorySourceIneligibleError();
18980
19019
  }
18981
19020
  if (options.canWrite && !await options.canWrite()) {
18982
- throw new Error("Memory source is no longer eligible");
19021
+ throw new MemorySourceIneligibleError();
18983
19022
  }
18984
19023
  writeOptions?.signal?.throwIfAborted();
18985
19024
  };
@@ -19321,6 +19360,7 @@ var queryFields = [
19321
19360
  "updated_after",
19322
19361
  "topics_due",
19323
19362
  "topics_extracted",
19363
+ "event_time_overlaps",
19324
19364
  "order",
19325
19365
  "cursor",
19326
19366
  "limit",
@@ -19787,7 +19827,7 @@ function createRemoteMemoryPipeline(options) {
19787
19827
  const assertWrite = async () => {
19788
19828
  signal?.throwIfAborted();
19789
19829
  if (writeOptions?.canWrite && !await writeOptions.canWrite())
19790
- throw new Error("Memory source is no longer eligible");
19830
+ throw new MemorySourceIneligibleError();
19791
19831
  signal?.throwIfAborted();
19792
19832
  };
19793
19833
  const rejectUndecryptable = (failed) => {
@@ -20568,6 +20608,7 @@ var MAX_QUERY_IDS = 1e3;
20568
20608
  var MAX_QUERY_TOPICS = 100;
20569
20609
  var MAX_QUERY_FILTER = 20;
20570
20610
  var GRAPH_LANE_ROWS = 256;
20611
+ var TEMPORAL_LANE_ROWS = 256;
20571
20612
  var RemoteMemoryPartialCreateError = class extends Error {
20572
20613
  constructor(created, cause) {
20573
20614
  super(`createMany stored ${created.length} memories before a batch failed`);
@@ -20666,7 +20707,7 @@ function createRemoteMemoryStore(options) {
20666
20707
  const pipeline = createRemoteMemoryPipeline({
20667
20708
  ...options,
20668
20709
  graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
20669
- temporalRanking: options.temporalRanking ?? (() => Promise.resolve([]))
20710
+ temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
20670
20711
  });
20671
20712
  const subscribers = /* @__PURE__ */ new Set();
20672
20713
  const seen = /* @__PURE__ */ new Map();
@@ -20729,6 +20770,24 @@ function createRemoteMemoryStore(options) {
20729
20770
  matched: [...canonicalTopics(memory)].filter((name) => wanted.has(name)).length
20730
20771
  })).filter((row) => row.matched > 0).sort((a, b) => b.matched - a.matched).slice(0, NODE_BUDGET).map((row) => row.memoryId);
20731
20772
  };
20773
+ const eventTimeRanking = async (query, now) => {
20774
+ const window2 = parseQueryTimeWindow(query, now);
20775
+ if (!window2) return [];
20776
+ const rows = await pages(
20777
+ metadata2,
20778
+ { event_time_overlaps: { start: window2.start, end: window2.end } },
20779
+ TEMPORAL_LANE_ROWS
20780
+ );
20781
+ return rows.map(({ memory }) => ({
20782
+ memoryId: memory.memory_id,
20783
+ score: scoreEventTimeOverlap(
20784
+ memory.event_time_start ?? null,
20785
+ memory.event_time_end ?? null,
20786
+ memory.event_time_kind ?? null,
20787
+ window2
20788
+ )
20789
+ })).filter((row) => row.score > 0).sort((a, b) => b.score - a.score).map((row) => row.memoryId);
20790
+ };
20732
20791
  const enumerateIds = async (read, ids, filters) => (await Promise.all(
20733
20792
  chunks2([...new Set(ids)], MAX_QUERY_IDS).map(
20734
20793
  (memory_ids) => pages(read, { ...filters, memory_ids })
@@ -20774,7 +20833,7 @@ function createRemoteMemoryStore(options) {
20774
20833
  if (!record2) return null;
20775
20834
  if (record2.memory.is_deleted) return null;
20776
20835
  if (writeOptions?.canWrite && !await writeOptions.canWrite())
20777
- throw new Error("Memory source is no longer eligible");
20836
+ throw new MemorySourceIneligibleError();
20778
20837
  writeOptions?.signal?.throwIfAborted();
20779
20838
  const next = edit(structuredClone(record2.memory));
20780
20839
  if (!next) return null;
@@ -22402,6 +22461,26 @@ function createDurableAutoExtractor(options) {
22402
22461
  );
22403
22462
  continue;
22404
22463
  }
22464
+ const foreign = new Set(
22465
+ ids.filter((_id, index) => loaded[index]?.conversationId !== conversationId)
22466
+ );
22467
+ if (foreign.size) {
22468
+ await database.write(
22469
+ () => job.update(
22470
+ (r) => r._setRaw(
22471
+ "message_ids",
22472
+ JSON.stringify(idsOf(job).filter((id) => !foreign.has(id)))
22473
+ )
22474
+ )
22475
+ );
22476
+ attempts.delete(job.id);
22477
+ scheduleAfterSuccess = true;
22478
+ reportError(
22479
+ new Error(`Dropped ${foreign.size} source id(s) from another conversation`),
22480
+ conversationId
22481
+ );
22482
+ continue;
22483
+ }
22405
22484
  const locked = loaded.filter((message) => message && isEncrypted(message.content));
22406
22485
  if (locked.length) {
22407
22486
  throw new LockedSourcesError(
@@ -22411,7 +22490,7 @@ function createDurableAutoExtractor(options) {
22411
22490
  );
22412
22491
  }
22413
22492
  const messages = loaded.flatMap(
22414
- (m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
22493
+ (m) => m && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
22415
22494
  );
22416
22495
  const jobScope = currentScope() === "private" ? "private" : String(job._getRaw("scope"));
22417
22496
  const jobFolderId = job._getRaw("folder_id") ?? null;
@@ -22504,9 +22583,31 @@ function createDurableAutoExtractor(options) {
22504
22583
  (candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
22505
22584
  );
22506
22585
  const positions = new Map(ids.map((id, index) => [id, index]));
22586
+ const watermarks = existing.flatMap((prior) => {
22587
+ const watermark = prior._getRaw("watermark");
22588
+ return typeof watermark === "string" && watermark ? [watermark] : [];
22589
+ });
22590
+ if (watermarks.length) {
22591
+ const misplaced = new Set(
22592
+ await storage.messagesCollection.query(
22593
+ Q9.where("id", Q9.oneOf(watermarks)),
22594
+ Q9.where("conversation_id", Q9.notEq(conversationId))
22595
+ ).fetchIds()
22596
+ );
22597
+ for (const prior of existing)
22598
+ if (misplaced.has(String(prior._getRaw("watermark"))))
22599
+ await prior.update((r) => {
22600
+ r._setRaw("watermark", null);
22601
+ r._setRaw("watermark_seq", null);
22602
+ });
22603
+ }
22507
22604
  const rows = await storage.messagesCollection.query(Q9.where("id", Q9.oneOf(ids))).fetch();
22605
+ const foreignRows = new Set(
22606
+ rows.filter((row) => row._getRaw("conversation_id") !== conversationId).map((row) => row.id)
22607
+ );
22508
22608
  const sequences = /* @__PURE__ */ new Map();
22509
22609
  for (const row of rows) {
22610
+ if (foreignRows.has(row.id)) continue;
22510
22611
  const sequence = Number(row._getRaw("message_id"));
22511
22612
  if (Number.isFinite(sequence) && sequence > 0) sequences.set(row.id, sequence);
22512
22613
  }
@@ -22549,7 +22650,7 @@ function createDurableAutoExtractor(options) {
22549
22650
  const ownWatermark = job?._getRaw("watermark");
22550
22651
  const atOwnWatermark = !!job && boundary >= 0 && failedSessionsOf(job, String(ownWatermark)) < MAX_FAILED_SESSIONS && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
22551
22652
  const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
22552
- const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
22653
+ const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id) && !foreignRows.has(id));
22553
22654
  if (!fresh.length) return;
22554
22655
  if (job) {
22555
22656
  await job.update(